STM32的CubeMX关于串口中断接收
C语言
作为刚工作不久的小白,刚接触STM32的HAL库,工作中使用到了,就记录下自己遇到的问题,希望看到的大佬多多指教。
1、关于串口的初始化函数:
MX_USART2_UART_Init()---波特率、奇偶校验等配置
HAL_UART_Init()---会将 huart->RxState = HAL_UART_STATE_READY;
HAL_UART_MspInit()---GPIO,中断优先级等配置
2、当需要使用中断接收时需要调用
HAL_UART_Receive_IT()---配置接收的缓冲区指针,数量,huart->RxState = HAL_UART_STATE_BUSY_RX;,最后使能相应中断
3、当中断发生时,执行
HAL_UART_IRQHandler()--判断中断的类型,在此处我用到的是非空中断,那么会继续调用UART_Receive_IT(huart);
这个函数会首先判断串口的接收状态huart->RxState == HAL_UART_STATE_BUSY_RX,若果为真就进行数据的保存,进 如 果达到规定的传输数量就会关闭中断,改变huart->RxState = HAL_UART_STATE_READY;然后执行HAL_UART_RxCpltCallback();如果不为真,就清除接收中断标志。
4、HAL_UART_RxCpltCallback()这个函数里尽可能的少些代码否则影响效率,如果想再次开启中断,可以在这里调用 HAL_UART_Receive_IT(),进行再次接收
下面说说我遇到的问题:
初始化串口完毕后,调用一次HAL_UART_Receive_IT(&huart2,uxComDMA.ucRxBuf,ONE_BYTE),进行一个字节的中断接收,然后在HAL_UART_RxCpltCallback()函数里,进行帧头的校验和传输数量的计算,然后继续开启。代码如下
//如果计算的数量大于规定的数量,说明传输出错。丢弃,判定上位机发送是否错误
if(usRecLength > DMA_BUF_MAX)
{
uxComDMA.ucRxBuf[eMsg_DTH] = APP_NULL;
uxComDMA.ucRxBuf[eMsg_DTL] = APP_NULL;
uxComDMA.usRxLen = APP_NULL;
PTCL_Dbg("计算数量大于规定数量");
}
//接收的数量大于等于计算的数量
if(uxComDMA.usRxLen >= usRecLength)
{
uxComDMA.uxReceiveFlag = eAppTrue;//标记接收完成。---此时不再调用HAL_UART_Receive_IT()
}
else//继续接受下一个数据
{
HAL_UART_Receive_IT(&huart2, uxComDMA.ucRxBuf+uxComDMA.usRxLen,ONE_BYTE);
}
当正确接收一帧数据后,便不再开启,直到这一阵数据处理完,主程序再次调用HAL_UART_Receive_IT()进行下一轮的接收。
那么问题来了:规定的协议是8个字节,在正确接收到8个字节后便不再开启中断接收,主函数执行数据帧的处理完毕后才会开启。但是如果上位机一次一共发送了10个字节,前8个字节是正确的一帧,后面2个无用。当下位机接收到8个字节便关闭了中断,处理完后再次开启。然后上位机再发来数据,发现下位机再也不能执行HAL_UART_RxCpltCallback(),协议就报废了。
调试后发现,后来接收数据时虽然可以进入中断并且执行了UART_Receive_IT();但是huart->RxState 的值不是HAL_UART_STATE_BUSY_RX导致不能继续执行传输完成回调。疑问是,最后一次开启中断接收时调用HAL_UART_Receive_IT()函数确实将 huart->RxState = HAL_UART_STATE_BUSY_RX;
PTCL_Dbg("初始化接收的状态%d",HAL_UART_Receive_IT(&huart2,uxComDMA.ucRxBuf,ONE_BYTE));//串口2的接收中断
函数返回值为HAL_OK
PTCL_Dbg("串口的接收状态%#x\r\n",huart2.RxState);----确实不等于HAL_UART_STATE_BUSY_RX,而是等于 HAL_UART_STATE_READY
// huart2.RxState = HAL_UART_STATE_BUSY_RX; ----加上这句话,可以解决问题
这是为什呢?
解决上述问题:
关于上述问题的总结:后两个字节传输时,已经关闭了中断,但是硬件将ORE位(溢出标志,看数据手册)置一和RXNE位置一。当调用HAL_UART_Receive_IT()函数时,会同时使能EIE、PEIE、RXNEIE三个中断。第一次我手动将RXNE位清除,但是没有清除ORE位,造成调用就会立即产生中断(溢出中断)。当执行HAL_UART_IRQHandler()函数时:
关于HAL库,更多的是考虑到安全性和兼容性所以代码量比较大,一开始使用不会像我们使用寄存器那么随意,所以必须深入看源码,才能更好的使用。