RT-Thread Getting Started Study Notes - Familiarizado com o uso de filas de mensagens

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
  • enviar mensagens
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.

Acho que você gosta

Origin blog.csdn.net/tcjy1000/article/details/114900996
Recomendado
Clasificación