07嵌入式实时操作系统FreeRTOS队列与消息传递.ppt
嵌入式实时操作系统嵌入式实时操作系统FreeRTOSFreeRTOS原理及应用原理及应用基基于于STM32STM32微控制器微控制器嵌入式实时操作系统嵌入式实时操作系统FreeRTOS原理及应用原理及应用张超张超 主编主编STM32 Cortex-M4通用开发板通用开发板嵌入式实时操作系统嵌入式实时操作系统FreeRTOS原理及应用原理及应用FreeRTOS队列及其结构队列及其结构队列操作队列操作用队列实现串口守护任务用队列实现串口守护任务FreeRTOS队列与消息传递队列与消息传递主要内容:主要内容:一、FreeRTOS队列及其结构队列及其结构FreeRTOS队列与消息传递队列与消息传递FreeRTOS队列特性队列特性FreeRTOS队列及其结构队列及其结构 1、存储数据:通常情况下,队列被作为FIFO(先进先出)使用。2、多任务访问:队列不属于某个任务,所有任务都可以操作队列。3、读队列时阻塞:当某个任务试图读一个队列时,可以指定一个阻塞超时时间,当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。4、写队列时阻塞:同读队列一样,任务也可以在写队列时指定一个阻塞超时时间。队列读写过程队列读写过程FreeRTOS队列及其结构队列及其结构二、队列操作队列操作FreeRTOS队列与消息传递队列与消息传递队列创建队列创建队列操作队列操作与任务创建一样,队列创建也有动态方法和静态方法两种,用xQueueCreate()动态方法创建队列和用xQueueCreateStatic()静态方法创建队列。动态创建方法使用动态内存分配,而静态方法需要用户指定相应内存区。队列创建队列创建队列操作队列操作1、xQueueCreate()用动态内存分配方法创建队列,这其实是一个宏,定义如下:#define xQueueCreate(uxQueueLength,uxItemSize)xQueueGenericCreate(uxQueueLength),(uxItemSize),(queueQUEUE_TYPE_BASE)QueueHandle_t xQueueGenericCreate(const UBaseType_t uxQueueLength,const UBaseType_t uxItemSize,const uint8_t ucQueueType);真正用来创建队列的是xQueueGenericCreate()函数,函数的原型为:队列创建队列创建队列操作队列操作2、xQueueCreateStatic()用静态方法创建队列,创建过程中使用的内存,需要用户事先分配。这也是一个宏,定义如下:#define xQueueCreateStatic(uxQueueLength,uxItemSize,pucQueueStorage,pxQueueBuffer)xQueueGenericCreateStatic(uxQueueLength),(uxItemSize),(pucQueueStorage),(pxQueueBuffer),(queueQUEUE_TYPE_BASE)队列创建队列创建队列操作队列操作QueueHandle_t xQueueGenericCreateStatic(const UBaseType_t uxQueueLength,const UBaseType_t uxItemSize,uint8_t*pucQueueStorage,StaticQueue_t*pxStaticQueue,const uint8_t ucQueueType);真正用来创建队列的是xQueueGenericCreateStatic()函数入队操作入队操作队列操作队列操作入队操作API有xQueueSend()、xQueueSendToBack()、xQueueSendToFront()、xQueueOverwrite()四个,它们都是长得像函数的宏,实际操作的是xQueueGenericSend()函数。xQueueSendFromISR()、xQueueSendToBackFromISR()、xQueueSendToFrontFromISR()、xQueueOverwriteFromISR()是入队函数的中断安全版本,实际操作的是xQueueGenericSendFromISR()函数。入队操作入队操作队列操作队列操作1、xQueueGenericSend()通用入队函数,函数原型为:BaseType_txQueueGenericSend(QueueHandle_t xQueue,const void*const pvItemToQueue,TickType_t xTicksToWait,const BaseType_t xCopyPosition);入队操作入队操作队列操作队列操作2、xQueueGenericSendFromISR()中断服务中使用的入队函数,函数原型为:BaseType_txQueueGenericSend(QueueHandle_t xQueue,const void*const pvItemToQueue,BaseType_t*const pxHigherPriorityTaskWoken,const BaseType_t xCopyPosition);出队出队操作操作队列操作队列操作从队列中获取数据,需要用到出队操作。出队操作有xQueueReceive()和xQueuePeek()二个函数,它们的中断安全版本是xQueueReceiveFromISR()和xQueuePeekFromISR()。出队出队操作操作队列操作队列操作1、xQueueReceive()从指定的队列中读取消息,读取成功后会将队列中的这个数据删除,函数的原型为:BaseType_txQueueReceive(QueueHandle_t xQueue,void*const pvBuffer,TickType_t xTicksToWait);出队出队操作操作队列操作队列操作2、xQueuePeek()从指定的队列中读取消息,读取成功后并不删除队列中的这个数据,函数的原型为:BaseType_txQueuePeek(QueueHandle_t xQueue,void*const pvBuffer,TickType_t xTicksToWait);出队出队操作操作队列操作队列操作3、xQueueReceiveFromISR()用于中断服务函数中,从指定的队列中读取消息,读取成功后会将队列中的这个数据删除。函数的原型为:BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue,void*const pvBuffer,BaseType_t*const pxHigherPriorityTaskWoken);出队出队操作操作队列操作队列操作4、xQueuePeekFromISR()用于中断服务函数中,从指定的队列中读取消息,读取成功后并不删除队列中的这个数据。函数的原型为:BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue,void*const pvBuffer);其它队列操作函数其它队列操作函数队列操作队列操作vQueueDelete删除队列并释放内存删除队列并释放内存uxQueueMessagesWaiting查询队列中的消息数量uxQueueMessagesWaitingFromISR查询队列中的消息数量中断版本uxQueueSpacesAvailable查询队列中空闲空间数xQueueReset将队列重置为原始的空状态vQueueAddToRegistry为队列分配名称并添加到队列注册表pcQueueGetName通过队列句柄查询队列名称vQueueUnregisterQueue从队列注册表中删除队列xQueueIsQueueEmptyFromISR中断服务函数中查询队列是否为空xQueueIsQueueFullFromISR中断服务函数中查询队列是否为满三、用队列实现串口守护任务用队列实现串口守护任务FreeRTOS队列与消息传递队列与消息传递守护任务守护任务用队列实现串口守护任务用队列实现串口守护任务守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源其它任务要访问该资源只能间接地通过守护任务提供的服务。守护任务提供了一种干净利落的方法来实现互斥功能,也不用担心会发生优先级反转和死锁。串口守护任务示例串口守护任务示例用队列实现串口守护任务用队列实现串口守护任务本示例对例子“延时函数使用示例”进行改写,将原来二个任务通过临界段代码保护实现串口输出改写成通过串口守护任务输出。本示例通过一个函数appStartTask(),创建3个相同优先级的FreeRTOS任务,均运行于优先级3,抢占式调度和时间片调度开启。任务1的任务函数为Led0Task(),任务1的执行总节拍数通过队列传给守护任务打印。任务2的任务函数是Led1Task(),将任务2的执行总节拍数通过队列传给守护任务打印。任务3是串口输出守护任务,任务函数是printTask(),任何时候只有该守护任务能访问串口。