
本文编写代码部门C语言复习参考江科大侵删一、状态机1、定义同一时间只能处在某一种固定状态收到外部触发条件后切换到另外一种状态每个状态做固定动作。关键词如下有限状态数量是固定可数的不会无限多。状态必须提前定义无法运行时新增。单一任意时刻只有一个当前状态不能多状态共存。触发必须有事件/条件才会切换状态不会自己乱跳即状态不会自动跳转举例电灯状态1、灯灭2、灯亮触发事件按开关状态流转当前 灯灭 按开关→切换为灯亮当前灯亮 按开关→切换为灯灭2、四大组成要素1状态集合S所有能存在的模式灭亮2输入/事件结合E触发状态转换的信号、条件等按下开关3状态转移规则T当前状态输入 →下一个状态灯灭 按开关→灯亮灯亮 按开关→灯灭4输出/动作A 停留在这个状态要执行的行为亮状态输出“通电发光”灭状态输出“断电”3、两种经典状态机1Moore状态机动作/输出只由当前状态决定和输入无关比如灯只要状态是“亮”就一直发光不管有没有按键输入2Mealy状态机常用动作/输出由当前状态当前输入一起决定比如电梯状态停靠1楼输入按下3楼按钮动作关门上行即同一个状态输入不同动作不一样。4、常见逻辑枚举列举所有状态→定义全局/结构体变量保存当前状态→循环里用switch判断当前状态每个状态写对应的逻辑。这是最基础轮询式状态机也是最通用的。typedef enum{ State_Idle,//空闲 State_Run,//运行 State_Err//故障 }State; State Curr_State State_Idle;//定义全局变量初始化 int main() { while(1) { switch(Curr_State) { case State_Idle: (*此处写空闲时的动作代码* if(触发启动事件) { Curr_State State_Run;//切换状态 } break; case State_Run: (*此处写运行时的动作代码* if(故障信号) { Curr_State State_Err; } if(运行完成 Curr_State State_Idle break; case State_Err: (*此处写故障处理时的动作代码* if(复位按键) { Curr_State State_Idle; } break; } } }5、状态机优势1替代多层if-else逻辑分层清晰易维护2不会出现逻辑卡死分支混乱3自带异常处理分支出错统一跳转到错误状态复位4适配中断、定时器、通信协议6、状态转移表以3段式设备举例当前状态触发事件下一个状态该状态动作IDLE启动信号RUN待机、低功耗RUN完成信号IDLE正常工作RUN故障信号ERROR停止工作ERROR复位信号IDLE报警、清理故障7、注意点1状态是静态模式事件是动态触发信号2状态不会自动跳转必须满足条件才切换3任何时刻只有一个当前状态不存在同时处于两个状态4有限状态机≠无限状态状态必须提前定义好不能动态新增二、串口接收HEX数据包和文本数据包1、HEX数据包1固定包长一整个数据包字节数固定不变。包头0xFF起始标记判断一帧开始包尾0xFE结束标记判断一帧结束有效数据是中间的4个字节。接收流程逐个字节接收抓到字节0xFF开始缓存→持续存入后续字节直到遇到0xFE停止接收→有效数据是中间4个字节2可变长度数据包包长度不固定只靠包头包尾来分割。格式0xFF任意长数据0xFE接收逻辑收到0xFF开始缓存数据一直往后存直到收到0xFE就把这一段当成完整数据包可变包长坑点如果有限数据里刚好包含了0xFF或0xFE解析会错乱。举例0xFF,0x01,0xFE,0x02,0x03,0xFE程序直接把0xFF~0xFE截断成一个包剩下数据就错位了。即数据和包头包尾重复导致分包出错。解决方法①限制有限数据的取值范围不让数据出现0xFF、0xFE只使用剩下的字节数据从根源避免冲突②改用固定长度数据包只要每个数据包字节长度固定只靠包头长度对齐包尾可以不用就不会错位。2程序编写固定包长含包头包尾,接收4个字节数据Serial初始化#include Serial.h uint8_t Serial_RxPacket[4]; uint8_t Serial_TxPacket[4]; uint8_t Receive_Flag; uint8_t Serial_State; void Serial_Init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_9 ; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin GPIO_Pin_10 ; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStructure); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority 2; NVIC_Init(NVIC_InitStructure); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate 9600; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Tx |USART_Mode_Rx; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_Init(USART1,USART_InitStructure); USART_Cmd(USART1,ENABLE); } //标志位返回并清零 uint8_t Serial_RxFlag() { if(Receive_Flag 1) { Receive_Flag 0; return 1; } return 0; } void USART1_IRQHandler() { static uint8_t pRxNum; if(USART_GetITStatus(USART1,USART_IT_RXNE) SET) { if(Serial_State 0) { if(USART_ReceiveData(USART1) 0xFF) { Serial_State 1; pRxNum 0; } } else if(Serial_State 1) { Serial_RxPacket[pRxNum] USART_ReceiveData(USART1); pRxNum ; if(pRxNum 4) { pRxNum 0 ; Serial_State 2; } } else if(Serial_State 2) { if(USART_ReceiveData(USART1) 0xFE) { Serial_State 0; Receive_Flag 1; } } USART_ClearITPendingBit(USART1,USART_IT_RXNE); } }main函数#include stm32f10x.h #include Delay.h #include OLED.h #include Serial.h int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); OLED_Init(); Serial_Init(); OLED_ShowString(3,1,RxPacket); while(1) { if(Serial_RxFlag() 1) { OLED_ShowHexNum(4,1,Serial_RxPacket[0],2); OLED_ShowHexNum(4,4,Serial_RxPacket[1],2); OLED_ShowHexNum(4,7,Serial_RxPacket[2],2); OLED_ShowHexNum(4,10,Serial_RxPacket[3],2); } } }2、文本数据包1固定包长整包字节总数严格固定一整包1字节包头2字节数据2字节包尾总长6个字符接收逻辑找到包头→再接收5个字符→收满6个字节2可变包长只靠包头包尾分割格式任意长度文本\r\n依靠作为起始\r\n作为结束切分字符串但要避免文本内容里自带回车换行\r\n否则会提前切断数据乱序。3程序编写可变包长接收数据#include Serial.h char Serial_RxPacket[100]; uint8_t Receive_Flag; void Serial_Init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_9 ; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin GPIO_Pin_10 ; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStructure); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority 2; NVIC_Init(NVIC_InitStructure); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate 9600; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Tx |USART_Mode_Rx; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_Init(USART1,USART_InitStructure); USART_Cmd(USART1,ENABLE); } void Serial_SendByte(uint8_t Byte) { USART_SendData(USART1,Byte); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) RESET); } void Serial_SendString(char* String) { while(*String ) { Serial_SendByte(*String); } } void Serial_SendArray(uint8_t *Array,uint8_t Length) { uint8_t i0; for(i0;iLength;i) { Serial_SendByte(Array[i]); } } uint8_t Serial_RxFlag() { if(Receive_Flag 1) { Receive_Flag 0; return 1; } return 0; } void USART1_IRQHandler() { static uint8_t pRxNum 0; static uint8_t Serial_State 0; if(USART_GetITStatus(USART1,USART_IT_RXNE) SET) { uint8_t GetData USART_ReceiveData(USART1); if(Serial_State 0) { if(GetData ) { Serial_State 1; pRxNum 0; } } else if(Serial_State 1) { if(GetData \r) { Serial_State 2; } else { Serial_RxPacket[pRxNum] GetData; pRxNum ; } } else if(Serial_State 2) { if(GetData\n) { Serial_State 0; Serial_RxPacket[pRxNum] \0; Receive_Flag 1; } } USART_ClearITPendingBit(USART1,USART_IT_RXNE); } }本文完其他方式还在学习中……