fundo
- A fila de mensagens do RT-Thread é usada para comunicação entre threads, transmissão de comandos e dados, o que é muito conveniente
- As filas de mensagens são mais convenientes de usar do que as caixas de correio e transmitem dados mais curtos e de comprimento variável sem aplicação dinâmica de memória
- O recebimento da fila de mensagens requer threads
- A fila de mensagens pode ser enviada em retorno de chamada de interrupção, thread, shell cmd.
O que a fila de mensagens pode fazer
- A transmissão de dados e comandos entre threads, a realização da máquina de estado e o cache da fila não perderão as operações
- Fila de mensagens, o conteúdo pode ter comprimento variável, não pode ser uma variável global, a fila de mensagens fará backup dos dados transmitidos
- A fila de mensagens pode transmitir comandos e dados. Para dados complexos, você pode usar um corpo de mensagem personalizado.
Exemplo de operação
- Defina o corpo da mensagem do usuário da fila de mensagens
#ifndef MAX_PHONE_MSG_MQ_SIZE
#define MAX_PHONE_MSG_MQ_SIZE 32
#endif
/* messagequeue struct */
struct mq_msg
{
rt_uint32_t cmd; /* command or event, msg id */
rt_uint32_t dat; /* mq load data */
rt_uint32_t len; /* mq load buffer length */
char *buf; /* mq load buffer pointer */
};
enum PHONE_MSG_
{
MSG_PHONE_OPEN_DIAL = 0,
MSG_PHONE_INCOMING,
MSG_PHONE_ANSWER,
MSG_PHONE_END_DIAL,
};
- Inicialize a fila de mensagens, observe que antes de usá-la, você precisa inicializar a fila de mensagens
static rt_err_t phone_mq_init(void)
{
rt_err_t ret = RT_EOK;
ret = rt_mq_init(&phone_mq, "phone_mq", &phone_msg_buf,
sizeof(struct mq_msg), sizeof(phone_msg_buf), RT_IPC_FLAG_FIFO);
if (ret != RT_EOK)
{
LOG_E("%s : error!", __func__);
return -RT_ERROR;
}
return ret;
}
- Crie o encadeamento de processamento de recebimento da fila de mensagens. O recebimento está bloqueado e precisa ser colocado no encadeamento
static void phone_task_entry(void *param)
{
struct mq_msg recv_msg = { 0 };
while(1)
{
if (rt_mq_recv(&phone_mq, &recv_msg, sizeof(recv_msg), RT_WAITING_FOREVER) == RT_EOK)
{
switch (recv_msg.cmd)
{
case MSG_PHONE_OPEN_DIAL:
LOG_D("%s: MSG_PHONE_OPEN_DIAL.", __func__);
break;
case MSG_PHONE_INCOMING:
LOG_D("%s: MSG_PHONE_INCOMING.", __func__);
break;
case MSG_PHONE_END_DIAL:
LOG_D("%s: MSG_PHONE_END_DIAL.", __func__);
break;
case MSG_PHONE_ANSWER:
LOG_D("%s: MSG_PHONE_ANSWER.", __func__);
break;
default:
break;
}
}
phone_mq_free(&recv_msg);
}
}
/* 消息队列接收线程初始化 */
int phone_task_init(void)
{
rt_thread_t tid;
phone_mq_init();
tid = rt_thread_create("phone", phone_task_entry, RT_NULL, 2048, 10, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
LOG_D("%s: end.", __func__);
return 0;
}
else
{
LOG_E("%s: error!", __func__);
return -1;
}
}
INIT_APP_EXPORT(phone_task_init);
- Para enviar mensagens, comandos shell são usados aqui. O envio pode ser feito em threads, interrupções e chamadas de retorno. Tenha cuidado para não solicitar memória nas interrupções.
/* 发送消息 */
rt_err_t phone_send_msg(struct mq_msg *msg)
{
if (msg == RT_NULL)
return -RT_ERROR;
return rt_mq_send(&phone_mq, msg, sizeof(struct mq_msg));
}
/* 消息中free掉用户动态申请的内存【按需】 */
static void phone_mq_free(struct mq_msg *msg)
{
if (msg)
{
if (msg->buf)
{
rt_free(msg->buf);
msg->buf = RT_NULL;
}
}
}
/* shell命令,用于验证发送命令 */
void phone_open_dial(void)
{
struct mq_msg msg = { 0 };
msg.cmd = MSG_PHONE_OPEN_DIAL;
phone_send_msg(&msg);
}
void phone_end_dial(void)
{
struct mq_msg msg = { 0 };
msg.cmd = MSG_PHONE_END_DIAL;
phone_send_msg(&msg);
}
void phone_answer_dial(void)
{
struct mq_msg msg = { 0 };
msg.cmd = MSG_PHONE_ANSWER;
phone_send_msg(&msg);
}
MSH_CMD_EXPORT(phone_open_dial, phone_open_dial);
MSH_CMD_EXPORT(phone_end_dial, phone_end_dial);
MSH_CMD_EXPORT(phone_answer_dial, phone_answer_dial);
Compilar, baixar e verificar funcional
- Use a plataforma STM32L4 ou simulador de PC
- list_thread ver discussão de recebimento de fila de mensagens
msh >list_thread
thread pri status sp stack size max used left tick error
-------- --- ------- ---------- ---------- ------ ---------- ---
tshell 20 running 0x00000088 0x00001000 12% 0x00000005 000
phone 10 suspend 0x000000ac 0x00000800 08% 0x00000005 000
tidle0 31 ready 0x00000080 0x00000400 12% 0x00000003 000
main 10 suspend 0x0000008c 0x00000800 13% 0x00000009 000
msh >phone_open_dial
[D/phone] phone_task_entry: MSG_PHONE_OPEN_DIAL.
msh >phone_end_dial
[D/phone] phone_task_entry: MSG_PHONE_END_DIAL.
msh >phone_answer_dial
[D/phone] phone_task_entry: MSG_PHONE_ANSWER.
resumo de um problema
- A fila de mensagens só pode ser usada após ser inicializada. Se você usar um emulador, a função de inicialização automática pode falhar e será necessário inicializá-la manualmente.
- A função de recepção rt_mq_recv precisa julgar se a execução foi bem-sucedida, == RT_EOK não pode ser omitido, caso contrário, a mensagem é recebida com sucesso, o julgamento falha e a mensagem não é processada.
if (rt_mq_recv(&phone_mq, &recv_msg, sizeof(recv_msg), RT_WAITING_FOREVER) == RT_EOK) /* 【== RT_EOK不能丢,否则无法进入接收,原因是RT_EOK是0 】 */
Resumindo
- Use RT-Thread corretamente para resolver o problema de troca de dados e comando entre threads, que podem ser usados para transmissão de dados
- Familiarizado com a comunicação IPC entre threads.