• stm32cubemx hal学习记录:FreeRTOS消息队列


    一、基本介绍

    1、消息队列就是一个像容器一样的东西,我们所有的任务都可以往内部写,然后队列会将我们的消息按顺序存下来,所有的任务也可以按顺序将其读出来。

    2、队列需要明确数据的大小以及队列的长度,写队列和读队列都是采用赋值的方式将数据复制过去使用的。

    3、数据的操作默认采用先进先出的方式,写数据时放到尾部,读数据时从头部读

    二、基本配置

    1、配置RCC、USART1、时钟84MHz

    2、配置SYS,将Timebase Source修改为除滴答定时器外的其他定时器。

    3、初始化LED的两个引脚、两个按键引脚

    4、开启FreeRTOS,v1与v2版本不同,一般选用v1即可

    5、创建消息队列

    Queue Name: 队列名称
    Queue Size: 队列能够存储的最大单元数目,即队列深度
    Queue Size: 队列中数据单元的长度,以字节为单位
    Allocation: 分配方式:Dynamic 动态内存创建
    Buffer Name: 缓冲区名称
    Buffer Size: 缓冲区大小
    Conrol Block Name: 控制块名称

    6、创建两个线程,一个接收,一个发送

     7、生成代码

    三、API

    1、队列ID:osMessageQId

    osMessageQId TestQueueHandle;

    2、使用动态内存的方式创建一个新的队列:osMessageCreate

    1. osMessageQDef(TestQueue, 16, uint16_t);
    2. TestQueueHandle = osMessageCreate(osMessageQ(TestQueue), NULL);

    3、队列删除:osMessageDelete

    osMessageDelete(TestQueueHandle);

    4、向队列尾部发送一个队列消息:osMessagePut

    消息以拷贝的形式入队,而不是以引用的形式,可用在中断服务程序中。

    1. osMessagePut(TestQueueHandle,send_data1,0);
    2. 三个参数分别为:消息队列的句柄,发送的消息内容,等待时间
    1. void Send_thread_entry(void const * argument)
    2. {
    3. /* USER CODE BEGIN Send_thread_entry */
    4. /* Infinite loop */
    5. osEvent xReturn;
    6. uint32_t send_data1;
    7. for(;;)
    8. {
    9. if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8)==0)
    10. {
    11. printf("send_data1\n");
    12. xReturn.status=osMessagePut(TestQueueHandle,send_data1,0);
    13. if(osOK!=xReturn.status)
    14. {
    15. printf("send fail\n");
    16. }
    17. }
    18. osDelay(100);
    19. }
    20. /* USER CODE END Send_thread_entry */
    21. }

    5、从一个队列中接收消息并把消息从队列中删除:osMessageGet

    接收的消息是以拷贝的形式进行的,所以我们必须提供一个足够大的空间的缓冲区,可以在中断服务中运行。

    1. osMessageGet(TestQueueHandle,osWaitForever);
    2. 两个参数分别为:消息队列的句柄,等待时间(此时为一直等待)
    1. void Receive_thread_entry(void const * argument)
    2. {
    3. /* USER CODE BEGIN Receive_thread_entry */
    4. /* Infinite loop */
    5. osEvent event;
    6. for(;;)
    7. {
    8. event=osMessageGet(TestQueueHandle,osWaitForever);
    9. if(osEventMessage==event.status)
    10. {
    11. printf("receive data:%d\n",event.value.v);
    12. }
    13. else
    14. {
    15. printf("error:0x%d\n",event.status);
    16. }
    17. }
    18. /* USER CODE END Receive_thread_entry */
    19. }

    6、从队列中接收数据单元,但是并不删除接收到的单元:osMessagePeek

    从队列中接收到数据后,不会修改队列中的数据,也不会改变数据在队列中的存储顺序

    7、查询队列中当前有校的数据单元个数:osMessageWaiting

    uint32_t a=osMessageWaiting(TestQueueHandle);

    四、代码解释

    这个功能相当于在两个任务之间传递数据,一个发送,一个接收。

    1、传输数字

    ①发送

    1. void Send_thread_entry(void const * argument)
    2. {
    3. osEvent xReturn;
    4. uint32_t send_data1;
    5. for(;;)
    6. {
    7. printf("send_data1\n");
    8. xReturn.status=osMessagePut(TestQueueHandle,send_data1,0);
    9. if(osOK!=xReturn.status)
    10. {
    11. printf("send fail\n");
    12. }
    13. osDelay(100);
    14. }
    15. }

    ②接收

    1. void Receive_thread_entry(void const * argument)
    2. {
    3. osEvent event;
    4. for(;;)
    5. {
    6. event=osMessageGet(TestQueueHandle,osWaitForever);
    7. if(osEventMessage==event.status)
    8. {
    9. printf("receive data:%d\n",event.value.v);
    10. }
    11. else
    12. {
    13. printf("error:0x%d\n",event.status);
    14. }
    15. }
    16. }

    2、传输字符串或者结构体

    ①发送

    1. typedef struct
    2. {
    3. uint8_t name;
    4. uint8_t id;
    5. uint8_t age;
    6. }T_data;
    7. void Send_thread_entry(void const * argument)
    8. {
    9. for(;;)
    10. {
    11. T_data m_data;
    12. m_data.age=20;
    13. m_data.id=2;
    14. m_data.name=1;
    15. osMessagePut(TestQueueHandle,(uint32_t)&m_data,0);
    16. osDelay(100);
    17. }
    18. }

    ②接收

    1. void Receive_thread_entry(void const * argument)
    2. {
    3. osEvent event;
    4. for(;;)
    5. {
    6. event=osMessageGet(TestQueueHandle,osWaitForever);
    7. if(event.status==osEventMessage)
    8. {
    9. T_data *pData=(T_data *)event.value.p;
    10. printf("data=%d\n",pData->age);
    11. printf("id=%d\n",pData->id);
    12. printf("name=%d\n",pData->name);
    13. }
    14. }
    15. }

    3、以邮箱的形式传输数据

    邮箱不能使用cubemx自动生成,需要手动添加

    1. osMailQId mailQ01Handle;
    2. osMailQDef(mailQ01,15,T_data);
    3. mailQ01Handle=osMailCreate(osMailQ(mailQ01),NULL);

    ①邮箱发送数据

    1. T_data m_data;
    2. m_data.age=20;
    3. m_data.id=2;
    4. m_data.name=1;
    5. osMailPut(mailQ01Handle,&m_data);

    ②邮箱接收数据

    1. osEvent event=osMailGet(mailQ01Handle,osWaitForever);
    2. if(event.status==osEventMail)
    3. {
    4. T_data *m_Data=(T_data *)event.value.p;
    5. printf("data=%d\n",m_Data->age);
    6. printf("id=%d\n",m_Data->id);
    7. printf("name=%d\n",m_Data->name);
    8. }

    五、代码总结

    创建一个队列:

    osMessageQId TestQueueHandle;

    osMessageQDef(TestQueue, 16, uint16_t);
    TestQueueHandle = osMessageCreate(osMessageQ(TestQueue), NULL);

    删除队列:

    osMessageDelete(TestQueueHandle);

    发送一个数字:

    uint32_t send_data=100;

    osMessagePut(myQueue01Handle,send_data,0);

    接收一个数字:

    osMessageGet(myQueue01Handle,osWaitForever);

    发送一个字符串或者结构体:

    typedef struct
    {
        uint8_t name;
        uint8_t age;
        uint8_t id;
    }T_Data;

    T_Data m_data;
    m_data.age=18;
    m_data.name=12;
    m_data.id=123;
            
    osMessagePut(myQueue01Handle,(uint32_t)&m_data,0);

      

    接收一个字符或者结构体:

    uint8_t name;
    uint8_t id;
    uint8_t age;

    osEvent event=osMessageGet(myQueue01Handle,osWaitForever);
    T_Data *p_data=(T_Data *)event.value.p;
    name=p_data->name;
    id=p_data->id;
    age=p_data->age;

    创建邮箱:

    osMailQId mailQ01Handle;

     

    收发的类型设置为结构体T_data

    osMailQDef(mailQ01,15,T_data);
    mailQ01Handle=osMailCreate(osMailQ(mailQ01),NULL);

    邮箱发送数据:

    T_Data m_data;
    m_data.age=18;
    m_data.name=12;
    m_data.id=123;
    osMailPut(mailQ01Handle,&m_data);

    邮箱接收数据:

    osEvent event=osMailGet(mailQ01Handle,osWaitForever);
    T_Data *p_data=(T_Data *)event.value.p;
    name=p_data->name;
    id=p_data->id;
    age=p_data->age;

  • 相关阅读:
    什么专业最适合学网络安全?一篇文章告诉你
    Springboot导出mysql数据到Excel表
    产品经理工作职责是什么?
    什么是全媒体整合营销?如何做好全媒体整合营销呢?
    C++ 中指针常量、指向常量的指针、引用类型的常量
    k8s部署Eureka集群
    机器学习:逻辑回归--过采样
    JAVA设计模式-责任链模式
    spring boot零配置
    怎么关闭php错误提示?两者方法分享
  • 原文地址:https://blog.csdn.net/ohhjack/article/details/127954934