完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32用CubeMx生成的HAL库效率很低,利用HAL自带的串口中断在接收大量数据时很容易出现数据丢失。一般来说,串口所接受的数据长度可能是不固定的。然而在一串数据的连续接收中,串口接收中断内实现的程序应尽可能短小,避免因打断接收过程而产生数据丢失。本文介绍自己写一个轻量的串口接收中断,使用空闲中断实现效率的大幅提升,并且避免数据丢失。
原理 STM32 的串口中断标记中有
发送端每次都发送一串数据,发送这一串数据的各字符之间没有空闲时间,而每串数据结束到接收到下一串数据是有一定空闲时间的。因此,接收端只有在接收完一串数据之后才能检测到空闲,从而触发空闲中断。该方法直接利用数据串之间的空闲来识别数据串的尾部,而非使用如’n’等符号表示数据结尾,也将提高处理的效率。实现过程 这里是基于CubeMx生成的HAL库代码而改写。 在串口初始化中使能上述中断标记位 __HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE); __HAL_UART_ENABLE_IT(uartHandle,UART_IT_RXNE); 具体代码: void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ __HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE); __HAL_UART_ENABLE_IT(uartHandle,UART_IT_RXNE); /* USER CODE END USART1_MspInit 1 */ } } 改写串口中断函数 在stm32f4xx_it.c里的中断函数USART1_IRQHandler()原本是调用HAL库的HAL_UART_IRQHandler() 函数,这里把这个调用注释掉。 写检查UART_FLAG_RXNE 并存储接收到的字符的代码: if(__HAL_UART_GET_FLAG(&hirda3, UART_FLAG_RXNE) != RESET) { uint8_t ch=(uint16_t) READ_REG(huart1.Instance->DR); *(pBuff++)=ch; ctn++; __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE); } 写检查UART_FLAG_IDLE 并触发回调函数的代码: if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) { UART1_IDLECallBack(UART1_RxBuff,ctn); ctn=0; pBuff=UART1_RxBuff; __HAL_UART_CLEAR_IDLEFLAG(&huart1); } 完整代码如下: extern void UART1_IDLECallBack(uint8_t *buff,uint8_t size); uint8_t UART1_RxBuff[50]; void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ static uint8_t* pBuff=UART1_RxBuff; static uint8_t ctn=0; if(__HAL_UART_GET_FLAG(&hirda3, UART_FLAG_RXNE) != RESET) { uint8_t ch=(uint16_t) READ_REG(huart1.Instance->DR); *(pBuff++)=ch; ctn++; __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE); } if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) { UART1_IDLECallBack(UART1_RxBuff,ctn); ctn=0; pBuff=UART1_RxBuff; __HAL_UART_CLEAR_IDLEFLAG(&huart1); } /* USER CODE END USART1_IRQn 0 */ //HAL_IRDA_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ } 写回调函数 最后只要在main.c中重定义UART1_IDLECallBack()函数即可。 void IRDA3_IDLECallBack(uint8_t *buff,uint8_t size) { HAL_UART_Transmit(&huart1, buff, size, 0xFFFF); } 上述回调函数内容根据实际情况编写,这里提供的例程是听过串口将受到的一整串数据全部返回。结束语 简化单个字符接收后的处理过程,即只将字符存入缓存数组,只当整串数据接受完才调用回调函数执行对该串数据的处理。该方法大大提高了串口接收的效率,避免了数据丢失。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1750 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1608 浏览 1 评论
1049 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
721 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1665 浏览 2 评论
1924浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
709浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
559浏览 3评论
583浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
544浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 09:47 , Processed in 0.768855 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号