最近开始使用ST的hal库这个库相较于之前的标准库优缺点兼具吧hal库封装了更多底层的细节我们可以很轻易的实现我们需要的功能但是由于封装了太多的细节导致一旦出问题你就很难发现问题内部调用的复杂让你觉得懵逼。
一hal库接收中断的分析
这几天在使用hal库的USART其中用到的是接收中断官方推荐的使用接收中断的方式是在初始化函数上面先开启接收中断这里就不介绍串口的配置网上一大推我就不给世界增加无谓的存储量了开启的函数如下
HAL_UART_Receive_IT(//该函数会开启接收中断标志位UART_IT_RXNE并且设置接收缓冲以及接收缓冲接收最大数据量
接着直接调用总的回调函数就可以了这个函数的名称是定义好的的
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart->InstanceUSART2)//判断如果是串口2{//在这里写入自己要实现的代码}}
其实使用回调函数的原理大概是这样的MCU接收到数据产生中断进入中断函数
//串口中断服务程序void USART1_IRQHandler(void) { u32 timeout0;HAL_UART_IRQHandler(//调用HAL库中断处理公用函数//省略部分代码/*代码*/}
也就是中断进入了HAL_UART_IRQHandler(这个函数这个函数是一个总的中断处理函数也就是很多串口的中断处理最后都汇集到这个地方来处理。其实体如下
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart){/*省略一部分代码*/UART_Receive_IT(huart);/*省略一部分代码*/}
而UART_Receive_IT(huart);的实现如下
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart){/*省略一部分代码*/HAL_UART_RxCpltCallback(huart);/*省略一部分代码*/}
也就是说最后会调用到 HAL_UART_RxCpltCallback(huart);我们在这个函数内部做自己的需求就好了。
二 为了效率出了问题
由上面的分析我们可以知道hal库的中断接收虽然很方便但是是非常没有效率的兜兜转转绕了一个大弯才能处理中断接收的数据。尤其是我使用的是STM32F0的芯片频率只有48M不比那些动不动就上百兆的芯片这样的中断处理显然不能接受。
所以借鉴于标准库我想直接在串口中断函数void USART2_IRQHandler(void)上直接处理函数而不用在转一个圈跑到回调函数 HAL_UART_RxCpltCallback(huart)上处理。
然而一改问题就来了一共遇到过两个问题。
1一进中断就出不来
由于不知道之前hal库在中断处理做了什么手脚所以自己也忘了判断和清除中断标志加上下面几句话就好了。
void USART2_IRQHandler(void){/* UART in mode Receiver ---------------------------------------------------*/if((__HAL_UART_GET_IT( RESET) RESET)){/*处理代码*//* Clear RXNE interrupt flag */ __HAL_UART_SEND_REQ( //清除接收数据非空中断标志}}
2一进入中断MCU就死机
这个问题是由于我在中断处理了大量的任务导致的死机虽然我之前同样在别的芯片上这样处理而没有出现问题不过以前用的芯片比我现在用的这款强大太多了还是那句老话不要在中断干太多的任务。你可以在中断完成一些标志或者处理一下接收的数据可以转存到别的数据但记住不要用hal库的函数卡死不负责然后在回到主函数处理。比如
void USART2_IRQHandler(void){/* UART in mode Receiver ---------------------------------------------------*/if((__HAL_UART_GET_IT( RESET) RESET)){flag_text1; //中断标志RxBuif huart2.Instance->RDR; //将接收到的数据保存在全局变量/* Clear RXNE interrupt flag */ __HAL_UART_SEND_REQ( //清除接收数据非空中断标志}}