学习笔记|串口通信实战|简易串口控制器|sprintf函数|STC32G单片机视频开发教程(冲哥)|第二十一集(下):串口与PC通信
目录
- 3.串口通信实战
- 实操
- 简易的工作原理
- Tips:sprintf函数简介
- 总结
- 课后练习
3.串口通信实战
做一个简易串口控制器。发送对应指令,让板子做相应的事情,或者传输数据(文本模式下发送,不要选择HEX)。
1.串口发送字符Ax\r\n,(x表示0-7)板子点亮对应LED.\r\n也可以在串口软件中设置自动发送。
2.串口发送Bxxxx\r\n,xxxx表示一个四位数,四位数码管显示这个4位数
2.串口发送Z\r\n,板子给电脑发送“Hello STC”;
3.串口发送字符Cx\r\n,(x表示0-1)板子打开/关闭蜂鸣
4.串口发送字符D\r\n,板子通过串口发送当前温度给电脑。
实操
先把需求复制到demo.c顶部。
为实现功能1,首先要对串口接收进行处理。查看void UART2_int (void) interrupt UART2_VECTOR:
void UART2_int (void) interrupt 8
{if(S2RI) //如果接收到数据,{S2RI = 0; //Clear Rx flagRX2_Buffer[RX2_Cnt] = S2BUF;if(++RX2_Cnt >= UART2_BUF_LENGTH) RX2_Cnt = 0;}if(S2TI){S2TI = 0; //Clear Tx flagB_TX2_Busy = 0;}
}
简易的工作原理
先清空标志位,再把数据存入RX2_Buffer[RX2_Cnt]。S2BUF(写入的数据)不断的存到RX2_Buffer中,这里用到了循环写入的方式,刚刚上电的时候RX2_Cnt是0,
写完后变成了1,变成了2,…,总长度是#define UART2_BUF_LENGTH 128,数组RX2_Buffer的最大长度是128,也就是说写入值超过127以后下一次会重新开始写。
覆盖掉0的参数,再往下写,一个一个的覆盖下去,直到覆盖到最后一个,然后又从头开始。
再去看一下串口发送,在demo.c中,if((TX2_Cnt != RX2_Cnt) && (!B_TX2_Busy)) //收到数据, 发送空闲
如果TX2_Cnt != RX2_Cnt,假设接收的数值是4,则已经写入了4个数据,如果串口发送和串口接收的数值不相等,并且不为忙碌的时候,就可以开始发送数据。
把数据写入 S2BUF,然后他也是跟着跑,每次写入一个数据,RX2CNT是每接收到一个数据,RX2CNT数值加1,加1以后,TX就不等于RX2CNT了,这种情况下,先往上写一个数据,TX2CNT也就可以开始+1,
比如说写入的是4个数据,假设TX2CNT刚上电,初始是0,即满足(TX2_Cnt != RX2_Cnt) && (!B_TX2_Busy)的条件,则先将数据(写入0)先传送出去,写完以后这里还是不等于他,把写入1也写出去,如果说还是不等于,
再接着写出去,这里其实是一个循环的队列,串口在空闲的时候就可以跟着他走,这里就是一个循环队列的演示。
本次只要接收到一个指令就可以。从指令集分析,每次接收到\r\n以后,就可以重新开始计数。
在中断函数void UART2_int (void) interrupt 8中开始改写,如果先接收到了数据,先把接收到的数据存进去,初始化的时候RX2_Cnt = 0;(刚上电的时候这个数值为0)。
添加变量bit Rec_Flag =0; //接收完成标志位。还需要在.h文件中定义一下:extern bit Rec_Flag; 增加extern关键字,主函数中也可以调用。
假设接收到4个字符:

先接收到A以后,没有检测到\r\n,先接收到O以后他也是没有检测到\r\n,直到检测到\n再去判断前一个数值是不是\r,如果有,说明接收完成。
处理代码为:
if( RX2_Buffer[RX2_Cnt] == '\n' ){if( RX2_Buffer[RX2_Cnt-1] == '\r' )Rec_Flag = 1; //接收完成标志位,RX2_Cnt = 0; //接收完成清0}elseRX2_Cnt++;
接收完成后,在主函数里做处理。这里不需要把参数打印出来了,将接收数据处理代码注释掉或者删除。
// if((TX2_Cnt != RX2_Cnt) && (!B_TX2_Busy)) //收到数据, 发送空闲
// {
// S2BUF = RX2_Buffer[TX2_Cnt];
// B_TX2_Busy = 1;
// if(++TX2_Cnt >= UART2_BUF_LENGTH) TX2_Cnt = 0;
// }
通过检测Rec_Flag位,它已经检测到了最末尾的\r\n符号。可以用switch语句,根据RX2_Buffer[0]分情况处理,比较的时候只能是单个变量或者字符:
if(Rec_Flag == 1) //它已经检测到了最末尾的\r\n符号{switch (RX2_Buffer[0]){case 'A':if()break;case 'B':break;case 'C':break;case 'D':break;case 'Z':break;default:break;}Rec_Flag = 0; //执行完后Rec_Flag 清0,防止它反复执行}
下一步,判断第2个字符,根据ASCII码表,第二个数需要大于等于48,小于等于55,则这个数据有效:
if((RX2_Buffer[1] >= 48) && (RX2_Buffer[1] <= 55))
点亮灯执行,LED = (1<<(RX2_Buffer[1] - 48)) ,RX2_Buffer[1] - 48则取至范围变为0-7,如果0左移1位就是点亮LED0,左移7位就是点亮LED1.
case 'A':if((RX2_Buffer[1] >= 48) && (RX2_Buffer[1] <= 55)){LED = (1<<(RX2_Buffer[1] - 48));}break;
编译完,准备去下载。下载完成打开串口助手,发送A0,发现状态反了,很好处理,取反。一定要用全部取反(~):LED = ~(1<<(RX2_Buffer[1] - 48));,不是感叹号!(位取反)。
再来看第二个:
case 'B':SEG0 = RX2_Buffer[1] - 48;SEG1 = RX2_Buffer[2] - 48;SEG2 = RX2_Buffer[3] - 48;SEG3 = RX2_Buffer[4] - 48;break;
编译下载,选择正确的串口号,发送B1234,数码管上显示了1234。
接下来第三个,选项C,如果RX2_Buffer[1]==0,直接控制蜂鸣器的引脚。
case 'C':if(RX2_Buffer[1] == 48)BEEP = 0;elseBEEP = 1;break;
选项D,这里要新学一个函数sprintf。
Tips:sprintf函数简介
详细可参考:sprintf函数用法详解
sprintf函数的原型如下:
int sprintf(char *str, const char *format, …);
其中,str参数是指向存储输出结果的缓存区的指针,必须具有足够的容量来存储输出结果;format参数是格式控制字符串,定义了输出的格式等;其余的…参数是输出结果。
sprintf函数的返回值为输出到缓存区中的字符数量,这个值不包括字符串结尾的’\0’。
本工程中的应用,首先需要引用头文件:#include “stdio.h”。
sprintf函数与printf相比,里面的内容和后面的内容都是不变的,只是前面加了一个,把生成的字符保存到了前面,比如定义数组char str[30];将最终要显示的字符串保存在了之前定义的数组里,
int temp = 26; //这里仅做模拟,每执行一次加1,方便区分。下载执行,输入D点击发送,显示温度:0,温度1,…
再实现命令Z,代码为:PrintString2(“Hello STC!\r\n”);
完整核心代码为:
if(Rec_Flag == 1) //它已经检测到了最末尾的\r\n符号{switch (RX2_Buffer[0]){case 'A':if((RX2_Buffer[1] >= 48) && (RX2_Buffer[1] <= 55)){LED = ~(1<<(RX2_Buffer[1] - 48));}break;case 'B':SEG0 = RX2_Buffer[1] - 48;SEG1 = RX2_Buffer[2] - 48;SEG2 = RX2_Buffer[3] - 48;SEG3 = RX2_Buffer[4] - 48;break;case 'C':if(RX2_Buffer[1] == 48)BEEP = 0;elseBEEP = 1;break;case 'D':sprintf(str,"温度:%d\r\n",temp);PrintString2(str);temp++;break;case 'Z':PrintString2("Hello STC!\r\n");break;default:break;}Rec_Flag = 0; //执行完后Rec_Flag 清0,防止它反复执行}
实际场景下可以做相应的UI界面规划设计,发送相应指令,执行对应程序。下位机做好指令的接收和处理。如果担心数据乱码,可以加入数据校验,判断末尾的值是否和要求的相等,相等说明命令有效。
总结
1.了解串口的接线(TX和RX相连)和扩展(232,485等硬件)
2.学会分析和移植驱动代码。
3.拓展一下sprintf的用法(变量转字符串操作很有用)
4.课外可以自己买几个串口的模块体验一下~
课后练习
用试验箱实现简易串口控制器主机。(可以用本实验性的第二组串口/另外的核心板)
1.按下按钮0-7发送字符Ax\r\n(x表示0-7)
2.按下按钮8发送B0000\r\n
3.按下按钮9发送Z\r\n
4.按下按钮A串口发送字符C0\r\n
4.按下按钮B串口发送字符C1\r\n
4.按下按钮C发送字符Dx\r\n
相关文章:
学习笔记|串口通信实战|简易串口控制器|sprintf函数|STC32G单片机视频开发教程(冲哥)|第二十一集(下):串口与PC通信
目录 3.串口通信实战实操简易的工作原理Tips:sprintf函数简介 总结课后练习 3.串口通信实战 做一个简易串口控制器。发送对应指令,让板子做相应的事情,或者传输数据(文本模式下发送,不要选择HEX)。 1.串口发送字符Ax\…...
卷积神经网络CNN学习笔记-卷积计算Conv2D函数的理解
目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.Conv2D函数解析9.conv2d代码9.1 stride19.2 stride2 参考文章 1.全连接层存在的问题 在全连接层中,相邻层的神经元全部连接…...
收藏,安装报错信息汇总,MacOS上安装Adobe等软件/插件报错问题解决合集
打开允许“允许任何来源” 如何打开允许任何来源?在 Finder 菜单栏选择 【前往】 – 【实用工具 】,找到【终端】程序,双击打开,在终端窗口中输入:sudo spctl --master-disable 输入代码后,按【return 回车…...
Qt 报错:munmap_chunk(): invalid pointer解决方案
问题 在用Qt写程序的时候。报了munmap_chunk(): invalid pointer这个错误消息。 造成原因 在 Qt 程序中,这种错误可能出现在多种情况下,以下几点是容易造成此问题的原因: 函数未实现返回值:函数有返回值,但函数体中…...
【Java题】实现继承和多态的例子
一:题目 1.员工类Employee: (1)私有成员变量:姓名,年龄,工资 (2)提供无参,有参构造 (3)成员方法:work()方法——员工工作 …...
‘conda‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
原因:环境变量没有正确添加解决:我的电脑—右键属性—高级系统设置—环境变量—系统变量—Path—双击进入—新建,去安装Anaconda的目录下,找到Library中的bin,将此时的路径粘贴到此处...
C1N短网址 - 是如何做到行业领先的
今天从技术角度来聊下短网址的一些事情,市面上的短网址发展基本上经历了几个阶段。 短网址发展的几个阶段: 第一阶段:网址缩短,很纯粹的功能,各个大小公司都在做,门槛很低。典型代表:百度短网…...
【UE5】引入C++插件Plugins不在UE里出现
原因 未编译过C 原项目为蓝图项目,或者虽然为C项目,但并为编译过C. 解决 创建一个C脚本,让编辑器重启重新编译一遍。 如还不行,则打开Plugins插件面板,创建一个空的新的插件,再让引擎自动重启重新编译…...
第三部分:JavaScript
一:JavaScript介绍 JavaScript语言诞生主要是完成页面的数据验证。因此它运行在客户端,需要运行浏览器来解析执行JavaScript代码。 JavaScript是Net scape网景公司的产品,最早取名为LiveScript;为了吸引更多的程序员,更…...
Redis 命令—— 超详细操作演示!!!
内存数据库 Redis7 三、Redis 命令3.1 Redis 基本命令3.2 Key 操作命令3.3 String 型 Value 操作命令3.4 Hash 型 Value 操作命令3.5 List 型 Value 操作命令3.6 Set 型 Value 操作命令3.7 有序Set 型 Value 操作命令3.8 benchmark 测试工具3.9 简单动态字符串SDS3.10 集合的底…...
工业自动化控制通信协议Profinet系列-3、CoDeSys软PLC方案介绍
工业自动化控制通信协议Profinet系列-3、CoDeSys软PLC方案介绍 文章目录 工业自动化控制通信协议Profinet系列-3、CoDeSys软PLC方案介绍一、前言二、Profinet搭建资料收集三、CoDeSys系列四、接下来 一、前言 之前在树莓派desktop上已经成功编译运行测试程序,但是还…...
[补题记录] Atcoder Beginner Contest 293(E)
URL:https://atcoder.jp/contests/abc293 目录 E Problem/题意 Thought/思路 Code/代码 E Problem/题意 给出 A、X、M,求 。 Thought/思路 一开始想等比数列求和,但是 m 不保证是质数,所以不能用。 假设 dp[x] 表示&…...
R语言有关模型方面的函数(model.)介绍-model.matrix
R语言有关模型方面的函数(model.)介绍-model.matrix 引言model.matrix简单作用提取设计矩阵对有序因子与无序因子的处理(模型相关)手动编写contr.系列的函数写在最后引言 最近闲暇时间大量阅读了一些机器学习方面的R包源码,在此对阅读过程中的一些实用但是不常见的函数进行…...
owasp top 10
1、访问控制的崩溃: 通过身份验证的用户可以访问其他用户的信息,越权 达成方式:通过修改url、内部应用程序状态或html页面绕过 防范:除了公有资源外,默认情况下拒绝访问,严格判断权限,记录失败的…...
【FreeRTOS】【STM32】06 FreeRTOS的使用-动态创建多任务 FreeRTOS 的启动流程
主要流程参照【FreeRTOS】【STM32】06 FreeRTOS的使用-动态创建单任务 1.定义任务句柄 static TaskHandle_t AppTaskCreate_Handle NULL;2.硬件初始化 略 3.创建具体功能任务函数 见定义任务函数 4.使用xTaskCreate创建任务 xReturn xTaskCreate((TaskFunction_t )AppT…...
10月21日,每日信息差
今天是2023年10月21日,以下是为您准备的13条信息差 第一、东方物探公司与阿里云达成战略合作,逐步助力勘探行业实现智能化、自动化、绿色化和可持续化的目标 第二、九洲集团签约300MW集中式风电项目计划总投资21亿,项目达产后,预…...
C++学习笔记之三(函数指针、调用、动态内存、模板)
C 1、函数&指针1.1、指针函数1.2、函数指针1.2.1、函数指针作为函数的传入参数1.2.2、函数指针作为函数的返回值 2、传递2.1、值传递2.2、址传递2.3、引用传递 3、多态3.1、虚方法和抽象方法 4、动态内存5、模板5.1、函数模板5.2、类模板5.3、内联函数 1、函数&指针 1…...
【LeetCode】57. 插入区间
1 问题 给你一个 无重叠的 ,按照区间起始端点排序的区间列表。 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。 示例 1: 输入:interval…...
实时消息传送:WebSocket实现系统后台消息实时通知
实时消息传送:WebSocket实现系统后台消息实时通知 WebSocket简介基本实现步骤后台服务器后端接口SimpMessagingTemplate MessageDto前端客户端 示例应用 在现代Web应用中,提供实时通知对于改善用户体验至关重要。WebSocket技术允许建立双向通信通道&…...
【MATLAB第79期】基于MATLAB的数据抽样合集(sobol、LHS拉丁超立方抽样、Halton、正交/均匀设计、随机rand函数)
【MATLAB第79期】基于MATLAB的数据抽样合集(sobol、LHS拉丁超立方抽样、Halton、正交/均匀设计、随机rand函数) 一、传统函数 1.指定区间随机生成数据(小数) [a b]区间随机数生成: Aa(b-a)rand(m,n) m:待生成矩阵A…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
