最近开始使用ST的hal库,这个库相较于之前的标准库,优缺点兼具吧,hal库封装了更多底层的细节,我们可以很轻易的实现我们需要的功能,但是由于封装了太多的细节,导致一旦出问题,你就很难发现问题,内部调用的复杂让你觉得懵逼。
(一)hal库接收中断的分析
这几天在使用hal库的USART,其中用到的是接收中断,官方推荐的使用接收中断的方式是:在初始化函数上面先开启接收中断(这里就不介绍串口的配置,网上一大推,我就不给世界增加无谓的存储量了),开启的函数如下:
HAL_UART_Receive_IT(&huart2,(uint8_t*)aRxBuffer, 1);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
接着直接调用总的回调函数就可以了(这个函数的名称是定义好的),的:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART2)//判断,如果是串口2
{
//在这里写入自己要实现的代码
}
}
其实使用回调函数的原理大概是这样的:MCU接收到数据产生中断,进入中断函数:
//串口中断服务程序
void USART1_IRQHandler(void)
{
u32 timeout=0;
HAL_UART_IRQHandler(&UART1_Handler); //调用HAL库中断处理公用函数
//省略部分代码
/*
代码
*/
}
也就是中断进入了HAL_UART_IRQHandler(&UART1_Handler);这个函数,这个函数是一个总的中断处理函数,也就是很多串口的中断处理最后都汇集到这个地方来处理。其实体如下:
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(&huart2, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE) != RESET))
{
/*
处理代码
*/
/* Clear RXNE interrupt flag */
__HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST); //清除接收数据非空中断标志
}
}
(2)一进入中断MCU就死机
这个问题是由于我在中断处理了大量的任务导致的死机,虽然我之前同样在别的芯片上这样处理而没有出现问题,不过以前用的芯片比我现在用的这款强大太多了,还是那句老话:不要在中断干太多的任务。你可以在中断完成一些标志,或者处理一下接收的数据(可以转存到别的数据,但记住不要用hal库的函数,卡死不负责)然后在回到主函数处理。比如:
void USART2_IRQHandler(void)
{
/* UART in mode Receiver ---------------------------------------------------*/
if((__HAL_UART_GET_IT(&huart2, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE) != RESET))
{
flag_text=1; //中断标志
/* Clear RXNE interrupt flag */
__HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST); //清除接收数据非空中断标志
}
}