首页 > 其他分享 >【stm32】USART编码部分--串口数据包

【stm32】USART编码部分--串口数据包

时间:2024-04-02 21:30:56浏览次数:21  
标签:USART void uint8 InitStructure 串口 GPIO Serial 数据包

USART串口数据包【源码放在最后】

关于数据包的分类

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

关于数据包的发送

  • 如果想要发送Hex数据包,定义一个数组填充数据,然后使用串口模块函数SendArray进行发送

  • 如果想要发送文本数据包,写一个字符串然后调用SendString进行发送

  • 对于发送数据包很简单,因为发送过程完全是自主可控的,想法啥就发啥

关于接收一个数据包
  • 固定包长Hex数据包的接收方法

    • 每次收到一个字节程序都会进一次中断,在中断函数里我们可以拿到这个字节,但是拿到之后就要推出中断,所以每拿到一个数据都是个独立的过程

    • 对于数据包来说,很明显它具有前后关联性,包头之后是数据数据之后是包尾,对于包头、数据和包尾这三种状态,需要有不同的处理逻辑,所以在程序中需要设计一个能够记住不同状态的机制,在不同状态执行不同的操作,同时还要进行不同状态的合理转移,这种状态思维就叫做-------状态机

    • 状态转移图-在这里插入图片描述

    • 执行逻辑

      • 开始s=0;收到一个数据进中断,根据S=0,进入第一个状态的程序,判断包头是不是FF,如果是FF

      • 置S=1,退出中断,结束

      • 下次在进中断,根据S=1,就可以进行接收数据的程序

      • 在第一个状态如果接收到的数据不是FF、就证明数据包没有对齐,应该等待数据包包头的出现,这时状态就仍然是0,下次进中断就还是等待包头的逻辑,直到出现FF,才能转到下一个状态

      • 等到接收数据时,再收到数据就把他存到数组中,再用个变量记录接收到了多少个数据,如果没收够四个数据,就一直是接收数据的状态,如果收够了,就置S=2,进入等待包尾的程序中

      • 判断收到的数据是不是FE,如果时FE,置S=0,回到最初的状态,开始下个轮回

      • 也有可能最后一个不是包尾,比如数据和包头重复,导致包头位置判断错了,那这个包尾位置就有可能不是FE、这时就可以进入重读等待包尾的状态,直到接收到包尾

串口收发Hex数据包编码–基于串口发送+接收
  1. 建立两个字符数组,用来接收和发送载荷数据,不存储包头和包尾

  2. 先编写SendPacket函数,调用一下这个函数Txpacket数组的四个数据,就会自动加上包头包尾发送出去(发送不进中断函数),首先调用SendByte发送包头,调用SendArray发送数据,调用SendByte发送包尾

  3. 把Txpacket数组在头文件包含 变为外部可调用,在main函数中分别赋数据到数组的每个成员,添加按键,在按键的判断中不断++数组的值

  4. 对于接收这样一个数据包的代码

    1. 在接受中断函数里,需要使用状态机来执行接收逻辑,接收数据包,把载荷数据存在RxPacket数组里
    2. 首先定义一个标志当前状态的变量RxState,在中断函数里定义一个静态变量,根据RxState的不同进入不同的处理程序
    3. 定义变量RxData用于接收每次接收到的一个字节数据uint8_t RxData = USART_ReceiveData(USART1);
    4. 在状态RxState = 1时需要定义一个静态变量pRxPacket来记录接收载荷数据的个数,记得清0----pRxPacket
    5. 在状态2时等待包尾,当接收到包尾时置一个标志位,证明数据接收完成
    6. 主函数判断标志位进行显示载荷数据
串口收发文本数据包
  • 可变包长含包头包尾

  • 只写接收的部分,因为发送不方便像Hex数组一样方便的一个个更改,所以发送就直接在主函数里SendString,或者printf就行
    在这里插入图片描述

串口收发HEX数据包程序

serial.c文件

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t Serial_TxPacket[4];				//FF 01 02 03 04 FE
uint8_t Serial_RxPacket[4];
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_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_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_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_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}


void Serial_SendPacket(void)
{
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket, 4);
	Serial_SendByte(0xFE);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == 0xFF)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket ++;
			if (pRxPacket >= 4)
			{
				RxState = 2;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == 0xFE)
			{
				RxState = 0;
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

serial.h文件

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

extern uint8_t Serial_TxPacket[];
extern uint8_t Serial_RxPacket[];

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

void Serial_SendPacket(void);
uint8_t Serial_GetRxFlag(void);

#endif

main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	Key_Init();
	Serial_Init();
	
	OLED_ShowString(1, 1, "TxPacket");
	OLED_ShowString(3, 1, "RxPacket");
	
	Serial_TxPacket[0] = 0x01;
	Serial_TxPacket[1] = 0x02;
	Serial_TxPacket[2] = 0x03;
	Serial_TxPacket[3] = 0x04;
	
	while (1)
	{
		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			Serial_TxPacket[0] ++;
			Serial_TxPacket[1] ++;
			Serial_TxPacket[2] ++;
			Serial_TxPacket[3] ++;
			
			Serial_SendPacket();
			
			OLED_ShowHexNum(2, 1, Serial_TxPacket[0], 2);
			OLED_ShowHexNum(2, 4, Serial_TxPacket[1], 2);
			OLED_ShowHexNum(2, 7, Serial_TxPacket[2], 2);
			OLED_ShowHexNum(2, 10, Serial_TxPacket[3], 2);
		}
		
		if (Serial_GetRxFlag() == 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);
		}
	}
}

串口收发文本数据包程序

serial.c文件

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

char Serial_RxPacket[100];				//"@MSG\r\n"
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_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_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_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_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == '@' && Serial_RxFlag == 0)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			if (RxData == '\r')
			{
				RxState = 2;
			}
			else
			{
				Serial_RxPacket[pRxPacket] = RxData;
				pRxPacket ++;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == '\n')
			{
				RxState = 0;
				Serial_RxPacket[pRxPacket] = '\0';
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

serial.h文件

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

extern char Serial_RxPacket[];
extern uint8_t Serial_RxFlag;

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

#endif

main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include "string.h"

int main(void)
{
	OLED_Init();
	LED_Init();
	Serial_Init();
	
	OLED_ShowString(1, 1, "TxPacket");
	OLED_ShowString(3, 1, "RxPacket");
	
	while (1)
	{
		if (Serial_RxFlag == 1)
		{
			OLED_ShowString(4, 1, "                ");
			OLED_ShowString(4, 1, Serial_RxPacket);
			
			if (strcmp(Serial_RxPacket, "LED_ON") == 0)
			{
				LED1_ON();
				Serial_SendString("LED_ON_OK\r\n");
				OLED_ShowString(2, 1, "                ");
				OLED_ShowString(2, 1, "LED_ON_OK");
			}
			else if (strcmp(Serial_RxPacket, "LED_OFF") == 0)
			{
				LED1_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");
			}
			
			Serial_RxFlag = 0;
		}
	}
}

标签:USART,void,uint8,InitStructure,串口,GPIO,Serial,数据包
From: https://blog.csdn.net/weixin_52978505/article/details/137290939

相关文章

  • IP(Internet Protocol)是一种网络协议,用于在网络中发送和接收数据包
    IP(InternetProtocol)是一种网络协议,用于在网络中发送和接收数据包。它是一个无连接的、不可靠的数据报协议,负责将数据从源主机传输到目标主机。IP协议的主要功能包括寻址、路由和分段。寻址:IP协议为每个连接到网络的设备分配一个唯一的IP地址,这个地址用于在网络中识别设备......
  • .net和java串口通讯压力测试对比
    最近由于工作要求,需要对一个串口通讯设备进行压力测试,要求连续持续对串口设备发送指令,无间隔,测试设备是否会死机。要求做到毫秒级,测试第三方的工具,基本上都无法达到毫秒级,最少的也是10毫秒。于是就自己写代码测试。通过.net写,发现最少能达到1毫秒,但是有遗漏,看日志如下2024-03-3......
  • 32-3 APP渗透核心 - APP数据包抓取
    环境准备安装模拟器:在PC上安装一个Android模拟器,例如Genymotion、Bluestacks或者AndroidStudio提供的模拟器等。模拟器可以模拟手机环境,让你在PC上运行Android应用程序。下载APP:在模拟器中下载需要进行渗透测试的APP。你可以通过GooglePlay商店、APK文件或者其他渠道获......
  • 35.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-登录成功数据包内容分析
    免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!如果看不懂、不知道现在做的什么,那就跟着做完看效果内容参考于:易道云信息技术研究院VIP课上一个内容:34.登录数据包的监视与模拟首先登陆游戏,到角色选择界面,如下图,可以看到这个数据包很大2421个字节首先确定......
  • 1-WIFI&蓝牙(ESP32)转CAN总线&串口TTL模块-CSDK-VSCode开发环境搭建
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ESP32_CAN"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p> 安装串口(CH340)驱动(已经安装的不需......
  • STM32 串口 DMA 接收不定长数据的一种方法
    1.前言使用串口接收不定长数据时,可以有多种方法,比如最常见的有额外使能一个定时器,在超过定时范围未收到后续的字节时,认为此帧结束;或者利用IDLE中断,当数据空闲时,自动产生中断;亦或每接收到一个字节后都通过应用程序进行一次处理。这次我们介绍另外一种方法,在DMA方式下利......
  • 转载:使用 Linux tracepoint、perf 和 eBPF 跟踪数据包 (2017)
    http://arthurchiao.art/blog/trace-packet-with-tracepoint-perf-ebpf-zh/Linux允许在主机上用虚拟网卡(virtualinterface)和网络命名空间(networknamespace)构建复杂的网络。但出现故障时,排障(troubleshooting)相当痛苦。如果是3层路由问题,mtr 可以排上用场;但如果是更底层的问......
  • 在Linux中,如何追踪TCP连接和网络数据包,如使用tcpdump或Wireshark?
    在Linux环境中,追踪TCP连接和网络数据包主要通过使用命令行工具tcpdump和图形化网络分析软件Wireshark来实现。以下是详细的操作步骤:1.使用tcpdumptcpdump是一个强大的命令行网络抓包工具,用于实时捕获和分析网络流量。以下是如何使用tcpdump追踪TCP连接和数据包:1.基本用法......
  • STM32收发HEX数据包
            在实际应用中,STM32的串口通信都是以数据包格式进行收发,这个数据包一般都包含包头和包尾,表示一个数据包。源代码在文末给出数据包格式:固定长度,含包头包尾可变包长,含包头包尾问题1:当数据包传输时,里面有数据与包头包尾重复怎么办?1:设置限幅,包头包尾设置为数......
  • QT串口通信原理加实例
    串口通信原理:一、串口通信的基本原理串口的本质功能是作为CPU和串行设备间的编码转换器。当数据从CPU经过串行端口发送出去时,字节数据转换为串行的位(bit);在接收数据时,串行的位被转换为字节数据。应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开......