STM32入门笔记11_USART串口数据包+案例: USART接收HEX数据包 USART接收文本数据包

USART串口数据包

数据模式

  • HEX模式/十六进制模式/二进制模式: 以原始数据的形式显示
  • 文本模式/字符模式
    在这里插入图片描述
    在这里插入图片描述

HEX数据包

  • 固定包长, 含包头包尾
    在这里插入图片描述

  • 可变包长, 含包头包尾

在这里插入图片描述

文本数据包

  • 固定包长, 含包头包尾

在这里插入图片描述

  • 可变包长, 含包头包尾

在这里插入图片描述

HEX数据包接收

在这里插入图片描述
在这里插入图片描述

文本数据包接收

在这里插入图片描述
在这里插入图片描述

状态机

状态机(State Machine): 实际就是指一个数学模型,可反映事物的不同状态,也就是数电学的状态转换图

想用好状态机的思想需要明白以下四个概念:

  • State, 状态(一个状态机至少有两种状态) 即图中 S, 当 S=0,S=1,S=2即对应了状态机的三种不同的状态
  • Event, 事件 图中收到‘@’,收到‘r’, 收到’\n’, 收到其他数据 即为四种不同的
  • Action, 动作 一般来说,每个事件发生后要有对应的动作(比如说 收到LED_ON指令(事件) 开启LED(动作))
  • Transition, 变换 特定事件发生后, 状态机的状态发生变化

状态机的思想在各种程序的编写中使用广泛

案例1: USART收发HEX数据包

主要函数

/*
	发送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);
	}
}

主要代码

main.c
#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;
		}
		
	}
}
Serial.c
#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);
	}
}

Serial.h
#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

案例2: USART收发文本数据包

主要函数

/*
	中断函数 状态机思想
*/
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);
	}
}

主要代码

main.c
#include "stm32f10x.h" 
#include "delay.h"
#include "OLED.h"
#include "serial.h"
#include "LED.h"
#include <string.h>  // 字符串处理函数
// 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;  // 清除自定义标志
		}
		
	}
}

serial.c
#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);
	}
}
serial.h
#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 王广忠的文章 - 知乎

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值