STM32收发HEX数据包

        在实际应用中,STM32的串口通信都是以数据包格式进行收发,这个数据包一般都包含包头和包尾,表示一个数据包。源代码在文末给出

数据包格式:

固定长度,含包头包尾

可变包长,含包头包尾

问题1:当数据包传输时,里面有数据与包头包尾重复怎么办?

1:设置限幅,包头包尾设置为数据包无法超过的16进制数

2:如果无法避免重复,那么就采用固定长度,含包头包尾的包格式

3:增加包头包尾的数据,增强包头包尾的唯一性,例如可以设置两位包头:0xFF与0xFD,判断包头时,需要同时判断第二位是否为0xFD,包尾同理。

问题2:包头包尾是否可以去掉一个?

        是可以的,包头包尾并不是全都需要,例如当采用固定包长进行数据包收发时候,这时就可以只有一个包头,当程序检测到包头后开始接收数据,收够4个字节后,置标志位,一个数据包接收完成。但是这种方法存在很大的弊端,例如当设置包头为0xFF的时候,这时传输4个0xFF的时,程序就可能分不清哪个是包头。

问题3:如何发送字节流:

        在STM32中,数据包都是以一个字节一个字节进行发送的,当需要发送16位,或32位的数据时,如何发送?例如float,double,甚至是结构体。STM32支持这种发送方式,这种16位或32位的数据类型内部都是由多个字节组成的,发送时只需要使用uint8_t指针指向它,把它当成一个字节数组发送就可以发送整个数据。

总结:

        若数据包载荷不会和包头包尾重复,那么就可以选择可变包长,相反就选择固定包长。可变包长的灵活性很强,可以选择任意的数据包长度,发送16位或32位的变量时候使用uint8_t指针指向它,就可以发送整个数据。

HEX数据包与文本数据包:

        HEX数据包发送的就是16进制数据,而文本数据包是将数字译码后的数据,通常以换行作为包尾,文本载荷数据是一个字符串。

        HEX数据包传输最直接,解析数据非常简单,比较适合模块发送原始数据,例如传感器等,缺点是载荷容易和包头包尾重复,文本数据包数据适合输入指令进行人机交互,例如蓝牙模块的AT指令,缺点是解析效率低,例如发送数字100,文本数据就需要占用3个字节,而HEX只需要1个字节空间。 根据实际场景选择数据。

数据包发送:

HEX数据包:

        定义字符数组进行发送

文本数据包发送:

        定义字符串进行发送

数据包接收:

        每收到一个字节,程序都会进入一次中断,因此每拿到一个字节的数据都是独立的过程,对数据包来说,主要有包头,载荷,包尾这三种数据,那么需要设计一种能记住不同状态的程序和机制,在不同状态执行不同的操作,同时还要进行状态的合理转移,这种程序设计就叫做状态机(State Machine)

HEX数据包接收:

如下图状态转移图:

        首先设置状态变量s = 0;表示等待包头,当接收到数据进入中断时,中断程序进行判断状态接收到的数据是否为包头,是的话将s置1,表示接收数据,这样在下一次中断时就会进行数据接收,并且还要在程序中设置一个数组,当接收到载荷的长度后,表示数据接收完成,这时将s置2,表示等待包尾,如果没有问题,那么下一次收到的数据就是包尾数据,这时将s置0,这样就完成了一次接收数据的循环。

        如果数据和包头重复,那么就说明数据判断错误,那么接收完成后包尾的位置就可能不是FE,这时就可以进入重复等待包尾的状态,直到接收到真正的包尾,这样能预防数据和包头重复的错误。

        真正设计串口通信时,尽量避免包头与数据重复。

文本数据包接收:

如下图状态转移图:   

        与HEX不同的是,在s = 1的时候,每次接收数据都要判断是否为\r如果是,则不接受数据并进入下一个状态等待包尾\n,这里有两个包尾,如果只有一个包尾为\r的话那么当接收到\r时可以直接回到s=0了。

 电路连接:

        连接显示屏与触摸模块,显示屏的SCL在B10,SDA在B11,触摸模块的输出引脚在A1(触摸时输出高电平)。

编写代码:

Serial.c

#include "stm32f10x.h"                  // Device header
#include "DELAY.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
uint8_t KeyNum;

int main() {
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//下拉输入IPD,上拉输入IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//这一行可以不写,在输入模式下这一行不起作用
	GPIO_Init(GPIOA,  &GPIO_InitStructure);
	OLED_Init();
	Serial_Init();
	OLED_ShowString(1, 1, "TxData:");
	OLED_ShowString(3, 1, "RxData:");

	Serial_TxPacket[0] = 0x01;
	Serial_TxPacket[1] = 0x02;
	Serial_TxPacket[2] = 0x03;
	Serial_TxPacket[3] = 0x04;

	while(1){
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1){//按键按下,这一位为1
			while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1);//如果一直不松手那么程序就卡在这里
			KeyNum = 1;//返回按键的值
		}
		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);//RxPacket数组是同时读写的数组,
			OLED_ShowHexNum(2,4, Serial_TxPacket[1], 2);
			OLED_ShowHexNum(2,7, Serial_TxPacket[2], 2);
			OLED_ShowHexNum(2,10, Serial_TxPacket[3], 2);
			KeyNum = 0;
		}
		if(Serial_GetRxFlag() == 1) {
			OLED_ShowHexNum(4,1, Serial_RxPacket[0], 2);//RxPacket数组是同时读写的数组,
			//当读取速度慢的时候,后面的数据可能会刷新为下一个数据包的数据,可能会造成数据冲突
			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.h

#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
extern uint8_t Serial_TxPacket[];//外部可调用,如果模块里有数组需要外部调用,一般使用Get,Set函数进行封装,使用指针传递
extern uint8_t Serial_RxPacket[];

void Serial_Init();
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,...);
uint8_t Serial_GetRxFlag();
void Serial_SendPacket();


#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "DELAY.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
uint8_t KeyNum;

int main() {
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//下拉输入IPD,上拉输入IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//这一行可以不写,在输入模式下这一行不起作用
	GPIO_Init(GPIOA,  &GPIO_InitStructure);
	OLED_Init();
	Serial_Init();
	OLED_ShowString(1, 1, "TxData:");
	OLED_ShowString(3, 1, "RxData:");

	Serial_TxPacket[0] = 0x01;
	Serial_TxPacket[1] = 0x02;
	Serial_TxPacket[2] = 0x03;
	Serial_TxPacket[3] = 0x04;

	while(1){
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1){//按键按下,这一位为1
			while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1);//如果一直不松手那么程序就卡在这里
			KeyNum = 1;//返回按键的值
		}
		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);//RxPacket数组是同时读写的数组,
			OLED_ShowHexNum(2,4, Serial_TxPacket[1], 2);
			OLED_ShowHexNum(2,7, Serial_TxPacket[2], 2);
			OLED_ShowHexNum(2,10, Serial_TxPacket[3], 2);
			KeyNum = 0;
		}
		if(Serial_GetRxFlag() == 1) {
			OLED_ShowHexNum(4,1, Serial_RxPacket[0], 2);//RxPacket数组是同时读写的数组,
			//当读取速度慢的时候,后面的数据可能会刷新为下一个数据包的数据,可能会造成数据冲突
			OLED_ShowHexNum(4,4, Serial_RxPacket[1], 2);
			//若在这里(读取的过程中)进入中断,那么数组的数据就可能被覆盖
			OLED_ShowHexNum(4,7, Serial_RxPacket[2], 2);
			OLED_ShowHexNum(4,10, Serial_RxPacket[3], 2);
		}
	}
}

程序现象:

        触摸开关触摸一次,发送一个数据包,在串口助手中,发送区域填写FF 12 34 56 78 FE发送数据,STM32接收到数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/493608.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学点儿数据库_Day11_多表、等值连接、内连接、模糊查找

1 多表 学生表、班级表、课程表、班级课程表 关系型数据库&#xff1a; MySql、SqlServer、Oracle 相同的数据出现多次绝不是一件好事&#xff0c;这是关系数据库设计的基础。关系表的设计就是要把信息分解成多个表&#xff0c;一个数据一个表&#xff0c;各表通过某些共同的…

真机笔记(3) 真机需求讲解

目录 拓扑分析&#xff1a; 设计理念&#xff1a; 1. 生产区交换需求&#xff1a; 2. 生产区交换需求&#xff1a; 3. 服务器区交换需求&#xff1a; 4. 路由设计 5. 地址规划&#xff1a; 拓扑分析&#xff1a; 蓝色&#xff1a;网线 红色&#xff1a;多模光纤 黄色&am…

AI Agent(LLM Agent)入门解读

1. 什么是AI Agent&#xff1f; AI Agent可以理解为一个智能体&#xff0c;包括感知模块、规划决策模块和行动模块&#xff0c;类似于人类的五官、大脑和肢体。它能帮助人类处理复杂的任务&#xff0c;并能根据环境反馈进行学习和调整。 五官可以理解为感知模块&#xff0c;大…

React和Vue.js的有什么区别

在当今前端开发领域&#xff0c;React 和 Vue.js 作为两大热门的前端框架备受开发者关注。它们各自拥有独特的特点和优势&#xff0c;在实际项目中有着广泛的运用。本文将深入探讨 React 和 Vue.js 之间的区别&#xff0c;从组件化方式、数据绑定、模板语法以及生态系统和工具支…

全国草地资源类型分布图

草地出现在世界各地&#xff0c;约占全球陆地面积的24%&#xff0c;大多分布于大陆内部气候干燥、降水较少的地区&#xff0c;其中澳大利亚、俄罗斯、中国、美国和巴西等国面积较大。中国草地面积约占国土面积的40%&#xff0c;主要分布在内蒙古、东北、西北和青藏高原&#xf…

2024/03/27(C++·day3)

一、思维导图 二、完成下面类 代码 #include <cstring> #include <iostream>using namespace std;class myString { private:char *str; // 记录C风格的字符串int size; // 记录字符串的实际长度public:// 无参构造函数myString() : size(10){str new char[si…

力扣Lc23--- 290. 单词规律(java版)-2024年3月27日

1.题目描述 2.知识点 1&#xff09;思路 &#xff08;1&#xff09;s.split(" "); 是将字符串 s 按空格进行分割&#xff0c;得到一个单词列表。 &#xff08;2&#xff09;建立模式字符和单词之间的双向映射关系&#xff0c;我们可以使用两个哈希映射&#xff08;或…

Oracle数据库管理:从基础到高级应用【文末送书-45】

文章目录 入门篇&#xff1a;初识Oracle进阶篇&#xff1a;深入学习Oracle精通篇&#xff1a;掌握Oracle高级技术Oracle从入门到精通&#xff08;第5版&#xff09;&#xff08;软件开发视频大讲堂&#xff09;【文末送书-45】 在当今数字化时代&#xff0c;数据是企业成功的关…

数据结构之单链表的详细实现(图解)

前言 本次博客讲结合图例讲解单向不带头非循环链表 此后会讲解一些题目 1单链表的实现 1.1什么是单链表 我们先看数组&#xff0c;即顺序表的是什么样的&#xff0c;再看链表 1.2单链表的特点 实际中要实现的链表的结构非常多样&#xff0c;以下情况组合起来就有8种链表结…

【业界动态】Digital Twin-数字孪生

绝大多数的人对数字孪生是一个模糊的概念&#xff0c;数字孪生也被称为数字映射、数字镜像&#xff0c;他既是一种技术&#xff0c;也是一种生态。随着互联网的建设与发展&#xff0c;数字孪生在未来又会如何发展&#xff0c;虚拟与现实之间会产生怎样的星火&#xff1f; 上帝按…

【MATLAB源码-第170期】基于matlab的BP神经网络股票价格预测GUI界面附带详细文档说明。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于BP神经网络的股票价格预测是一种利用人工神经网络中的反向传播&#xff08;Backpropagation&#xff0c;简称BP&#xff09;算法来预测股票市场价格变化的技术。这种方法通过模拟人脑的处理方式&#xff0c;尝试捕捉股票…

chrome 浏览器报错 This page will not function without javascript enabled

This page will not function without javascript enabled. Please enable javascript on your browser. 在访问公司spark history 页面时&#xff0c;发现页面加载不全&#xff0c;并提示如上报错&#xff0c;因此按照如下步骤&#xff0c;已解决问题。 在浏览器中启用 JavaS…

产品经理进阶:抖音电商的商业逻辑(抖店)

目录 内容简介 市场情况 作者简介 内容简介 最近看到很多人在讲如何开抖店、如何做无货源等等这些事情。 这个事本身没有什么问题&#xff0c;毕竟有人下场挖金子&#xff0c;就有人卖工具。 问题在于很多是边开店边传授知识&#xff0c;而抖店本身其实赚的是信息差的钱。…

Openstack创建和操作实例,实现与外部网络通信

一、熟悉OpenStack图形界面操作 1、了解Horizon项目 Horizon项目 各OpenStack服务的图形界面都是由Horizon提供的。Horizon提供基于Web的模块化用户界面。Horizon为云管理员提供一个整体的视图。Horizon为终端用户提供一个自主服务的门户。Horizon由云管理员进行管理与控制&a…

centos7.9安装mysql

1. 概述 官网&#xff1a;https://www.mysql.com/ MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Management S…

稀碎从零算法笔记Day28-LeetCode:零钱兑换

前言&#xff1a;鸽了好多天了哈哈哈&#xff0c;虽然C站没更但是LC还是坚持刷的&#xff0c;任重道远啊&#xff01;(可恶的寝室熄灯) 题型&#xff1a;动态规划 链接&#xff1a;322. 零钱兑换 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述…

张宏波:希望 MoonBit 可以成为世界级的编程语言以及配套的工具链

首场线下 MeetUp 精彩回顾来啦&#xff01; 3月23日&#xff0c;MoonBit 的首场线下 MeetUp 如期而至&#xff0c;带来了一场关于国产软件新发展的探讨。这场活动汇集了五位行业内的知名专家&#xff0c;他们围绕国产基础软件的新发展&#xff0c;分享了四个充满洞见的主题。从…

Springboot整合Redis报错:Unable to connection Redis

今天在做Springboot整合Redis中碰到下列错误&#xff1a; 基于以上的错误首先在Xshell或者其他远程操控虚拟机的软件上看能不能连接到Redis: [zzllocalhost ~]$ redis-cli -h 192.168.136.132 -p 6379 -a ****** Warning: Using a password with -a or -u option on the comma…

AI大模型学习——AI领域技术发展

目录 前言 一、AI大模型学习的理论基础 二、AI大模型的训练与优化 三、AI大模型在特定领域的应用 四、AI大模型学习的伦理与社会影响 五、未来发展趋势与挑战 总结 前言 在当前技术环境下&#xff0c;AI大模型学习不仅要求研究者具备深厚的数学基础和编程能力&#xff…

django orm DateTimeField 6位小数精度问题

from django.db.backends.mysql.base import DatabaseWrapperDatabaseWrapper.data_types[DateTimeField] "datetime"意思就是重写源码里面的DateTimeField字段