试验三:信号量应用 创建FreeRTOS任务中断和同步(信号量方式)
其实可以这里可以延伸利用信号量来实现串口数据的不定长收发,定长收发使用 “HAL_UART_Receive_IT(&huart2,Rx_Buffer,RxBufferSize);”即可,而不定长的方法在论坛中有网友也举了详细的创建方法(可在论坛中搜索“不定长”),也有修改HAL_UART_Receive_IT 函数的方法实现。 试验设想:这里是利用FreeRTOS信号量机制实现,主要结合不定长数据的接收,加上FreeRTOS信号量的控制,再通过串口数据接收任务中的消息解析操作,可实现简单的人机交互功能。
交互机制的选择: 面对消息队列、事件标志组、 信号量等多种交互机制下,可以参考下表进行任务间的交互。
本实验选择互斥信号量来实现,相关的FreeRTOS 信号量 API 函数如下图:
使用CubeMX配置串口 DMA的内容略过(参考论坛的不定长DMA配置,FreeRTOS的配置见前篇),待工程建立好后,在代码中增加以下的内容:
在main.h中增加定义:
在main.c中增加定义: - extern SemaphoreHandle_t xScanSemaphore; //串口中断处理的任务
- uint8_t ReceiveBuff[RXBUFFERSIZE] = { 0 }; //接收缓冲区
- uint8_t ReceiveInfo[RXBUFFERSIZE]={ 0 }; //接收待识别字符数组
- uint8_t Rx_BuffLen, Rx_InfoLen;
- void vStartLPUart1ScanTask(void const * argument);
- #define Uart_TASK_PRIORITY ( tskIDLE_PRIORITY + 3UL )
复制代码
在main函数中,调整增加部分代码内容: - int main(void){
- HAL_Init();
- SystemClock_Config();
- MX_GPIO_Init();
- MX_DMA_Init();
- MX_LPUART1_UART_Init();
- MX_USB_OTG_FS_PCD_Init();
- MX_NVIC_Init(); //中断初始化中,增加空闲中断的捕获 __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE);
- /* 开启下一次接收 */
- HAL_UART_Receive_DMA(&hlpuart1,(uint8_t*)ReceiveBuff,RXBUFFERSIZE);
- //创建信号量
- xScanSemaphore = xSemaphoreCreateBinary();
- //增加交互任务
- xTaskCreate((TaskFunction_t) vStartLPUart1ScanTask, //任务函数
- "LPUart1S", //任务名称
- 200, //任务栈大小
- NULL, //任务函数参数
- Uart_TASK_PRIORITY, //任务执行等级
- (TaskHandle_t *) NULL); //任务句柄
- //启动任务
- vTaskStartScheduler();
- }
复制代码
创建串口中断任务内容 - void vStartLPUart1ScanTask(void const * argument){
- uint8_t *strp,*strp1;
- configASSERT(xScanSemaphore);
- //获取信号量,等待时间为0,则xSemaphoreTake()在信号量无效时会立刻返回
- xSemaphoreTake(xScanSemaphore, Scan_BLOCK);
- for (;;) {
- //获取信号量,超时时间为portMAX_DELAY值
- xSemaphoreTake(xScanSemaphore, portMAX_DELAY);
- /* 打印接收到的数据长度 */
- printf("rx_len=%d:\n%s \n", Rx_InfoLen,ReceiveInfo);
- //回答Hello
- strp=strstr((char *)ReceiveInfo,(char *)"Hello");
- if (NULL != strp){
- printf("\n Nice to meet you! \n");
- };
- //回答guten tag/ guten morgen/ guten abend / guten nacht
- strp=strstr((char *)ReceiveInfo,(char *)"Guten");
- if (NULL != strp){
- strp1=strstr((char *)ReceiveInfo,(char *)"morgen");
- if (NULL != strp1){
- printf("\n Guten Morgen ! \n");
- }
- strp1=strstr((char *)ReceiveInfo,(char *)"tag");
- if (NULL != strp1){
- printf("\n Guten Tag ! \n");
- }
- strp1=strstr((char *)ReceiveInfo,(char *)"abend");
- if (NULL != strp1){
- printf("\n Guten Abend ! \n");
- }
- strp1=strstr((char *)ReceiveInfo,(char *)"nacht");
- if (NULL != strp1){
- printf("\n Guten Nacht ! \n");
- }
- }
- /* 清空接收到的数据 */
- memset(ReceiveInfo, 0x00, Rx_InfoLen);
- Rx_InfoLen=0;
- </font>
复制代码严格意义上需要词法、语法分析器,这里就不多说,往深的说就就可以实现类似“micropython”的系统了。这里就不离FreeRTOS 信量太远
在stm32l4xx_it.c 文件中设置以下内容 - <font face="新宋体" size="3">extern SemaphoreHandle_t xScanSemaphore;
- extern uint8_t ReceiveInfo[RXBUFFERSIZE];
- extern uint8_t Rx_BuffLen, Rx_InfoLen;
复制代码将CubeMX生成的LPUART1_IRQHandler(void)函数中增加以下内容: - void LPUART1_IRQHandler(void) {
- ………
- uint32_t temp;
- static BaseType_t xHigherPriorityTaskWoken;
- HAL_UART_IRQHandler(&hlpuart1);
- /* 如果是串口1IDLE中断 */
- if (RESET != __HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE)) {
- /* 停止DMA接收 */
- HAL_UART_DMAStop(&hlpuart1);
- /* 获取DMA当前还有多少未填充 */
- temp = __HAL_DMA_GET_COUNTER(&hdma_lpuart_rx);
- /* 清除中断标志 */
- __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
- /* 计算串口接收到的数据个数 */
- Rx_BuffLen = RXBUFFERSIZE - temp;
- Rx_InfoLen = Rx_BuffLen;
- memcpy(ReceiveInfo,ReceiveBuff,Rx_InfoLen);
- memset(ReceiveBuff, 0x00, Rx_BuffLen);
- /* 接收数据长度清零 */
- Rx_BuffLen = 0;
- }
- if (utime_tick >= 200) {
- xSemaphoreGiveFromISR(xScanSemaphore, &xHigherPriorityTaskWoken);
- utime_tick = 0;
- }
- portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
- …………
- }
复制代码
编译项目,下载执行,打开串口工具,分别输入 Hello、Guten morgen、Gutentag、Guten abend、Guten nacht能从串口中得到开发板返回的以下内容:
没有严格的词法、语法分析, 就不能正确识别处理 “ Hello Guten tag" 之类的指令了,当然回复也是错误的。人机交互的内容就可参考状态机、模糊逻辑、人工智能等内容。
在增加这个信号量任务的时候,还可以将LED的任务、按键中断同时执行,通过控制LED的不同闪烁,同步返回不同的状态。 也可以配合音频文件、音频流等方式,发出标准的语音模式。可以将实验更加丰富、更加有趣。
这样基本的基于FreeRTOS的信号量的人机交互就初步完成。 注意,创建多个任务时“FreeRTOSConfig.h”中#define configTOTAL_HEAP_SIZE 的值大小,太小了,某些任务不会被成功创建;
《低功耗MCU运行FreeRTOS》培课程的准备内容(一)
《低功耗MCU运行FreeRTOS》培课程回顾(二)
《低功耗MCU运行FreeRTOS》培训课程(三) Atollic环境实验
《低功耗MCU运行FreeRTOS》培训课程(四) 创建任务
《低功耗MCU运行FreeRTOS》培训课程(六)消息队列的使用
|