单片机串口接收状态机STM32
单片机串口接收状态机stm32
前言
项目的芯片stm32转国产,国产芯片的串口DMA接收功能测试不通过,所以要由原本很容易配置的串口空闲中断触发DMA接收数据的方式转为串口逐字节接收的状态机接收数据
两种方式各有优劣,不过我的芯片已经主频跑到72m,对于接收115200波特率的数据,绰绰有余。
给一张图,接收状态机就是设置串口每次接收1byte的数据就触发一次中断,在中断函数里面逐次统计数据,最后把有用的数据包放进缓存区给到处理区
1.首先现在cubemx的串口的dma接收关闭,具体配置看截图,然后导出下代码
2.开始配置代码,这里我用的代码编辑器是vscode,个人认为vscode编辑代码+keil调试的方式是最舒服的,有兴趣的可以试试,绝对提一档。
先定义一个uint8_t的变量用来接收每次收到的数据,一定注意,只要你是用的cubemx生成的project,在生成的文件下,都有把你改的代码写到/* USER CODE BEGIN 0 */
下面,不然等你下次在cubemx更改底层配置的时候会把你改好的代码擦洗掉。
uint8_t USART1_rxdata = 0;
往下滑,找到这个串口1的初始化函数,加这个串口接收中断启动函数
HAL_UART_Receive_IT(&huart1, &USART1_rxdata, 1);
然后我们来到中断c文件下,在串口1中断里增加我们的接收状态机
rec_buff_scan(USART1_rxdata); HAL_UART_Receive_IT(&huart1, &USART1_rxdata, 1);
这里的rec_buff_scan就是我们定义的函数,因为我的习惯是在我自己创建的文件下写代码,避免更改cube生成的东西,所以文件名可能就不一样,这里就只看代码就好了
首先先把定义全部cv下来,我们协议是[0XAA,0X55,命令包长度,…(命令包内容),校验和高位,校验和底位,的格式,如果你们的不一样就改下RecState里面的变量名
#define REC_BUFF_SIZE 100
uint8_t rec_buf_scan[REC_BUFF_SIZE]; // 数据接收缓冲区
uint8_t rec_index = 0; // 数据接收索引
extern uint8_t USART1_rxdata; // 存储接收的单个字节// 状态枚举
typedef enum {STATE_WAIT_FOR_HEAD1, // 等待帧头AASTATE_WAIT_FOR_HEAD2, // 等待帧头55STATE_WAIT_FOR_LENGTH, // 等待命令包长度STATE_RECEIVE_DATA, // 接收命令包数据STATE_WAIT_FOR_CHECKSUM1, // 等待校验和字节1STATE_WAIT_FOR_CHECKSUM2 // 等待校验和字节2
} RecState;RecState rec_state = STATE_WAIT_FOR_HEAD1; // 初始状态
uint8_t packet_length = 0; // 数据包长度
uint16_t checksum = 0;
然后把状态机整段cv,状态机就是把接收部分分成一个个的状态,条件符合就会跳到下一段,最后会在校验和验证整段数据是否接收正常,正常的话就会送入数据处理的函数里面,我这里定义了一个rec_buf_scan[REC_BUFF_SIZE]是跟我之前的接收数据缓存区做兼容而已,你们可以只导入数据包的内容,不需要把头和校验和导入,这里其实就是我懒了嘻嘻
我这里的处理其实你们不用借鉴的 ,直接在STATE_WAIT_FOR_CHECKSUM2状态判断校验和成功后,把接收成功flag=true;然后在你另外的处理函数就可以处理数据包了,这里的memcpy一下,也是很有必要的,我们的处理缓存和接收缓存一定要区分开来,因为没有自锁,所以只能在成功的时候把接受的数据塞入处理缓存,至于我这里为什么塞了全部数据而不是只有数据包,主要是配合我以前的处理,无需借鉴,总之你上班就明白我的难处,要改来改去还要兼容是很麻烦的事情
void rec_buff_scan(uint8_t byte) {switch (rec_state) {case STATE_WAIT_FOR_HEAD1:if (byte == 0xAA) {rec_state = STATE_WAIT_FOR_HEAD2;rec_index = 0; // 重置接收索引checksum = 0; // 重置校验和rec_buf_scan[rec_index++] = byte;//可以不用导入}break;case STATE_WAIT_FOR_HEAD2:if (byte == 0x55) {rec_state = STATE_WAIT_FOR_LENGTH;rec_buf_scan[rec_index++] = byte;//可以不用导入} else {rec_state = STATE_WAIT_FOR_HEAD1;}break;case STATE_WAIT_FOR_LENGTH:packet_length = byte;rec_buf_scan[rec_index++] = byte;//可以不用导入rec_state = STATE_RECEIVE_DATA;break;case STATE_RECEIVE_DATA:if (rec_index-3 < packet_length) {//这里if里面的条件把-3去掉 rec_buf_scan[rec_index++] = byte;}if (rec_index-3 == packet_length) {//这里if里面的条件把-3去掉 checksum = Frame_CalculationChecksum(&rec_buf_scan[3], packet_length); // 计算校验和rec_state = STATE_WAIT_FOR_CHECKSUM1;}break;case STATE_WAIT_FOR_CHECKSUM1:if (byte == ((checksum >> 8) & 0xFF)) {rec_state = STATE_WAIT_FOR_CHECKSUM2;rec_buf_scan[rec_index++] = byte;//可以不用导入} else {rec_state = STATE_WAIT_FOR_HEAD1;}break;case STATE_WAIT_FOR_CHECKSUM2:if (byte == (checksum & 0xFF)) {//这里做你自己的处理就好了 ,程序跑到这里就已经验证通过了rec_buf_scan[rec_index++] = byte;//可以不用导入memcpy(&rec_buff[0], &rec_buf_scan[0], rec_index);Device_data.device_state = JUDGE_FLAG;Data_queue_rx.Interrupt_Len = rec_index;}// 无论校验是否通过,回到初始状态rec_state = STATE_WAIT_FOR_HEAD1;break;}
}
用到的Frame_CalculationChecksum函数是校验和计算函数,具体操作就是把接收的数据需要校验的那一段的第一个元素地址放进去,把数据包长度放进去,他会算完把结果返回,我这里就是简单的数据包加和校验
uint16_t Frame_CalculationChecksum(uint8_t *pData, uint8_t u8Length)
{uint16_t u16check_sum = 0;uint8_t i;for (i = 0; i < u8Length; i++){u16check_sum = u16check_sum + pData[i];}return u16check_sum;
}
这样基本上就把接收状态机整完了,可以仿真下试试看。
3.仿真测试
可以看到断点在第二步的时候0xaa已经存入数据缓存去了
同理我们直接看到接收成功这里打断点,可以看到我们在把接收成功时,已经把所有数据都塞进处理缓存区了。这里再严谨点最好是在移完数据后把接收缓存清零一下,但是不清也不影响。
4.小结
串口中断状态机是最基本的协议解析接收方式,作为一个嵌入式人员这个你必须要学会的,写法不限制,但是流程就是跟我的差不多的,具体根据协议来定的。
这种接收方式适合没有dma外设的单片机比如51单片机,国产单片机,在项目开发完成进行降本的时候也是可能会改到这种方式的,如果有不规范的地方请留言,我会更改。
相关文章:

单片机串口接收状态机STM32
单片机串口接收状态机stm32 前言 项目的芯片stm32转国产,国产芯片的串口DMA接收功能测试不通过,所以要由原本很容易配置的串口空闲中断触发DMA接收数据的方式转为串口逐字节接收的状态机接收数据 两种方式各有优劣,不过我的芯片已经主频跑…...
ipv6的 fc00(FC00::/7) 和 fec0(FEC0::/10)
ipv6的 fc00(FC00::/7)(唯一本地地址) 替代了 fec0(FEC0::/10) (站点本地地址,已弃用) ipv6的 fc00(FC00::/7) 替代了 fec0(FEC0::/10) , 在IPv6地址中,FC00::/7(通常简写为FC00)和…...
Chat GPT英文学术写作指令
目录 Chat GPT英文学术写作指令 Chat GPT英文学术写作指令 1."为我捉供一些建议和技巧,以提高我的学术写作质最和风格" (Provide me with some suggestions andtips to improve the quality andstyleofmyacademic writing.) 2."帮我提写一个清晰而有逻辑的…...

超详细Pycharm安装汉化教程,Python环境配置和使用指南,Python零基础入门看这个就够了!
包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】! PyCharm 是由 JetBrains 打造的一款 Python IDE (集成开发环境,Integrated Development Environment),带有一整套可以帮助用户在使用 Py…...
react-native:解决使用webView后部分场景在安卓10崩溃闪退问题
app闪退问题原因: 安卓7以上版本(7和7以下版本不会出现闪退):在屏幕不可视区域加载webView或者webView不在可视区域内切换页面时app崩溃闪退(在屏幕可视区域加载webView或者webView在可视区域内切换页面不会闪退&…...

大数据工具 flume 的安装配置与使用 (详细版)
参考网址:Flume 1.9用户手册中文版 — 可能是目前翻译最完整的版本了 1,上传安装包 安装包链接:文件下载-奶牛快传 Download |CowTransfer 口令:x8bhcg 1,切换盘符到安装目录 cd /opt/moudles 解压文件…...

智慧城市智慧城市项目方案-大数据平台建设技术方案(原件Word)
第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障…...
C语言比较两个字符串是否相同
在不使用string.h中的内置函数的情况下 #include <stdio.h> #include <string.h> void main(){char arr1[]"hello world";char arr2[]"hello world";int i,a0;if(strlen(arr1)!strlen(arr2)){print("不相等");return 0;}for(i0;arr…...

丹摩征文活动|FLUX.1图像生成模型:AI工程师的创新实践
文章目录 一、对"FLUX.1"系列模型版本分析 二、AI工程师与FLUX.1系列模型 三、ComfyUI在线部署四、FLUX.1在线部署五、添加工作流呈现效果图展示六、总结 黑森林实验室(Black Forest Labs)推出的FLUX.1图像生成模型,凭借120亿参数的…...

ZABBIX API获取监控服务器OS层信息
Zabbix 是一款强大的开源监控解决方案,能够通过其 API 接口自动化管理和获取监控数据。在这篇文章中,详细讲解如何通过 Zabbix API 批量获取服务器的系统名称、IP 地址及操作系统版本信息,并将数据保存到 CSV 文件中。本文适合对 Python 编程和 Zabbix 监控系统有一定基础的…...

SpringBoot基础系列学习(五):JdbcTemplate 访问数据库
文章目录 一丶介绍二丶引入依赖三丶配置配置文件四丶创建表五丶java代码 一丶介绍 Spring Boot作为Spring的集大成者,自然会将JdbcTemplate集成进去。Spring Boot针对JDBC的使用提供了对应的Starter包:spring-boot-starter-jdbc,它其实就是在…...

JavaEE-多线程初阶(3)
目录 1.线程的状态 1.1 NEW、RUNNABLE、TERMINATED 1.2 TIMED_WAITING 1.3 WAITING 1.4 BLOCKED 2.多线程带来的风险-线程安全(重点) 2.1 观察线程不安全的现象 2.2 分析产生该现象的原因 2.3 产生线程安全问题的原因 2.3.1 抢占式执行&#x…...
从入门到精通:如何在Vue项目中有效运用el-image-viewer
Element UI之el-image-viewer组件详解 引言 在现代 Web 应用中,高质量的用户体验是不可或缺的一环。Element UI 作为一款基于Vue.js 2.0 的桌面端组件库,以其丰富的组件集、良好的文档和支持赢得了广大开发者的好评。本文将深入探讨el-image-viewer组件,这是一个用于在网页…...

uniapp组件实现省市区三级联动选择
1.导入插件 先将uni-data-picker组件导入我们的HBuilder项目中,在DCloud插件市场搜索uni-data-picker 点击下载插件并导入到我们的项目中 2.组件调用 curLocation :获取到的当前位置(省市区) <uni-data-picker v-slot:defa…...

【C++】异常处理机制(对运行时错误的处理)
🌈 个人主页:谁在夜里看海. 🔥 个人专栏:《C系列》《Linux系列》 ⛰️ 天高地阔,欲往观之。 目录 引言 1.编译器可以处理的错误 2.编译器不能处理的错误 3.传统的错误处理机制 assert终止程序 返回错误码 一、…...
C++ boost steady_timer使用介绍
文章目录 1. 引入必要的头文件2. 基本用法2.1 同步定时器解释:2.2 异步定时器解释:3. 异步定时器与回调函数4. 设置定时器的超时时间4.1 使用秒、毫秒、微秒4.2 修改定时器的到期时间5. 多次使用定时器6. 循环执行任务7. 错误处理总结:C++ Boost 库提供了 boost::asio::stea…...
JVM 由多个模块组成,每个模块负责特定的功能
Java虚拟机(JVM, Java Virtual Machine)是一个抽象的计算机,它提供了一个运行环境,使得Java字节码可以在不同的平台上执行。JVM 由多个模块组成,每个模块负责特定的功能。以下是 JVM 的主要模块及其功能: …...
ORACLE批量插入更新如何拆分大事务?
拆分大事务 一、批量插入更新二、拆分事务之前文章MYSQL批量插入更新如何拆分大事务?说明了Mysql如何拆分,本篇文章探讨Oracle或OceanBase批量插入更新拆分大事务的问题 一、批量插入更新 oracle批量插入更新可使用merge语法eg: merge test ausing test_tmp bon (a.id = b.id…...

kafka+zookeeper的搭建
kafka从2.8版本开始,就可以不用配置zookeeper了,但是也可以继续配置。我目前使用的kafka版本是kafka_2.12-3.0.0.tgz,其中前面的2.12表示是使用该版本的scala语言进行编写的,而后面的3.00才是kafka当前的版本。 通过百度网盘分享…...

Spark中的宽窄依赖
一、什么是依赖关系 这里通过一张图来解释: result_rdd是由tuple_rdd使用reduceByKey算子得到的, 而tuple_rdd是由word_rdd使用map算子得到的,word_rdd又是由input_rdd使用flatMap算子得到的。它们之间的关系就称为依赖关系! 二…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...