欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32的CubeMX关于串口中断接收

程序员文章站 2024-02-25 18:22:15
...
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()函数时:      

STM32的CubeMX关于串口中断接收    STM32的CubeMX关于串口中断接收

STM32的CubeMX关于串口中断接收

STM32的CubeMX关于串口中断接收

STM32的CubeMX关于串口中断接收

关于HAL库,更多的是考虑到安全性和兼容性所以代码量比较大,一开始使用不会像我们使用寄存器那么随意,所以必须深入看源码,才能更好的使用。