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){//按键按下,这一位为1while(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){//按键按下,这一位为1while(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接收到数据。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言例4-15:从键盘输入一个整数,求其绝对值并输出。

代码如下&#xff1a; //从键盘输入一个整数&#xff0c;求其绝对值并输出。 #include<stdio.h> int main(void) {int n;printf("输出一个整数&#xff1a; \n");scanf("%d",&n); //从键盘输入一个整数保存至变量nif(n<0) //…

C#打印50*30条码标签

示例图&#xff1a; 源码下载地址&#xff1a;https://download.csdn.net/download/tiegenZ/89035407?spm1001.2014.3001.5503

混合云构建-使用 Azure ExpressRoute 建立从本地到 Azure 虚拟网络的专用连接

如果有大量业务数据需要在本地数据中心和azure私有网络进行传输&#xff0c;同时保证带宽和时延的情况需要使用 ExpressRoute 设置从本地网络到 Azure 中的虚拟网络的专用连接。以下是实操步骤供参考&#xff1a; 一、创建和预配 ExpressRoute 线路 登录 Azure 门户。 在页面顶…

comfyui 代码结构分析

comfyui的服务器端是用aiohtttp写的&#xff0c;webui是fastapi直接构建的&#xff0c;但是其实comfyui的这种设计思路是很好的&#xff0c;也许我们不需要在后端起一个复杂的前台&#xff0c;但是可以借助json结构化pipeline&#xff0c;然后利用node节点流把整个流程重新映射…

DaisyDisk for mac 苹果电脑磁盘清理工具

DaisyDisk for Mac是一款直观易用的磁盘空间分析工具&#xff0c;专为Mac用户设计&#xff0c;旨在帮助他们快速识别和管理磁盘上的文件与文件夹&#xff0c;从而释放存储空间。 软件下载&#xff1a;DaisyDisk for mac 激活版 DaisyDisk采用独特的可视化界面&#xff0c;将磁盘…

2024年目前阿里云服务器一个月收费价格表多少钱?

阿里云服务器一个月多少钱&#xff1f;最便宜5元1个月。阿里云轻量应用服务器2核2G3M配置61元一年&#xff0c;折合5元一个月&#xff0c;2核4G服务器30元3个月&#xff0c;2核2G3M带宽服务器99元12个月&#xff0c;轻量应用服务器2核4G4M带宽165元12个月&#xff0c;4核16G服务…

基于OneAPI+ChatGLM3-6B+FastGPT搭建LLM大语言模型知识库问答系统

搭建大语言模型知识库问答系统 部署OneAPI部署一个LLM模型部署嵌入模型部署FastGPT新建FastGPT对话应用新建 FastGPT 知识库应用 部署OneAPI 拉取镜像 docker pull justsong/one-api创建挂载目录 mkdir -p /usr/local/docker/oneapi启动容器 docker run --name one-api -d …

解决 Xshell 等工具连接虚拟机失败

这里以 Xshell 等工具连接 Linux 虚拟机为例 对于我们使用 Xshell 等工具连接虚拟机失败&#xff0c;我们可以从以下的几个方面进行检查和解决 检查连接工具中的连接会话配置是否正确 对于这方面&#xff0c;我们要检查连接工具中连接会话配置的虚拟机 IP 地址和端口号是否正…

【数据库管理操作】Mysql 创建学生数据库及对数据表进行修改

MySQL 创建学生成绩数据库 1.创建数据库 create database studentscore;创建完成之后&#xff0c;如果需要使用该数据&#xff0c;使用use命令 use studentscore;创建表前查看当前数据库中包含的表 show tables; 2.创建bclass表 create table bclass( class_id char(8) …

语音情感分类(1)简单可运行项目(附代码)

1.目标 题主最开始是想做一个音乐情感分类的模型&#xff0c;但是查阅相关文献发现这个范围太大了&#xff0c;音乐情感特征包括文本&#xff0c;音频&#xff0c;甚至有的还有画面&#xff0c;是一个多模态的范畴。所以退而求其次&#xff0c;找了一个接近的语音情感分类来学…

Sentry(Android)源码解析

本文字数&#xff1a;16030字 预计阅读时间&#xff1a;40分钟 01 前言 Sentry是一个日志记录、错误上报、性能监控的开源框架&#xff0c;支持众多平台&#xff1a; 其使用方式在本文不进行说明了&#xff0c;大家可参照官方文档&#xff1a;https://docs.sentry.io/platforms…

Jenkins--在Linux上使用Docker安装

一、Jenkins 简介 Jenkins是一个流行的开源自动化服务器&#xff0c;用于持续集成和持续交付&#xff08;CI/CD&#xff09;。Jenkins的核心功能主要包括以下几点&#xff1a; 持续集成&#xff1a;Jenkins可以监控版本控制系统&#xff08;如Git、SVN&#xff09;中的代码变…

RAG进阶笔记:RAG进阶

1 查询/索引部分 1.1 层次索引 创建两个索引——一个由摘要组成&#xff0c;另一个由文档块组成分两步进行搜索&#xff1a;首先通过摘要过滤出相关文档&#xff0c;接着只在这个相关群体内进行搜索 1.2 假设性问题 让LLM为每个块生成一个假设性问题&#xff0c;并将这些问…

U盘未格式化,数据恢复攻略大揭秘

U盘遭遇未格式化困境&#xff0c;数据安全岌岌可危 在日常的工作和生活中&#xff0c;U盘以其便携、容量大的特性成为了我们不可或缺的存储工具。然而&#xff0c;有时我们会遇到这样一个棘手的问题&#xff1a;当我们将U盘插入电脑时&#xff0c;却收到了“未格式化”的提示。…

畅捷通T+ Ufida.T.DI.UIP.RRA.RRATableController 远程命令执行漏洞

一、漏洞信息 漏洞名称&#xff1a;畅捷通T Ufida.T.DI.UIP.RRA.RRATableController 远程命令执行漏洞 漏洞类别&#xff1a;远程命令执行漏洞 风险等级&#xff1a;高危 二、漏洞描述 畅捷通TPlus适用于异地多组织、多机构对企业财务汇总的管理需求&#xff1b;全面支持企…

为什么 Hashtable 不允许插入 null 键 和 null 值?

1、典型回答 浅层次的来回答这个问题的答案是&#xff0c;JDK 源码不支持 Hashtable 插入 value 值为 null&#xff0c;如以下JDK 源码所示&#xff1a; 也就是JDK 源码规定了&#xff0c;如果你给 Hashtable 插入 value 值为 null 就会抛出空指针异常 并目看上面的JDK 源码可…

js算法记录

> 更多请前往 https://www.passerma.com/article/86 滑动窗口 1 给定一个矩阵&#xff0c;包含N*M个整数&#xff0c;和一个包含K个整数的数组。现在要求在这个矩阵中找一个宽度最小的子矩阵&#xff0c;要求子矩阵包含数组中所有的整数 function minSubmatrixWidth(mat…

PCL拟合并绘制平面(二)

使用RANSAC拟合点云平面 1、C实现2、效果图 普通的点云平面拟合方式在一般情况下可以得到较好的平面拟合效果&#xff0c;但是容易出现平面拟合错误或是拟合的平面不是最优的情况。此时就需要根据自己的实际使用情况&#xff0c;调整平面拟合的迭代次数以及收敛条件。 使用RAN…

vue脚手架创建项目:账号登录(利用element-ui快速开发)(取消eslint强制格式)(修改端口号)

新手看不懂&#xff0c;老手不用看系列 文章目录 一、准备工作1.1 取消强制格式检查1.2 导入依赖&#xff0c;注册依赖 二、去element-ui官网找样式写Login组件2.1 引用局部组件2.2 运行项目 三、看一下发现没问题&#xff0c;开始修改前端的代码四、修改端口号4.1 修改后端端口…

一款比 K8S 更好用的编排工具——Nomod 单机部署

上下文 最近公司需要调研类似 EMCHub 这样支持算力共享的服务。第一直觉是使用 K8S 或 K3S&#xff0c;作为 CNCF 孵化的顶级项目&#xff0c;同时也是当前云原生生态使用最广的编排系统。但是在学习 EMC Hub 源码过程中&#xff0c;偶然发现它是基于 Nomad 做的集群管理。 相…