Buzón RT-Thread (notas de estudio)

Este artículo hace referencia a [Wildfire EmbedFire] "Implementación de kernel de subprocesos RT y desarrollo de aplicaciones: basado en STM32", que solo se usa como una nota de estudio personal. Para obtener contenido y pasos más detallados, consulte el texto original (puede descargarlo desde el Centro de descarga de datos de Wildfire)

Conceptos básicos de los buzones

El buzón es un método de comunicación IPC común en el sistema operativo y el buzón puede estar entre subprocesos. Los mensajes se transmiten entre interrupciones y subprocesos.Además, los buzones tienen una sobrecarga más baja y una mayor eficiencia que los semáforos y las colas de mensajes, por lo que a menudo se utilizan para la comunicación de subproceso a subproceso e interrupción a subproceso. Cada correo en el buzón solo puede contener un contenido fijo de 4 bytes (STM32 es un sistema de procesamiento de 32 bits, el tamaño de un puntero es de 4 bytes, por lo que un correo puede contener exactamente un puntero), cuando el hilo necesita Al transferir mensajes más grandes entre sí, se puede enviar un puntero a un búfer al buzón como un mensaje.

--original

Los buzones son similares a las colas de mensajes, excepto que el tamaño de los buzones solo puede ser de 4 bytes fijos, pero las colas de mensajes pueden tener cualquier longitud.

Cómo funcionan los buzones

El principio de funcionamiento del buzón se muestra en la figura siguiente. En la figura siguiente, la función de servicio de interrupción o subproceso envía un correo electrónico de 4 bytes al buzón. Hay varios subprocesos en la cola de espera de subprocesos que esperan recibir el buzón.

Fuente de la imagen: Manual chino oficial de RT-Thread

inserte la descripción de la imagen aquí

El hilo puede leer mensajes de correo del buzón. Cuando el correo en el buzón está vacío, decide si suspender el hilo de lectura de acuerdo con el tiempo de bloqueo definido por el usuario; cuando hay nuevos correos en el buzón, el hilo de lectura suspendido es despertado, el buzón es también un método de comunicación asincrónica.

Se pueden poner uno o más mensajes en un buzón mediante un buzón, un hilo o una función de servicio de interrupción. Asimismo, uno o más subprocesos pueden recibir mensajes de correo de los buzones. Cuando se envían varios correos electrónicos al buzón, generalmente el correo electrónico que ingresa primero al buzón debe pasar primero al hilo, es decir, el hilo recibe el mensaje que ingresa primero al buzón, es decir, el primero en entrar es el primero en salir. (FIFO), mientras que RT - Mailboxes in Thread admite prioridad, lo que significa que entre todos los hilos que esperan correo, el que tiene la prioridad más alta recibirá el correo primero.

--original

Escenarios de aplicación de buzones

El buzón de RT-Thread puede almacenar un número fijo de correos, que se determina cuando se inicializa o crea el buzón. Aunque un mensaje solo puede tener un tamaño de 4 bytes, es posible usar un puntero a un búfer (matriz, 4 bytes por elemento) como mensaje, de modo que se pueda enviar un contenido más grande.

En comparación con otros métodos de comunicación, los buzones se caracterizan por una baja sobrecarga y una alta eficiencia. Tanto los buzones de correo de envío como los de recepción admiten el bloqueo de espera, lo cual es muy adecuado para la comunicación entre subprocesos, interrupciones e interprocesos, pero tenga cuidado de no utilizar el bloqueo para enviar correos electrónicos en interrupciones.

Dado que el tamaño del mensaje del buzón solo puede ser de 4 bytes, y el puntero del sistema de 32 bits tiene exactamente 4 bytes, el buzón es muy adecuado para pasar datos de puntero.

Cómo usar el correo electrónico

En el desarrollo de proyectos reales, mucha información es una variable de estructura, ¿se puede enviar por correo electrónico? La respuesta no es problema, solo use un puntero de estructura.

//定义一个结构体指针(结构体成员自定义)
struct temp *pTemp;
//申请动态堆空间
pTemp = (struct temp*)rt_malloc(sizeof(struct temp));
//发送方在数据处理完成后,将这个消息指针发送给一个邮箱,邮箱名为mb
rt_mb_send(mb, (rt_uint32_t)pTemp);

Dado que el espacio de memoria del puntero de mensaje anterior se solicita manualmente, después de que el hilo recibe la información del buzón y se completa el procesamiento, también es necesario liberar manualmente el espacio del puntero de mensaje.

struct temp *pTemp;
if(rt_mb_recv(mb, (rt_uint32_t *)&pTemp) == RT_EOK)
{
    
    
	//数据处理完成后,释放消息指针内存空间
	rt_free(pTemp);
}

bloque de control del buzón

struct rt_mailbox
{
    
    
    struct rt_ipc_object parent;                        /**< 继承自ipc_object类 */

    rt_ubase_t          *msg_pool;                      /**< 邮箱缓冲区的开始地址 */

    rt_uint16_t          size;                          /**< 邮箱缓冲区的大小 */

    rt_uint16_t          entry;                         /**< 邮箱中邮件的数目 */
    rt_uint16_t          in_offset;                     /**< 邮箱缓冲的入口指针 */
    rt_uint16_t          out_offset;                    /**< 邮箱缓冲的出口指针 */

    rt_list_t            suspend_sender_thread;         /**< 发送线程的挂起等待队列 */
};

Interfaz de función de buzón

Crear buzón rt_mb_create()

rt_mailbox_t rt_mb_create(const char* name, rt_size_t size, rt_uint8_t flag);

Al crear un objeto de buzón, primero se crea un bloque de control de objeto de buzón y luego se asigna un espacio de memoria al buzón para almacenar el correo. El tamaño de esta memoria es igual al producto del tamaño del correo (4 bytes) y el capacidad del buzón, y luego se inicializa para recibir correo y enviar El desplazamiento del mensaje en el buzón. Para los objetos IPC creados con el indicador de prioridad RT_IPC_FLAG_PRIO, cuando varios subprocesos están esperando recursos, el subproceso con mayor prioridad obtendrá los recursos primero. El objeto IPC creado mediante el indicador FIFO RT_IPC_FLAG_FIFO obtendrá los recursos por orden de llegada cuando varios subprocesos estén esperando recursos.

parámetro describir
nombre el nombre del buzón
Talla Capacidad del buzón
bandera signo de buzón

Eliminar buzón rt_mb_delete()

rt_err_t rt_mb_delete(rt_mailbox_t mb);

Al eliminar un buzón, si un subproceso se suspende en el objeto del buzón, el kernel primero activa todos los subprocesos suspendidos en el buzón (el subproceso obtiene el valor de retorno de -RT_ERROR), luego libera la memoria utilizada por el buzón y finalmente elimina el objeto del buzón.

parámetro describir
megabyte identificador del objeto de buzón

Inicializar buzón rt_mb_init()

rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool,
rt_size_t size, rt_uint8_t flag)

Al inicializar el buzón, esta interfaz de función necesita obtener el bloque de control del objeto del buzón, el puntero del búfer y el nombre del buzón y la capacidad del buzón que el usuario ha solicitado. Para los objetos IPC creados con el indicador de prioridad RT_IPC_FLAG_PRIO, cuando varios subprocesos están esperando recursos, el subproceso con mayor prioridad obtendrá los recursos primero. El objeto IPC creado mediante el indicador FIFO RT_IPC_FLAG_FIFO obtendrá los recursos por orden de llegada cuando varios subprocesos estén esperando recursos.

parámetro describir
megabyte identificador del objeto de buzón
nombre el nombre del buzón
grupo de mensajes puntero de búfer
Talla Capacidad del buzón
bandera signo de buzón

Buzón recibe rt_mb_recv()

rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t* valor, rt_int32_t tiempo de espera);

Al recibir correos electrónicos, el destinatario debe especificar el identificador del buzón para recibir los correos electrónicos y especificar la ubicación de almacenamiento de los correos electrónicos recibidos y el período máximo de tiempo de espera que se puede esperar. Si se establece un tiempo de espera al recibir, cuando el correo electrónico aún no se recibe dentro del tiempo especificado, se devolverá -RT_ETIMEOUT.

parámetro describir
megabyte identificador del objeto de buzón
valor contenido del correo electrónico
se acabó el tiempo Especificar tiempo de espera

Envío de buzón rt_mb_send() (sin bloqueo)

rt_err_t rt_mb_send(rt_mailbox_t mb, valor rt_uint32_t);

El correo enviado puede ser datos de 32 bits en cualquier formato, un valor entero o un puntero a un búfer. Cuando el correo en el buzón está lleno, el subproceso que envía el correo o el programa de interrupción recibirá el valor de retorno de -RT_EFULL.

parámetro describir
megabyte identificador del objeto de buzón
valor contenido del correo electrónico

Envío de buzón rt_mb_send_wait() (bloqueo)

rt_err_t rt_mb_send_wait(rt_mailbox_t mb, valor rt_uint32_t, tiempo de espera rt_int32_t);

La diferencia entre rt_mb_send_wait y rt_mb_send es que si el buzón está lleno, el subproceso de envío esperará a que se desocupe el espacio en el buzón para recibir correo de acuerdo con el parámetro de tiempo de espera establecido. Si aún no hay espacio libre después del tiempo de espera establecido, el hilo de envío se activará y devolverá un código de error.

parámetro describir
megabyte identificador del objeto de buzón
valor contenido del correo electrónico
se acabó el tiempo Especificar tiempo de espera

experimento de buzón

Para usar la comunicación de buzón en RT-Thread, primero debe modificar el rtconfigharchivo de configuración. Puede utilizar los siguientes dos métodos:

  1. Descomentar, abrir definición de macro,

inserte la descripción de la imagen aquí

  1. O use el Configuration Wizardasistente para la configuración gráfica,

inserte la descripción de la imagen aquí

Este experimento se refiere al texto original correspondiente al código experimental, que solo contiene la función man(), y el código relacionado con la inicialización periférica no se proporciona a continuación.

En este experimento, se deben crear dos subprocesos, a saber, el subproceso de recepción y el subproceso de envío. El subproceso de recepción es responsable de recibir la información del buzón e imprimirla en el puerto serie, y el subproceso de envío es responsable de escanear los botones. Cuando el se detecta el botón, la información del buzón correspondiente se envía al buzón.

#include "board.h"
#include "rtthread.h"

// 定义线程控制块指针
static rt_thread_t recv_thread = RT_NULL;
static rt_thread_t send_thread = RT_NULL;

// 定义邮箱控制块
static rt_mailbox_t test_mb = RT_NULL;


// 实验需要用到的全局变量
char test_str1[] = "this is a mail test 1";
char test_str2[] = "this is a mail test 2";



/******************************************************************************
* @ 函数名  : recv_thread_entry
* @ 功  能  : 接收线程入口函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void recv_thread_entry(void *parameter)
{
    
    
	rt_err_t uwRet = RT_EOK;
	char *r_str;
	while(1)
	{
    
    
		// 等待接收邮箱信息
		uwRet = rt_mb_recv(test_mb,                          // 邮箱对象句柄
					(rt_uint32_t*)&r_str,                    // 接收邮箱信息
					RT_WAITING_FOREVER);                     // 超时一直等
		
		if(uwRet == RT_EOK)
		{
    
    
			rt_kprintf("邮箱接收到的内容:%s\n\n", r_str);
			LED0_TOGGLE;    // LED0 反转
		}
		else
		{
    
    
			rt_kprintf("邮箱接收错误!\n");
		}
	}	
}

/******************************************************************************
* @ 函数名  : send_thread_entry
* @ 功  能  : 发送线程入口函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void send_thread_entry(void *parameter)
{
    
    
	rt_err_t uwRet = RT_EOK;
	while(1)
	{
    
    
		
		// KEY0 被按下
		if(Key_Scan(KEY0_GPIO_PORT, KEY0_GPIO_PIN) == KEY_ON)
		{
    
    
			rt_kprintf("send:KEY0被单击\n");
			// 发送邮箱信息1
			uwRet = rt_mb_send(test_mb, (rt_uint32_t)&test_str1);
			if(uwRet == RT_EOK)
				rt_kprintf("邮箱信息发送成功!\n\n");
			else
				rt_kprintf("邮箱信息发送失败!\n\n");
		}
		
		// WK_UP 被按下
		if(Key_Scan(WK_UP_GPIO_PORT, WK_UP_GPIO_PIN) == KEY_ON)
		{
    
    
			rt_kprintf("send:WK_UP被单击\n");
			// 发送邮箱2
			uwRet = rt_mb_send(test_mb, (rt_uint32_t)&test_str2);
			if(uwRet == RT_EOK)
				rt_kprintf("邮箱信息发送成功!\n\n");
			else
				rt_kprintf("邮箱信息发送失败!\n\n");
		}
		rt_thread_delay(20);     //每20ms扫描一次
	}
}

int main(void)
{
    
    
	// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成
	
	// 创建一个邮箱
	test_mb =                                     // 邮箱控制块指针
	rt_mb_create("test_mb",                       // 邮箱初始值
				    10,                           // 邮箱大小
	                RT_IPC_FLAG_FIFO);            // FIFO队列模式(先进先出)
	
	if(test_mb != RT_NULL)
		rt_kprintf("邮箱创建成功!\n");

	// 创建一个动态线程
	recv_thread =                                 // 线程控制块指针
	rt_thread_create("recv",                      // 线程名字
	                recv_thread_entry,            // 线程入口函数
	                RT_NULL,                      // 入口函数参数
	                255,                          // 线程栈大小
				    5,                            // 线程优先级
					10);                          // 线程时间片
	
	
	// 开启线程调度
	if(recv_thread != RT_NULL)
		rt_thread_startup(recv_thread);
	else
		return -1;
							
	// 创建一个动态线程
	send_thread =                                 // 线程控制块指针
	rt_thread_create("send",                      // 线程名字
	                send_thread_entry,            // 线程入口函数
	                RT_NULL,                      // 入口函数参数
	                255,                          // 线程栈大小
				    5,                            // 线程优先级
					10);                          // 线程时间片
	// 开启线程调度
	if(send_thread != RT_NULL)
		rt_thread_startup(send_thread);
	else
		return -1;
}

Fenómenos experimentales

Cuando se presiona KEY0, el subproceso de envío envía la información del buzón 1 al subproceso de recepción. Cuando se presiona WK_UP, el subproceso de envío envía la información del buzón 2 al subproceso de recepción. Cuando el subproceso de recepción recibe la información del buzón, imprime el contenido recibido:

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_43772810/article/details/123981624
Recomendado
Clasificación