项目使用STM8S003单片机,数据发送速率比较慢时,一切正常。当速率快的时候,系统卡死,具体表现为一直运行中断服务程序,无法执行while(1)里面的内容了。
调试记录
开始怀疑是一直在响应某个中断,断点调试后发现是一直在响应UART1接收中断。调试步骤如下:
怀疑是串口中断里做了数据解析工作,导致在解析途中又收到了第二个串口接收中断,然后发生异常。解决办法是在串口接收中断中关闭串口接收中断,数据解析完成后再打开串口接收中断,防止在本次数据解析时发生下一次接收中断。具体代码表现如下:
/**
* @brief UART1 RX Interrupt routine
* @param None
* @retval None
*/
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
uint8_t temp;
temp = UART1_ReceiveData8();
UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE); //关闭串口中断
gh_protocol_parse(temp, &gh_parse); //解析数据
UART1_ClearITPendingBit(UART1_IT_RXNE);
UART1_ITConfig(UART1_IT_RXNE_OR, DISABLE); //打开串口中断
}
测试后发现问题依旧,所以又考虑是不是还有其他中断干扰(工程中还开启了两个定时器中断,中断频率比较高),索性关闭全局中断试试,如下:
/**
* @brief UART1 RX Interrupt routine
* @param None
* @retval None
*/
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
uint8_t temp;
temp = UART1_ReceiveData8();
disableInterrupts(); //关闭全局中断
gh_protocol_parse(temp, &gh_parse); //解析数据
UART1_ClearITPendingBit(UART1_IT_RXNE);
enableInterrupts(); //打开全局中断
}
测试后,问题依旧。
没办法,只能看看发生异常后,串口寄存器的状态,然后再定位异常。如下图所示。
OR_LHE置位,数据手册上如是介绍这位:
所以判断是过载错误没有清除导致中断异常,按照数据手册,每次中断来之前先读SR 然后后再读DR,不管有没有过载错误,都把该位给清掉,代码改成如下:
/**
* @brief UART1 RX Interrupt routine
* @param None
* @retval None
*/
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
uint8_t temp;
temp = UART1->SR;
temp = UART1_ReceiveData8();
gh_protocol_parse(temp, &gh_parse);
UART1_ClearITPendingBit(UART1_IT_RXNE);
}
烧录后,重新测试,发现快速率接收数据也不会出现卡死现象,系统运行正常,至此问题解决。
总结
在日常的开发过程中,我们往往注重的是如何完成特定的需求,没有考虑出现异常情况下的解决办法,如本例中所示,串口通讯时,为了接收实时性而选用中断接收,但是对于接收异常则没有考虑进去。同样的在其他外设的使用中也会犯类似的错误,所以解决途径是只有自己踩坑了,才知道填。将此分享出来是防止其他人踩同样的坑,亦或是正在踩坑的人早点跳出。