状态机(State Machine): 实际就是指一个数学模型,可反映事物的不同状态,也就是数电学的状态转换图
想用好状态机的思想需要明白以下四个概念:
状态机的思想在各种程序的编写中使用广泛
/*
发送HEX数据包
*/
void Serial_SendHexPacket(uint8_t * Arr)
{
Send_Byte(0xFF); // 发送包头
Serial_SendArr(Arr, 4);
Send_Byte(0xFE); // 发送包尾
Serial_SendString("\r\n");
}
/*
中断函数, 根据状态机的思想
*/
void USART1_IRQHandler(void)
{
static uint8_t i = 0; // 下标
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // 接收寄存器不空
{
uint8_t Serial_RxData;
Serial_RxData = USART_ReceiveData(USART1); // 接收数据
if(RxState == 0) // 等待包头
{
if(Serial_RxData == 0xFF) // 获取到包头
{
RxState = 1; // 转换
i = 0;
}
}
else if(RxState == 1) // 接收数据
{
RxPacket[i++] = Serial_RxData;
if(i >= 4) // 接收完数据
{
i = 0;
RxState = 2; // 转换状态
}
}else if(RxState == 2) // 等待包尾
{
if(Serial_RxData==0xFE) // 接收到包尾
{
RxState = 0; // 转换状态
RxFlag = 1;
}
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
#include "stm32f10x.h"
#include "delay.h"
#include "OLED.h"
#include "key.h"
#include "serial.h"
// USART串口接收HEX数据包
// 2023年4月4日09:16:55
uint8_t Key_Num;
int main(void)
{
OLED_Init();
Serial_Init();
Init_Key();
OLED_ShowString(1, 1, "TxPacket");
OLED_ShowString(3, 1, "RxPacket");
TxPacket[0] = 0x00;
TxPacket[1] = 0x01;
TxPacket[2] = 0x02;
TxPacket[3] = 0x03;
Serial_SendHexPacket((uint8_t*)TxPacket);
while(1)
{
Key_Num = Get_KeyNum();
if(Key_Num == 2) // 按键发送
{
TxPacket[0]++;
TxPacket[1]++;
TxPacket[2]++;
TxPacket[3]++;
Serial_SendHexPacket((uint8_t*)TxPacket);
OLED_ShowHexNum(2, 1, TxPacket[0], 2);
OLED_ShowHexNum(2, 4, TxPacket[1], 2);
OLED_ShowHexNum(2, 7, TxPacket[2], 2);
OLED_ShowHexNum(2, 10, TxPacket[3], 2);
}
if(RxFlag) // 将接受的数据打印到OLED屏
{
OLED_ShowHexNum(4, 1, RxPacket[0], 2);
OLED_ShowHexNum(4, 4, RxPacket[1], 2);
OLED_ShowHexNum(4, 7, RxPacket[2], 2);
OLED_ShowHexNum(4, 10, RxPacket[3], 2);
RxFlag = 0;
}
}
}
#include "stm32f10x.h"
uint8_t RxPacket[4]; // 保存接收到的数据包
uint8_t TxPacket[4]; // 保存要发送的数据包
uint8_t RxFlag; // 接收标志
uint8_t RxState; // 接收状态
void Serial_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 初始化GPIO
// TX 发送端
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);
// RX 接收端
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART串口通信
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600; // 波特率
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 无流控
USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity=USART_Parity_No; // 奇偶校验
USART_InitStructure.USART_StopBits=USART_StopBits_1; // 停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b; // 8位
USART_Init(USART1, &USART_InitStructure);
// 打开USART中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 接收寄存器非空(正在接收)
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);
// 启动USART
USART_Cmd(USART1, ENABLE);
}
/*
发送单个数据
*/
void Send_Byte(uint16_t Byte)
{
USART_SendData(USART1, Byte);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完毕
}
/*
发送字符串
*/
void Serial_SendString(char * String)
{
uint8_t i;
for(i=0; String[i] != '\0'; ++i)
{
Send_Byte(String[i]);
}
}
/*
发送数组
*/
void Serial_SendArr(uint8_t * Arr, uint8_t Length)
{
for(uint8_t i=0; i<Length; ++i)
{
Send_Byte(Arr[i]);
}
}
/*
发送HEX数据包
*/
void Serial_SendHexPacket(uint8_t * Arr)
{
Send_Byte(0xFF);
Serial_SendArr(Arr, 4);
Send_Byte(0xFE);
Serial_SendString("\r\n");
}
/*
中断函数
*/
void USART1_IRQHandler(void)
{
static uint8_t i = 0; // 下标
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // 接收寄存器不空
{
uint8_t Serial_RxData;
Serial_RxData = USART_ReceiveData(USART1); // 接收数据
if(RxState == 0) // 等待包头
{
if(Serial_RxData == 0xFF) // 获取到包头
{
RxState = 1; // 转换
i = 0;
}
}
else if(RxState == 1) // 接收数据
{
RxPacket[i++] = Serial_RxData;
if(i >= 4) // 接收完数据
{
i = 0;
RxState = 2; // 转换状态
}
}else if(RxState == 2) // 等待包尾
{
if(Serial_RxData==0xFE) // 接收到包尾
{
RxState = 0; // 转换状态
RxFlag = 1;
}
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
#ifndef __SERIAL_H
#define __SERIAL_H
void Serial_Init(void);
void Send_Byte(uint16_t Byte);
void Serial_SendString(char * String);
void Serial_SendArr(uint8_t * Arr, uint8_t Length);
void Serial_SendHexPacket(uint8_t * Arr);
void Serial_SendTxtPacket(char * String);
extern char RxPacket[];
extern char TxPacket[];
extern uint8_t RxFlag;
extern uint8_t RxState;
#endif
/*
中断函数 状态机思想
*/
void USART1_IRQHandler(void)
{
static uint8_t pRxData = 0;
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // 接收寄存器不空
{
uint8_t Serial_RxData;
Serial_RxData = USART_ReceiveData(USART1); // 接收数据
if(RxState == 0) // 等待包头
{
if(Serial_RxData == '@' && RxFlag==0) // 收到包头
{
RxState = 1; // 转换状态
pRxData = 0;
}
}
else if(RxState == 1) // 接收数据打包
{
if(Serial_RxData == '\r') // 收到完整数据
{
RxPacket[pRxData++] = Serial_RxData; // 'r'
RxState = 2;
}else
{
RxPacket[pRxData++] = Serial_RxData;
}
}
else if(RxState==2) // 等待包尾
{
if(Serial_RxData=='\n')
{
RxState = 0;
RxPacket[pRxData++] = '\n'; // '\n'
RxPacket[pRxData] = '\0'; // '字符串结束标志'
RxFlag = 1; // 接收完成标志位
}
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
#include "stm32f10x.h"
#include "delay.h"
#include "OLED.h"
#include "serial.h"
#include "LED.h"
#include // 字符串处理函数
// USART串口接收文本数据包
// 2023年4月6日19:22:18
uint8_t Key_Num;
int main(void)
{
OLED_Init();
Serial_Init(); // 串口初始化
LED_Init();
OLED_ShowString(1, 1, "TxPacket");
OLED_ShowString(3, 1, "RxPacket");
while(1)
{
if(RxFlag) // 收到一个数据包
{
OLED_ShowString(4, 1, " ");
OLED_ShowString(4, 1, RxPacket);
// 判断指令
if(strcmp(RxPacket, "LED_On\r\n")==0)
{
LED_On(); // 开灯
Serial_SendString("LED_ON_OK\r\n");
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "LED_ON_OK");
}else if(strcmp(RxPacket, "LED_Off\r\n")==0) // strcmp 可以比较两字符串是否相同
{
LED_Off(); // 关灯
Serial_SendString("LED_OFF_OK\r\n");
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "LED_OFF_OK");
}
else // 指令错误
{
Serial_SendString("ERROR_COMMAND\r\n");
OLED_ShowString(2, 1, " ");
OLED_ShowString(2, 1, "ERROR_COMMAND");
}
RxFlag = 0; // 清除自定义标志
}
}
}
#include "stm32f10x.h"
char RxPacket[100]; // 保存接收到的数据包
char TxPacket[100]; // 保存要发送的数据包
uint8_t RxFlag; // 接收标志
uint8_t RxState; // 接收状态
void Serial_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 初始化GPIO
// TX 发送端
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);
// RX 接收端
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART串口通信
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600; // 波特率
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 无流控
USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity=USART_Parity_No; // 奇偶校验
USART_InitStructure.USART_StopBits=USART_StopBits_1; // 停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b; // 8位
USART_Init(USART1, &USART_InitStructure);
// 打开USART中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 接收寄存器非空(正在接收)
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);
// 启动USART
USART_Cmd(USART1, ENABLE);
}
/*
发送单个数据
*/
void Send_Byte(uint16_t Byte)
{
USART_SendData(USART1, Byte);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完毕
}
/*
发送字符串
*/
void Serial_SendString(char * String)
{
uint8_t i;
for(i=0; String[i] != '\0'; ++i)
{
Send_Byte(String[i]);
}
}
/*
发送数组
*/
void Serial_SendArr(uint8_t * Arr, uint8_t Length)
{
for(uint8_t i=0; i<Length; ++i)
{
Send_Byte(Arr[i]);
}
}
/*
发送HEX数据包
*/
void Serial_SendHexPacket(uint8_t * Arr)
{
Send_Byte(0xFF);
Serial_SendArr(Arr, 4);
Send_Byte(0xFE);
Serial_SendString("\r\n");
}
/*
发送文本数据包
*/
void Serial_SendTxtPacket(char * String)
{
Serial_SendString("@");
Serial_SendString(String);
Serial_SendString("\r\n");
}
/*
中断函数
*/
void USART1_IRQHandler(void)
{
static uint8_t pRxData = 0;
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // 接收寄存器不空
{
uint8_t Serial_RxData;
Serial_RxData = USART_ReceiveData(USART1); // 接收数据
if(RxState == 0) // 等待包头
{
if(Serial_RxData == '@' && RxFlag==0) // 收到包头
{
RxState = 1; // 转换状态
pRxData = 0;
}
}
else if(RxState == 1) // 接收数据打包
{
if(Serial_RxData == '\r') // 收到完整数据
{
RxPacket[pRxData++] = Serial_RxData;
RxState = 2;
}else
{
RxPacket[pRxData++] = Serial_RxData;
}
}
else if(RxState==2) // 等待包尾
{
if(Serial_RxData=='\n')
{
RxState = 0;
RxPacket[pRxData++] = '\n';
RxPacket[pRxData] = '\0';
RxFlag = 1; // 接收完成标志位
}
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
#ifndef __SERIAL_H
#define __SERIAL_H
void Serial_Init(void);
void Send_Byte(uint16_t Byte);
void Serial_SendString(char * String);
void Serial_SendArr(uint8_t * Arr, uint8_t Length);
void Serial_SendHexPacket(uint8_t * Arr);
void Serial_SendTxtPacket(char * String);
extern char RxPacket[];
extern char TxPacket[];
extern uint8_t RxFlag;
extern uint8_t RxState;
#endif
江科大STM32入门教程
什么是状态机? - Peter 王广忠的文章 - 知乎