热度 23
2013-11-28 10:20
2818 次阅读|
5 个评论
现在用有限状态机的思想来写段程序。 硬件平台: STM32F103 软件平台: Keil uv4 说明:这段程序中用在 STM32 的 USART 串口中断里面,接收来自上位 PC 的一帧的数据,完成后向 PC 端做出应答,表示接收完成。 先把状态转移图贴上吧。这是手绘的,因为我的 visio 打开老有问题,只好手画了一个。简单说一下,上位发送给下位的一帧数据长度不定,帧头用 0x55 开始,数据帧的第二个字节为数据帧的长度,第三个字节开始后面是数据。要说明一下,第二字节的长度,是指后面从第三个字节开始跟的数据的长度,也就是说,整个数据帧的长度,就是第二个字节的内容 +2. 状态的切换是这样的,先是在“ WaitState ”,等待数据,当收到 0x55 后,跳到“ ReadyState ”,接收帧长度后就直接跳到“ BusyState ”,这个状态会把整个帧的数据都接收完,完成后,跳到“ ACKState ”应答状态,向上位 PC 应答,而后跳回“ WaitState ”。 /***********************************************************************/ enum {WaitState = 0, ReadyState, BusyState, ACKState} CommState;// 状态 u8 Rx_DataBuf = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};// 接收数据缓存 u8 ACKMessage = {0xAA,0x55};// 应答帧 u8 CommCnt,CommDataLen;// 接收计数和表示数据长度的变量 void USART1_IRQHandler(void)// 串口中断服务程序 { if((USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) == SET) { USART_ClearITPendingBit(USART1, USART_IT_RXNE); switch(CommState) // 状态机 { case WaitState:// 等待状态 { Rx_DataBuf = USART_ReceiveData(USART1); if(Rx_DataBuf == 0x55) { CommCnt++; CommState = ReadyState;// 如果是 0x55 ,状态切换 } break; } case ReadyState:// 准备状态,用来确定帧长度 { Rx_DataBuf = USART_ReceiveData(USART1); CommDataLen = Rx_DataBuf ; CommCnt++; CommState = BusyState;// 切换到下一状态 break; } case BusyState:// 忙状态,接收整个帧的数据 { Rx_DataBuf = USART_ReceiveData(USART1); CommCnt++; if(CommCnt=(CommDataLen + 2)) { CommCnt = 0; CommState = ACKState;// 接收完成,切换到下一状态 } break; } case ACKState: { USART1_Send(ACKMessage); CommState = WaitState;// 应答上位,跳回等待状态 } default:break; } } } /****************************************************************************/ 关于程序要做几点说明,一是这段程序是可用的,已经用在实际的项目里面,但完整的工程是不能分享给大家的,因为公司项目,只能分享这一部分用到 FSM 的部分;二是上面的 CommState 在初始化程序中已经初始化为 WaitState ,以及变量 CommCnt 也被初始化为 0 ;三是这段程序是最初用来测试用的,后面的加上了校验以及出错处理的机制,其实也就是再添加了几个状态,让控制逻辑上更严谨了,这个大家可以自己加上试试。 希望和大家分享的这点东西对您有帮助。