完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
问题:
HAL库在大数据量频繁收发时出现串口接收失效。 分析: HAL库对串口中断进行了封装,留给用户的接口只有一个回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //接收中断回调函数 平时在中断函数中写的东西,现在统统写在这个回调函数中。 在使用库函数或寄存器时,我们通常要自己清除中断标志位,且接收中断的使能和失能可以由用户直接操作寄存器控制,而这些都被HAL库进行了封装,呈现在用户面前的只有两个函数: HAL_UART_Receive(&huart2,(uint8_t*)Data_Buf, Data_Length,Timeout)//阻塞式接收,在指定时间内阻塞等待数据到来 HAL_UART_Receive_IT(&huart2,(uint8_t*)Data_Buf,Data_Length);//中断式接收 第一个函数使用频率较低,一般情况下,我们想要复现库函数或寄存器编程时的那种单字节接收中断的方式来处理数据,就可以使用第二个函数,将Data_Length设为1,这样接收到一字节数据就会进入一次回调函数。如下: HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1);//开启串口2接收中断 HAL库之所以把这些封装起来,就是为了大数据量的吞吐(因为可以可以指定数据长度,且清除标志位等操作HAL库都自己做了)。 现在拿它当单字节的接收中断用反而很低效,因为每一字节都要做很多判断再进入回调函数。 并且HAL_UART_Receive_IT这个函数每次使用时都在函数内部对串口中断进行使能。 因为HAL库在串口中断中加入了这样一个机制:在规定字节接收完成后,对中断进行失能。 为了保证能连续接收,我们通常要在回调函数结束时,重新调用该函数使能接收中断用以下一字节的接收,如下: void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ if(huart->Instance==USART2) { UART1_Rx_Buf[UART1_Rx_cnt] = UART2_temp; UART1_Rx_cnt++; HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1);//重新使能接收中断 }}123456789我们进入HAL_UART_Receive_IT()观察一下函数原型 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size){ /* Check that a Rx process is not already ongoing */ if (huart->RxState == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->RxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_PE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); /* Enable the UART Data Register not empty Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); return HAL_OK; } else { return HAL_BUSY; }}可以看到该函数使能中断时,是有可能失败的,如果使能失败,返回值为 HAL_BUSY 这里失败的具体原因我自己研究了一会儿,水平还是不太够,网上有大佬给出了答案(链接在文末)。 大概的问题是: 串口的发送和接收出现冲突,HAL_UART_Transmit是阻塞式调用,阻塞中发生中断后就会出问题。 我模拟大数据量的收发试验了一下。 if(HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1) == HAL_BUSY);//开启串口2接收中断 { printf("Uart2 is BUSY!rn"); } 如果使能串口失败,就提示Uart2 is BUSY!,串口助手界面结果如下: 在数据量过大时,就出现了使能串口中断失败的情况,之后串口接收便失效了,程序其他部分运行正常,串口发送也正常。 解决办法 检测到HAL_UART_Receive_IT()返回HAL_BUSY时就重新使能,注意不要迅速使能,在中断里千万不要这么写: hile(HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1) == HAL_BUSY);1亲测上面的代码要是卡在中断中的话会让程序崩溃,最好是这样: if(HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1) == HAL_BUSY)//开启串口2接收中断{ UART_ERR = 1;}1234然后在循环(或另一个任务中)检测UART_ERR,重新使能: if(UART_ERR){ UART_ERR = 0; printf("rnUart2 is BUSY!-------------------->rn"); while(HAL_UART_Receive_IT(&huart2,(uint8_t*)&UART2_RX_TEMP,1) == HAL_BUSY);//开启串口2接收中断}这种方法只能充当一个看门狗的角色,不能从根本上解决HAL库的串口接收问题。 如果在平时的应用中只是偶尔出现这样的问题,数据也有重发的机制的话,可以用这种方法解决。 我觉得这也不能算是HAL库的BUG,因为这里使能失败是可以读到的,并不是未知的错误,只能说是这样的机制没考虑到普通的小型应用设计的方便性吧。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1786 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1622 浏览 1 评论
1089 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
730 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1680 浏览 2 评论
1942浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
739浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
576浏览 3评论
598浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
560浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-25 13:31 , Processed in 0.664328 second(s), Total 48, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号