ucosIII_消息队列

 1.消息队列的作用

 对比信号量和互斥信号量。信号量和互斥信号量是用来完成任务间同步或共享资源加锁的。也就是说这两种都是一种flag标志位作用。表示一种事件的发生,并不能传递数据。那比如说我想让任务A给任务B发送4个字节的数据,怎么办?所以引入了消息队列的概念。

2.消息队列的API 文件os_q.c

2.1创建消息队列

void  OSQCreate (OS_Q        *p_q,
                 CPU_CHAR    *p_name,
                 OS_MSG_QTY   max_qty,
                 OS_ERR      *p_err)

 第一个参数是一个消息队列的结构体变量,需要先定义在:

OS_Q DATA_Msg;                //定义一个消息队列,用于发送数据

第二个参数是一个名字

第三个参数是是需要传递的数据的长度,字节为单位

第四个参数是保存返回值的变量

2.2删除消息队列

OS_OBJ_QTY  OSQDel (OS_Q    *p_q,
                    OS_OPT   opt,
                    OS_ERR  *p_err)

2.3发送消息

void  OSQPost (OS_Q         *p_q,
               void         *p_void,
               OS_MSG_SIZE   msg_size,
               OS_OPT        opt,
               OS_ERR       *p_err)

 第一个参数是一个消息结构体变量

第二个参数是传递的数据的第一个字节的地址(如果是数组则传数组名,如果是malloc分配的内存需要传对应的指针即可)

第三个参数是传递数据的大小,字节为单位

第四个参数是 

  OS OPT POST ALL
  OS OPT POST FIFO
  OS OPT POST LIFO
  0S OPT POST NO SCHED

2.4请求消息

void  *OSQPend (OS_Q         *p_q,
                OS_TICK       timeout,
                OS_OPT        opt,
                OS_MSG_SIZE  *p_msg_size,
                CPU_TS       *p_ts,
                OS_ERR       *p_err)

第一个参数是消息结构体变量

第二个参数是超时时间

第三个参数是设置阻塞还是不阻塞

第四个参数是传递的数据的大小(这个参数是一个输出型参数,是请求到数据后自动计算有多少字节的数据,我们需要读它)

第五个参数是时间戳

第六个参数是记录错误返回值的

使用过程:

1 任务A发送消息队列,包含数据多少字节

2 任务B接收消息队列,自动计算消息队列有多少字节

 3.任务之间使用消息队列传递数据

现在创建2个任务A和B,任务A发送数据,任务B接收数据。先使用消息队列发送字符串在发送4个字节的int数据。记录下遇到的问题。

3.1传递字符串

省略基础代码,只保留和消息队列相关的。

定义数据大小和消息队列(全局)

#define MyMsgSizeInByte    4    //发送数据的消息队列的大小
OS_Q MyMsg;                //定义一个消息队列,用于发送数据

创建消息队列(在第一个任务中,)

//创建消息队列MyMsg
    OSQCreate ((OS_Q*        )&MyMsg,    
                (CPU_CHAR*    )"MyMsg",    
                (OS_MSG_QTY    )MyMsgSizeInByte,    
                (OS_ERR*    )&err);    

任务A:发送数据

//任务A的任务函数
void taskA(void *p_arg)
{
    OS_ERR err;
    u8 *p;
    u8 *pbuf;
char * TaskAData = "TaskADatatoPost";
while(1) { printf("任务1 "); OSQPost(&MyMsg,TaskAData,sizeof(TaskAData),OS_OPT_POST_FIFO + OS_OPT_POST_ALL,&err);
     printf("任务1 post 数据:%s ",TaskAData);
        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
    }
}

任务B:请求数据

//任务B任务函数
void taskB(void *p_arg)
{    
    u8 num;
    u8 datas[4]= {0};
    OS_MSG_SIZE size = 10;
    OS_ERR err;
    u8 *TaskBData;
    
    while(1)
    {
        //printf("任务2
");
        TaskBData = OSQPend(&MyMsg,0,OS_OPT_PEND_BLOCKING,&size,0,&err);
       
        printf("任务2 pend 数据:%s
",TaskBData);
        printf("size大小%d
",size);
        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s   
    }
}

结果

发送字符串很顺利。

3.2传递多个int类型数据

 在发送4个字节int数据时遇到了个问题,只能接收第一个字节的数据。

定义了1个全局数组用来发送数据

int datatopost[4] = {15,16,17,18}; //存放任务A发
任务A:发送数据
//任务A的任务函数
void taskA(void *p_arg)
{
    u8 key,num;
    OS_ERR err;
    u8 *p;
    u8 *pbuf;
while(1)
    {
        
        printf("任务1
");

        OSQPost(&MyMsg,datatopost,4,OS_OPT_POST_FIFO + OS_OPT_POST_ALL,&err);
        printf("任务1 post 数据:%d%d%d%d
",datatopost[0],datatopost[1],datatopost[2],datatopost[3]);

        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    }
}

任务B:接收数据

//任务B任务函数
void taskB(void *p_arg)
{    
    u8 num;
    u8 datas[4]= {0};
    OS_MSG_SIZE size = 10;
    OS_ERR err;
    u8 *TaskBData;//接收数据的指针

    while(1)
    {
        //printf("任务2
");
        TaskBData = OSQPend(&MyMsg,0,OS_OPT_PEND_BLOCKING,&size,0,&err);
        printf("任务2 pend 数据:%d%d%d%d
",TaskBData[0],TaskBData[1],TaskBData[2],TaskBData[3]);

        printf("size大小%d
",size);
        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s

         
    }
}

结果:

 我在任务B中定义了一个u8指针用来接收这4个字节的数据。但是从运行结果中看到任务B确实接收到了4个字节,但是只能接收到第一个字节的数据。经过查找资料,最后发现要使用malloc给消息队列分配内存才行,改进代码后,任务A发送的数据不再使用全局变量,在任务A中使用malloc函数分配内存,经过测试只要发送的时候使用malloc,任务B接收的时候直接定义一个指针还是使用malloc分配内存,都可以接收到。关于详细的介绍在最后面的博客地址中有介绍。下面使用的mymalloc是原子封装的ucos系统下的malloc函数。

任务 A

//任务A的任务函数
void taskA(void *p_arg)
{
    u8 key,num;
    OS_ERR err;
    u8 *p;
    u8 *pbuf;
   
    pbuf = mymalloc(SRAMIN,10);    //申请10个字节
    pbuf[0]=15;pbuf[1]=16;pbuf[2]=17;pbuf[3]=18;
    
    while(1)
    {
        
        printf("任务1
");

        OSQPost(&MyMsg,pbuf,4,OS_OPT_POST_FIFO + OS_OPT_POST_ALL,&err);
        printf("任务1 post 数据:%d%d%d%d
",pbuf[0],pbuf[1],pbuf[2],pbuf[3]);

        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    }
}

任务B

//任务B任务函数
void taskB(void *p_arg)
{    
    u8 num;
    u8 datas[4]= {0};
    OS_MSG_SIZE size = 10;
    OS_ERR err;
    u8 *TaskBData;
    //TaskBData = mymalloc(SRAMIN,10);    //申请10个字节 无论这里是否分配内存都可以接到4个字节完整的数据

    while(1)
    {
        //printf("任务2
");
        TaskBData = OSQPend(&MyMsg,0,OS_OPT_PEND_BLOCKING,&size,0,&err);
        printf("任务2 pend 数据:%d%d%d%d
",TaskBData[0],TaskBData[1],TaskBData[2],TaskBData[3]);

        printf("size大小%d
",size);
        OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
     
    }
}

结果:

  参考资料:

1.消息队列接收数据覆盖问题https://blog.csdn.net/u012252959/article/details/53115024

2.原子的mymalloc

原文地址:https://www.cnblogs.com/1024E/p/13416955.html