学习笔记|串口通信实战|简易串口控制器|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…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...