完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
作为STM32最常用的外设之一,串口广泛应用于单片机与外部设备之间的通信。常见的串口轮训发送+接收中断虽然能够应付一般的项目,但在处理串口的数据时单片机的运行压力较大。使用DMA辅助处理串口的数据,能够大幅缓解单片机的运行压力,提高串口数据的处理能力。
使用CubeMx配置串口+DMA+FreeRTOS,以下内容仅展示了主要涉及到的串口和DMA的配置,操作系统的配置网上教程很多不多说(FreeRTOS的相关接口使用的是CMSIS_V1版版本),以串口3为例: USART3基础配置: 打开USART3中断: 配置串口的DMA相关通道: 配置FreeRTOS时创建一个串口数据处理任务USART3_DataProcessTask,用于串口数据的处理,一般这个任务就是用来跑协议的。串口数据的处理过程类似于前后台的关系,空闲中断作为后台负责接收数据,一旦接收到数据后通过消息队列或邮箱将数据发送至前台USART3_DataProcessTask中处理。 FreeRTOS本来不支持邮箱的,但是在cmsis_os.c中可以找到邮箱(osMail)的相关接口,这个应该是arm或者st自己封装的,实际上还是通过消息队列来实现的。邮箱的使用参照了官方BSP里的FreeRTOS下的osMail相关例程。 打开freertos.c文件,首先定义邮箱的大小、数据结构、邮箱ID,如下: /* USER CODE BEGIN Variables */ #define MAIL_SIZE (uint32_t) 4 typedef struct { uint16_t DataLength; uint8_t *DataReceive; } Amail_TypeDef; osMailQId USART3_MailId; /* USER CODE END Variables */ 在MX_FREERTOS_Init()中创建刚才定义的邮箱: osMailQDef(Usart3MailId, MAIL_SIZE, Amail_TypeDef); /* Define mail queue */ USART3_MailId = osMailCreate(osMailQ(Usart3MailId), NULL); /* create mail queue */ 在usart.c中定义定义一个相同的邮箱数据结构,以及一个USART3的数据结构,如下: /* USER CODE BEGIN 0 */ #define USART3_DATA_SIZE 256 typedef struct { uint16_t DataLength; uint8_t *DataReceive; } Amail_TypeDef; typedef struct { uint16_t DataLength; uint8_t RxBuffer[USART3_DATA_SIZE]; }USART_TYPE; static USART_TYPE Usart3; extern osMailQId USART3_MailId; /* USER CODE END 0 */ 可以看到,串口的数据结构在定义时直接定义了一个数组,已经为串口接收的数据分配了缓存;而邮箱中定义的是一个指针,所以邮箱在实际发送数据时应该发送的是指针,通过指针访问串口接收的数据。 CubeMx生成的代码没有发现有空闲中断的回调函数,所以就自己定义一个: /* USER CODE BEGIN 1 */ void USER_USART3_IdleCallback(void) { Amail_TypeDef *USART3_TxMail; BaseType_t xHigherPriorityTaskWoken; if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE) != RESET) { __HAL_UART_CLEAR_IDLEFLAG(&huart3); HAL_UART_DMAStop(&huart3); USART3_TxMail = osMailAlloc(USART3_MailId, 0); //为邮箱申请内存 USART3_TxMail->DataLength = USART3_DATA_SIZE- __HAL_DMA_GET_COUNTER(&hdma_usart3_rx); //获取接收数据长度 HAL_UART_Receive_DMA(&huart3,Usart3.RxBuffer,USART3_DATA_SIZE); //获取DMA中缓存的串口数据 USART3_TxMail->DataReceive = Usart3.RxBuffer; //传递缓存串口数据的指针 osMailPut(USART3_MailId, USART3_TxMail); //通过邮箱发送串口数据信息 } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart ) { if(huart == &huart3) { ; //发送完成中断 } } void BSP_USART_Init(void) { __HAL_UART_ENABLE_IT(&huart3,UART_IT_TC); __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE); HAL_UART_Receive_DMA(&huart3,Usart3.RxBuffer,USART3_DATA_SIZE); }; /* USER CODE END 1 */ 触发空闲中断后邮箱发送数据的流程为:先关闭串口的DMA通道->为邮箱申请内存(因为从刚才定义邮箱到创建邮箱均未为邮箱申请内存)->获取串口接收的数据长度->将长度信息写入邮箱->获取DMA中缓存的串口数据->将缓存串口数据的地址(指针)写入邮箱->通过邮箱发送串口相关的数据信息,最后将USER_USART3_IdleCallback()放到串口3的USART3_IRQHandler中就可以了。别忘了串口初始化:开启发送完成中断、空闲中断、分配串口DMA缓存。空闲中断可有可无,一般RS485通讯中需要用到,数据发送完毕后转为接收模式等。 后台已经将数据发送过来,剩下就是前台处理数据了,在USART3_DataProcessTask()任务中处理邮箱数据: /* USER CODE END USART3_DataProcessTask */ void USART3_DataProcessTask(void const * argument) { /* USER CODE BEGIN USART3_DataProcessTask */ osEvent USART3_Event; Amail_TypeDef *USART3_RxMail; static uint8_t *RxBuff; static uint8_t RxLength = 0; RxBuff = pvPortMalloc(256); /* Infinite loop */ for(;;) { USART3_Event = osMailGet(USART3_MailId, 0); //等待邮箱发送数据 if(USART3_Event.status == osEventMail) { USART3_RxMail = USART3_Event.value.p; //获取邮箱中的数据 RxLength = USART3_RxMail->DataLength; RxBuff = USART3_RxMail->DataReceive; osMailFree(USART3_MailId, USART3_RxMail); //释放在串口空闲中断中申请的邮箱内存 printf("数据长度:%drn",RxLength); for(uint8_t i=0;i printf("%xrn",RxBuff); } } osDelay(1); } /* USER CODE END USART3_DataProcessTask */ } 在USART3_DataProcessTask()中等待邮箱数据的传入,如果有数据传入打印相关数据信息。别忘了要释放邮箱的内存,否则几次中断过后内存溢出程序卡死。 DMA发送就简单了,简单封装一下就可以拿来用: void BSP_USART3_SendData(uint8_t *TxBuff,uint16_t BuffLen) { __HAL_DMA_CLEAR_FLAG(&hdma_usart3_tx,DMA_FLAG_TC2); HAL_UART_Transmit_DMA(&huart3,TxBuff,BuffLen); } 上面的串口DMA收发是带操作系统的,如果不带操作系统就省事儿多了,定义一个全局数据缓存串口数据需要用的时候直接拿来用就可以了。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 12:48 , Processed in 0.739411 second(s), Total 46, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号