CH579M开发笔记13——超时判断+状态机
专栏目录:CH579M开发笔记——目录
功能概述
本文主要介绍CH579M进行串口数据收发时采用的超时判断+状态机方法,用该方法处理不定长的串口数据接收非常方便。
该方法笔者最开始是在“正点原子”的STM32单片机开发板示例代码看到的,读者阅读理解后,也可以用于其他平台的单片机串口数据的处理。
代码整体流程图↓↓↓

代码讲解
接下来,我们结合流程图来学习一下代码思路。
- 外设初始化,包括GPIO、串口、定时器等外设,此后程序将进入串口接收待机状态。
查看代码
GPIOA_SetBits(GPIO_Pin_9); GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); UART1_DefInit(); printf("Realiot UART test\r\n"); ///////////////////////////////////////////////////////////////////////// GPIOA_SetBits(GPIO_Pin_6); GPIOA_ModeCfg(GPIO_Pin_6, GPIO_ModeOut_PP_5mA); GPIOB_ResetBits(GPIO_Pin_3 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_9); GPIOB_ModeCfg(GPIO_Pin_3 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_9, GPIO_ModeOut_PP_5mA); timer0_init(1); uart3_init(115200); UART3_SendString("uart3_rx_buf\r\n", 14); delay_ms(10); GPIOA_ResetBits(GPIO_Pin_6); - 当有串口数据接收到时
- uart_sta的值如果是0,则说明串口数据首次收到,将uart_sta的值设为0x8000。Uart_sta不仅是串口数据接收的标志位,也是接收到串口数据个数的计数器。
- uart_sta的值如果不是0,则说明串口数据不是首次收到,此时将uart_sta++进行加一操作,表示收到的数据加1
查看代码
void UART3_IRQHandler(void) { u8 rev = 0; switch (UART3_GetITFlag()) { case UART_II_LINE_STAT: // 线路状态错误 { UART3_GetLinSTA(); } break; case UART_II_RECV_RDY: // 数据达到设置触发点 { rev = UART3_RecvByte(); if (uart3_rx_sta == 0) { //首次收到数据 uart3_rx_sta |= 0x8000; } if ((uart3_rx_sta & 0xFF) < uart3_rx_max) { //将收到的数据写入数组中 uart3_rx_buf[uart3_rx_sta & 0xFF] = rev; uart3_rx_sta++; } GPIOB_InverseBits(GPIO_Pin_3); uart3_rx_tcnt = 0; } break; case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成 { } break; case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送 break; case UART_II_MODEM_CHG: // 只支持串口0 break; default: break; } }
- 此时因为有数据收到后,uart_sta标志位已经不是了,则定时器中每次定时器中断触发后都将time_cnt加一。
- 当time_cnt超过一定数值后,则认为数据接收超时了,即串口数据已经完成接收。我们可以在主函数中对串口数据进行处理,处理结束后将uart_sta标志位复位。
- 如果在time_cnt超过一定数值之前,又有新的串口数据收到,则time_cnt的数值将被清零,重新开始计数。
查看代码
void TMR0_IRQHandler(void) // TMR0 定时中断 { if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) { TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志 } if ((++timer0_cnt) > 999) { timer0_cnt = 0; cycle_1000ms = 1; } if (timer0_cnt % 99 == 0) { cycle_100ms = 1; } if (timer0_cnt % 499 == 0) { cycle_500ms = 1; } if (uart3_rx_sta & 0x8000) { //判断是否是串口接收状态 if (uart3_rx_tcnt++ > 20) { //判断是否接收超时 uart3_rx_tcnt = 0; uart3_rx_sta &= 0x3FFF; uart3_rx_sta |= 0x4000; } } }
结合uart_sta数值的示例
我们再次结合uart_sta的数值的大致描述一下串口数据的接收流程,以帮助理解这一方法。
- 当 uart_sta==0X0000 待机,此时没有串口数据接收
- 当 uart_sta==0X8000 开始接收串口数据了
- 当 uart_sta&0X8000!=0 处于正在接收串口数据的状态
- 当 uart_sta&0X4000!=0 串口数据已经接收完成了,并且标记了串口数据的个数
- 当 uart_sta==0X0000 计数值复位,开始处理数据并准备下一次接收

浙公网安备 33010602011771号