| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 嵌入式 -> STM32MP157资源扩展板驱动移植篇11:FreeRTOS队列 -> 正文阅读 |
|
[嵌入式]STM32MP157资源扩展板驱动移植篇11:FreeRTOS队列 |
写在前面: 本文章为《STM32MP157资源扩展板驱动移植篇》系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板)。资源扩展板是FS-MP1A开发板的扩展模块,主要包含了10余种主流传感器、执行器件、总线控制器件,非常方便项目扩展用。可拓展开发智慧家庭、智能医疗、智能安防、工业控制、图像识别、环境检测等方向的10个左右综合项目,华清远见开发板也将配套提供所有项目的说明文档、实验源码、应用程序等资料。 针对FS-MP1A开发板,除了资源扩展板驱动移植篇外,还包括其他多系列教程,包括Cortex-A7开发篇、Cortex-M4开发篇、FreeRTOS篇、Linux应用开发篇、Linux系统移植篇、Linux驱动开发篇、硬件设计篇、人工智能机器视觉篇、Qt应用编程篇、Qt综合项目实战篇等。欢迎关注,更多stm32mp157开发教程及视频,可加技术交流Q群459754978,感谢关注。 FS-MP1A开发板详情介绍:https://item.taobao.com/item.htm?id=622457259672
? 1.2资源扩展板可开发项目 ? 2.FreeRTOS队列 2.1队列简介 队列可以用于任务与任务、任务与中断之间的通信,在任务与任务、任务与中断之间传递数据,队列中可以存储有限的、大小固定的数据项目。 一般情况下,队列采用先进先出(FIFO)的存储机制,也就是说先发送进队列的数据先被提取,当然也可以使用先进后出(LIFO)的存储缓冲,FreeRTOS中提供了两种存储缓冲机制。 队列不属于某个特定的任务,对于所有任务都可以向任务中发送数据,也可以从任务中提取数据。队列函数 2.2.1?创建队列创建事件标志组的函数有两个,分别如下: xQueueCreate(),此函数用于动态创建队列,所需要的内存通过动态内存管理方法分配,此函数是个宏,真正完成队列创建的函数时xQueueGenericCreate()。函数原型如下: QueueHandle_t ?xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize) 参数: uxQueueLength: ?要创建的队列的队列长度,这里是队列的项目数。 uxItemSize: ?????队列中每个项目(消息)的长度,单位为字节。 返回值: NULL:?队列创建失败。 其他值:创建成功的队列返回的队列句柄。 xQueueCreate Static(),此函数为静态方法创建队列,所需要的内存通过用户自行分配,此函数也是个宏,最终调用的是函数xQueueGenericCreateStatic()。其函数原型如下: QueueHandle_t xQueueCreateStatic(UBaseType_t ?uxQueueLength, ??????????????????????????????UBaseType_t ?uxItemSize, ??????????????????????????????uint8_t* ?pucQueueStorageBuffer, ??????????????????????????????StaticQueue_t* ?pxQueueBuffer) 参数: uxQueueLength: ????要创建的队列的队列长度,这里是队列的项目数。 uxItemSize: ????????队列中每个项目(消息)的长度,单位为字节 pucQueueStorage: ????指向队列项目的存储区,也就是消息的存储区,这个存储区需要 用户自行分配。此参数必须指向一个 uint8_t 类型的数组。这个 存储区要大于等于(uxQueueLength * uxItemsSize)字节。 pxQueueBuffer: ??????此参数指向一个 StaticQueue_t 类型的变量,用来保存队列结构体。 返回值: NULL:?队列创建失败。 其他值:创建成功的队列返回的队列句柄。 2.2.2?向队列发送消息队列创建好以后便可以向其中发送消息,FreeRTOS提供的向队列中发送消息的API函数有8个,分别如下: 函数xQueueSend()、xQueueSendToBcck()和xQueueSendToFront() 此三个函数都用于向队列中发送消息,函数本质都是宏,其中xQueueSend()和xQueueSendToBcck()都是将消息添加到队列的后面,xQueueSendToFront()是将消息添加到队列的前面,这三个函数最终调用的同一个函数:xQueueGenericSend(),都只能用于任务函数中,其函数原型分别如下: ??BaseType_t ?xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait) ??BaseType_t ?xQueueSendToBack(QueueHandle_t xQueue, const void* ?pvItemToQueue, TickType_t ?xTicksToWait) ??BaseType_t ?xQueueSendToFront(QueueHandle_t ?xQueue, const void * ?pvItemToQueue, TickType_t xTicksToWait) 参数: xQueue: ?????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后会 返回此队列的队列句柄。 pvItemToQueue: ??????指向要发送的消息,发送时候会将这个消息拷贝到队列中。 xTicksToWait: ????????阻塞时间,此参数指示当队列满的时候任务进入阻塞态等待队 列空闲的最大时间。 返回值: pdPASS:??????????????向队列发送消息成功。 ErrQUEUE_FULL: ????队列已满,消息发送失败 ????函数xQueueOverwrite(),此函数同样用于向队列中发送数据,但当队列满了以后会覆写掉旧的数据,不管此数据有没有被其他任务或中断取走,同样此函数也是宏,最终调用的也是函数xQueueGenericSend(),其函数原型如下: BaseType_t ?xQueueOverwrite( QueueHandle_t ?xQueue, const void * ?pvItemToQueue) 参数: xQueue: ?????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后会 返回此队列的队列句柄。 pvItemToQueue: ??????指向要发送的消息,发送的时候会将这个消息拷贝到队列中。 返回值: pdPASS: ??向队列发送消息成功,此函数也只会返回 pdPASS!因为此函数执行过程中 不在乎队列满不满,满了的话就覆写掉旧的数据,总之肯定能成功。 函数xQueueGenericSend(),前面所有任务级入队函数最终调用的都是此函数,其函数原型如下: BaseType_t ?xQueueGenericSend (QueueHandle_t ?xQueue, const void * ??pvItemToQueue, TickType_t ?xTicksToWait, const BaseType_t ?xCopyPosition) 参数: xQueue: ?????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后会 返回此队列的队列句柄。 pvItemToQueue: ??????指向要发送的消息,发送的时候会将这个消息拷贝到队列中。 xTicksToWait: ????????阻塞时间。 xCopyPosition: ???????入队方式,总共有三种 ????????????????????????queueSEND_TO_BACK: ?后向入队 queueSEND_TO_FRONT: 前向入队 queueOVERWRITE: ?????覆写入队。 返回值: pdTRUE:??????????????向队列发送消息成功。 errQUEUE_FULL: ?????队列已满,消息发送失败 函数xQueueSendFromISR()、xQueueSendToBcckFromISR ()、 xQueueSendToFrontFromISR () 这三个函数用于中断服务函数中向队列发送消息,分别为之前三个向队列发送消息函数的中断版本,函数本质上也是宏,最终调用的是同一个函数xQueueGenericSendFromISR(),函数原型分别如下: BaseType_t xQueueSendFromISR( QueueHandle_t ?xQueue, const void * ??pvItemToQueue, BaseType_t * ?pxHigherPriorityTaskWoken) BaseType_t xQueueSendToBackFromISR(QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t * ?pxHigherPriorityTaskWoken) ??BaseType_t xQueueSendToFrontFromISR(QueueHandle_t ?xQueue, const void * ?pvItemToQueue, BaseType_t * ?pxHigherPriorityTaskWoken) 参数: xQueue: ?????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后会 返回此队列的队列句柄。 pvItemToQueue: ??????指向要发送的消息,发送的时候会将这个消息拷贝到队列中。 pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换 返回值: pdTRUE:??????????????向队列发送消息成功。 errQUEUE_FULL: ?????队列已满,消息发送失败 函数xQueueOverwriteFromISR(),此函数为xQueueOverwrite()的中断版本,同样此函数也是宏,最终调用的也是函数xQueueGenericSendFromISR(),其函数原型如下: BaseType_t ?xQueueOverwriteFromISR( QueueHandle_t ?xQueue, const void * ?pvItemToQueue, BaseType_t * ?pxHigherPriorityTaskWoken) 参数: xQueue: ?????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后会 返回此队列的队列句柄。 pvItemToQueue: ??????指向要发送的消息,发送的时候会将这个消息拷贝到队列中。 pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换 返回值: pdTRUE:??????????????向队列发送消息成功。 errQUEUE_FULL: ?????队列已满,消息发送失败 函数xQueueGenericSendFromISR(),前面所有中断级入队函数最终调用的都是此函数,此函数也是函数xQueueGenericSend()的中断版本,其函数原型如下: BaseType_t ?xQueueGenericSend FromISR (QueueHandle_t ?xQueue, const void * ?pvItemToQueue, BaseType_t* ?pxHigherPriorityTaskWoken, ????????????????????????????????????????BaseType_t ?xCopyPosition) 参数: xQueue: ???????????????队列句柄,指明要向哪个队列发送数据,创建队列成功以后 会返回此队列的队列句柄。 pvItemToQueue: ?????????指向要发送的消息,发送的时候会将这个消息拷贝到队列中。 pxHigherPriorityTaskWoken: ??????标记退出此函数以后是否进行任务切换。 xCopyPosition: ?????????入队方式,总共有三种 ????????????????????????queueSEND_TO_BACK: ?后向入队 queueSEND_TO_FRONT: 前向入队 queueOVERWRITE: ?????覆写入队。 返回值: pdTRUE:??????????????向队列发送消息成功。 errQUEUE_FULL: ?????队列已满,消息发送失败 2.2.3?从队列读取消息与入队相对应,那么就会有出队,出队就是从队列中获取消息,FreeRTOS中提供的出队API函数分别如下: xQueueReceive(),此函数用于任务中从队列读取一条消息,读取成功以后就会将这条数据删除,此函数是个宏,真正执行的函数为xQueueGenericReceive(),此函数原型如下: BaseType_t ?xQueueReceive(QueueHandle_t ?xQueue, void * ?pvBuffer, TickType_t ?xTicksToWait) 参数: xQueue: ???????队列句柄,指明要读取哪个队列的数据,创建队列成功以后会返回此 队列的队列句柄。 pvBuffer: ??????保存数据的缓冲区,读取队列的过程中会将读取到的数据拷贝到这个 缓冲区中。 ??xTicksToWait: ??阻塞时间,此参数指示当队列空的时候任务进入阻塞态等待队列有数 据的最大时间。 返回值: pdTRUE:???????从队列中读取消息成功。 pdFALSE: ?????从队列中读取消息失败。 ????xQueuePeek(),此函数也用于任务中从队列读取一条消息,但是读取成功以后不会将这条数据删除,此函数也是个宏,真正执行的函数为xQueueGenericReceive(),此函数原型如下: BaseType_t xQueuePeek( QueueHandle_t ?xQueue, void * ?pvBuffer, TickType_t ?xTicksToWait) 参数: xQueue: ???????队列句柄,指明要读取哪个队列的数据,创建队列成功以后会返回此 队列的队列句柄。 pvBuffer: ??????保存数据的缓冲区,读取队列的过程中会将读取到的数据拷贝到这个 缓冲区中。 ??xTicksToWait: ??阻塞时间,此参数指示当队列空的时候任务进入阻塞态等待队列有数 据的最大时间。 返回值: pdTRUE:???????从队列中读取消息成功。 pdFALSE: ?????从队列中读取消息失败。 xQueueReceiveFromISR(),此函数为xQueueReceive()的中断版本,用于在中断服务函数中从队列读取消息,其函数原型如下: BaseType_t xQueueReceiveFromISR(QueueHandle_t ?xQueue, void* ?pvBuffer, BaseType_t * ?pxTaskWoken) 参数: xQueue: ?????????队列句柄,指明要读取哪个队列的数据,创建队列成功以后会返回 此队列的队列句柄。 pvBuffer: ????????保存数据的缓冲区,读取队列的过程中会将读取到的数据拷贝到这 个缓冲区中。 pxTaskWoken: ????标记退出此函数以后是否进行任务切换 返回值: pdTRUE: ?从队列中读取数据成功。 pdFALSE: ?从队列中读取数据失败。 xQueuePeekFromISR (),此函数为xQueuePeek()的中断版本,读取数据成功以后不会将这条数据删除,此函数原型如下: BaseType_t xQueuePeekFromISR( QueueHandle_t ?xQueue, void * ?pvBuffer) 参数: xQueue: ???????队列句柄,指明要读取哪个队列的数据,创建队列成功以后会返回此 队列的队列句柄。 pvBuffer: ??????保存数据的缓冲区,读取队列的过程中会将读取到的数据拷贝到这个 缓冲区中。 返回值: pdTRUE:???????从队列中读取消息成功。 pdFALSE: ?????从队列中读取消息失败。 2.3.1实验设计本次设计通过中断检测三个按键状态,读取到不同键值后发送到队列中,然后在任务中读取队列中的消息,根据不同的指令做出不同的处理。 可参考12.3.2章节进行导入已有工程,工程存放路径【华清远见-FS-MP1A开发资料\02-程序源码\ARM体系结构与接口技术\FreeRTOS\6_MP1A-FreeRTOS-Queue】 任务及其功能如下: StartTask02():?????读取队列中的数据,根据读取到的数据做不同处理。 StartDefaultTask():?读取按键值,并发送到队列中。 2.3.2实验过程与分析首先,根据之前几章内容配置好CubeMX,按照上一节配置“FREERTOS”,完成后生成代码。 在StartDefaultTask() 与StartTask02()中添加代码如下。 void?StartDefaultTask(void?*argument) { ??/* USER CODE BEGIN 5 */ ??/* Infinite loop */ uint8_t?err; ??for(;;) ??{ ??????????if((Key_Queue!=NULL)&&(key)) ?? //消息队列Key_Queue创建成功,并且按键被按下 ??????????{ ??????????????err=xQueueSend(Key_Queue,&key,10); ??????????????if(err==pdPASS) ?? //发送按键值 ??????????????{ ??????????????????printf("\r data transmission success \n"); ??????????????} ????????????? ??????????} ??????????vTaskDelay(10); ??????????????????????????//延时10ms,也就是10个时钟节拍 ??} ??/* USER CODE END 5 */? } void?StartTask02(void?*argument) { ??/* USER CODE BEGIN StartTask02 */ ??/* Infinite loop */ ??for(;;) ??{ ??if(Key_Queue!=NULL) ??????{ ??????if(xQueueReceive(Key_Queue,&key,portMAX_DELAY))//请求消息Key_Queue ??????{ ?? ? ???????????switch(key) ???????????{ ???????????????case?EVENTBIT_1: // ????????????????????LED_1_TOG(); ????????????????????break; ???????????????case?EVENTBIT_2: // ????????????????????LED_2_TOG(); ????????????????????break; ???????????????case?EVENTBIT_3: // ????????????????????LED_3_TOG(); ????????????????????break; ????????????} ???????????key = 0; ???????} ???} ? vTaskDelay(10); ?????//延时10ms,也就是10个时钟节拍 ??} ??/* USER CODE END StartTask02 */ } 另外,首先需要在主函数中调用xQueueCreate ()函数创建消息队列,获得创建成功的队列句柄。 编写按键中断回调函数如下 void?HAL_GPIO_EXTI_Rising_Callback(uint16_t?GPIO_Pin) { switch(GPIO_Pin) { ???case?GPIO_PIN_8: ???????if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_8) == GPIO_PIN_SET) /* read KEY3 PF8 state */ ???? ???key = EVENTBIT_3; ??? ?? break; ???case?GPIO_PIN_7: ???if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_7) == GPIO_PIN_SET) /* read KEY2 PF7 state */ ???key = EVENTBIT_2; ??? break; ???case?GPIO_PIN_9: ???if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_9) == GPIO_PIN_SET) /* read KEY1 PF9 state */ ???key = EVENTBIT_1; ????break; } } ?此时,当按下KEY1键时,LED1电平发生翻转;当按下KEY2键时,LED2电平发生翻转;当按下KEY3键时,LED3电平发生翻转。 硬件平台:华清远见FS-MP1A开发板(STM32MP157) |
|
嵌入式 最新文章 |
基于高精度单片机开发红外测温仪方案 |
89C51单片机与DAC0832 |
基于51单片机宠物自动投料喂食器控制系统仿 |
《痞子衡嵌入式半月刊》 第 68 期 |
多思计组实验实验七 简单模型机实验 |
CSC7720 |
启明智显分享| ESP32学习笔记参考--PWM(脉冲 |
STM32初探 |
STM32 总结 |
【STM32】CubeMX例程四---定时器中断(附工 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 22:26:51- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |