FreeRTOS进程间通信-消息队列

消息队列是进程间的一种通信机制,实际项目运用很多。

1、什么是消息队列?

2、消息队列API函数

3、在进程间通信使用消息队列

4、在中断中使用消息队列

1.1、消息队列是什么?

      消息队列是realtime os 内核提供的服务,任务之间或者是中断中可以将一个消息放到队列中进行传递,freertos可以通过内核API获取到队列中的数据,freertos传递了实际数据。消息可以由多个任务压入队列,一个队列也可以被多个任务读取,消息队列的获取遵循fifo原则,freertos支持fifo以及lifo.

对比裸机编程,消息队列有如下特点:

a.裸机下需要自己实现超时等待机制,rtos下不用自己实现,且该机制的数据管理交给rtos;

b.裸机下的全局变量需要防止多任务访问冲突,消息队列自己处理这个问题,无需码农担心这个问题;

c.解决中断server和task之间的消息传递;

1.2消息队列的实现方式

通过图片可对消息队列有个具体认知。

---》该队列可以存放是个数据单元;

---》task1给task2传递数据,task2从队列中获取数据;

---》fifo方式存取;

存取过程会出现两种情况:

a、task1存放数据速度大于task2 速度,会出现队列放满的情况,freertos 中的xQueueSend已经实现超时等待功能,用户可以设置超时等待时间直到超时时间溢出或者是队列有空;

b、队列会满当然也会空,当队列为空,依然可以设置超时等待,直到超时或者是队列有数据;

1.3在中断中实现消息队列

a.中断中无法实现超时等待功能,所以在中断里面往队列里面压数据需要先判断队列是否满,消息队列发送函数xQueueSendFromISR不支持超时设置。

b、队列会满当然也会空,当队列为空,依然可以设置超时等待,直到超时或者是队列有数据;

注意:

a.中断serverfunc需要尽量短,因为进入中断是进入临界区下的代码,是关闭中断的,如果代码太长,会导致其他中断得不到及时响应;

b.中断服务程序中一定要调用专用于中断的消息队列函数,即以FromISR结尾的函数

 

2.消息队列API

(1)    xQueueCreateStatic() 
(2)    vQueueDelete()
(3)    xQueueSend()
(4)    xQueueSendFromISR()
(5)    xQueueSendToBack()
(6)    xQueueSendToBackFromISR()
(7)    xQueueSendToFront()
(8)    xQueueSendToFrontFromISR()
(9)    xQueueReceive()
(10)    xQueueReceiveFromISR()
(11)    uxQueueMessagesWaiting()
(12)    uxQueueMessagesWaitingFromISR()
(13)    uxQueueSpacesAvailable()
(14)    xQueueReset()
(15)    xQueueOverwrite()
(16)    xQueueOverwriteFromISR()
(17)    xQueuePeek()
(18)    xQueuePeekFromISR()
(19)    vQueueAddToRegistry()
(20)    vQueueUnregisterQueue()
(21)    pcQueueGetName()
(22)    xQueueIsQueueFullFromISR()
(23)    xQueueIsQueueEmptyFromISR()

 

2.1主要函数:

 

(1)    xQueueCreate ()

函数xQueueCreate用于创建消息队列。

u  第1个参数是消息队列支持的消息个数。

u  第2个参数是每个消息的大小,单位字节。

u  返回值,如果创建成功会返回消息队列的句柄,如果由于FreeRTOSConfig.h文件中heap大小不足,无法为此消息队列提供所需的空间会返回NULL。

 

(2)    xQueueSend ()

函数xQueueSend用于任务中消息发送。

u  第1个参数是消息队列句柄。

u  第2个参数要传递数据地址,每次发送都是将消息队列创建函数xQueueCreate所指定的单个消息大小复制到消息队列空间中。

u  第3个参数是当消息队列已经满时,等待消息队列有空间时的最大等待时间,单位系统时钟节拍。

u  返回值,如果消息成功发送返回pdTRUE,否则返回errQUEUE_FULL。

使用这个函数要注意以下问题:

1.     FreeRTOS的消息传递是数据的复制,而不是传递的数据地址。

2.     此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是

xQueueSendFromISR。

3.     如果消息队列已经满且第三个参数为0,那么此函数会立即返回。

4.     如果用户将FreeRTOSConfig.h文件中的宏定义INCLUDE_vTaskSuspend配置为1且第三个参数配置为portMAX_DELAY,那么此发送函数会永久等待直到消息队列有空间可以使用。

5.     消息队列还有两个函数xQueueSendToBack和xQueueSendToFront,函数xQueueSendToBack实现的是FIFO方式的存取,函数xQueueSendToFront实现的是LIFO方式的读写。我们这里说的函数xQueueSend等效于xQueueSendToBack,即实现的是FIFO方式的存取。

 

(3)    xQueueSendFromISR ()

 

函数xQueueSendFromISR用于中断服务程序中消息发送。

u  第1个参数是消息队列句柄。

u  第2个参数要传递数据地址,每次发送都是将消息队列创建函数xQueueCreate所指定的单个消息大小复制到消息队列空间中。

u  第3个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE,说明有高优先级任务要执行,否则没有。

u  返回值,如果消息成功发送返回pdTRUE,否则返回errQUEUE_FULL。

使用这个函数要注意以下问题:

1.     FreeRTOS的消息传递是数据的复制,而不是传递的数据地址。正因为这个原因,用户在创建消息队列时单个消息大小不可太大,因为一定程度上面会增加中断服务程序的执行时间。

2.     此函数是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是xQueueSend。

3.     消息队列还有两个函数xQueueSendToBackFromISR和xQueueSendToFrontFromISR,函数xQueueSendToBackFromISR实现的是FIFO方式的存取,函数xQueueSendToFrontFromISR实现的是LIFO方式的读写。我们这里说的函数xQueueSendFromISR等效于xQueueSendToBackFromISR,即实现的是FIFO方式的存取。

 

(4)    xQueueReceive ()

函数xQueueReceive用于接收消息队列中的数据。

u  第1个参数是消息队列句柄。

u  第2个参数是从消息队列中复制出数据后所储存的缓冲地址,缓冲区空间要大于等于消息队列创建函数xQueueCreate所指定的单个消息大小,否则取出的数据无法全部存储到缓冲区,从而造成内存溢出。

u  第3个参数是消息队列为空时,等待消息队列有数据的最大等待时间,单位系统时钟节拍。

u  返回值,如果接到到消息返回pdTRUE,否则返回pdFALSE。

使用这个函数要注意以下问题:

1.     此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序使用的是xQueueReceiveFromISR。

2.     如果消息队列为空且第三个参数为0,那么此函数会立即返回。

3.     如果用户将FreeRTOSConfig.h文件中的宏定义INCLUDE_vTaskSuspend配置为1且第三个参数配置为portMAX_DELAY,那么此函数会永久等待直到消息队列有数据。

查看板子原理图,sclk链接的是GPIO5(哈哈,抽烟太多,板子在吃烟灰)

 

示例代码:

使用中断中的消息队列为api为实例:


static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
void mrfc_630_task()
{
unsigned char io_num;
    gpio_config_t io_conf;
      io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
    //bit mask of the pins, use GPIO4 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode    
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;
    gpio_config(&io_conf);

    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);///add intrrupt function 
while(1)
{

  if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }

}


}

 

测试结果如下(获取中断引脚的电平):

GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
GPIO[5] intr, val: 0
I (4843571) Touch pad: Waiting for any pad being touched...
I (4848571) Touch pad: Waiting for any pad being touched...

 

 

 

 

 

  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS中,可以使用消息队列和信号量这两种方式进行进程间通信。 1. 消息队列是一种在任务之间或者是中断中传递消息的机制。任务可以将消息放入队列中,并通过内核API来获取队列中的数据。消息队列遵循FIFO原则,即先进先出。在FreeRTOS中,可以使用队列集的结构来管理外设多的情况下的消息队列。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [FreeRTOS进程间通信-消息队列](https://blog.csdn.net/a13698709128/article/details/89429842)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [FreeRTOS任务间的通信](https://blog.csdn.net/weixin_47397155/article/details/126915957)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [FreeRTOS 通信方式](https://blog.csdn.net/WANGYONGZIXUE/article/details/121755186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值