学习笔记|串口通信的基础知识|同步/异步|RS232|常见的串口软件的参数|STC32G单片机视频开发教程(冲哥)|第二十集:串口通信基础
目录
- 1.串口通信的基础知识
- 串口通信(Serial Communication)
- 同步/异步?
- 全双工?
- 常见的串口软件的参数
- 2.STC32的串口通信实现原理
- 引脚选择:实现分时复用
- 模式选择
- 串口1模式1,模式1波特率计算公式
- 3.串口通信代码实现
- 编写串口1通信程序
- 15.5.4 串口2使用定时器2做波特率发生器
- 新建工程16.串口2通信
- 错误排查及代码分析
- 总结
- 课后练习:
1.串口通信的基础知识
百度百科:串口通信的概念
什么是通信?
例如U盘和电脑,我们电脑需要往U盘存东西,而U盘上只有四个触点,除去一个电源一个地,只剩下两个引脚了。此时我们坑定不能像点亮LED那样单纯的给他两个引脚上输出个高低电平就能写数据了对吧。总不至于输出一个高电平就能在U盘里写入“STC32位8051单片机就是牛!”这么一句话了吧。
通信指设备之间通过一定的协议进行的信息交换。

每次发送一位数据的称为串行通信,多位(严格来说是2位以上)一起传输的称为并行通信。
今天要讲的串口通信是串行通信的其中的一种!也是1位1位的往外发数据,不是像这个图一样8位一起发。
stc共有4个串口!串口1/2和3/4的主要区别在这里,这节课主要讲异步串口。


串口通信(Serial Communication)
是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。

同步/异步?
异步方式(使用较多):

①以字符为单位传送信息。
②相邻两字符间的间隔是任意长。
③因为一个字符中的比特位长度有限,所以需 要的接收时钟和发送时钟只要相近就可以。
④异步方式特点简单的说就是:字符间异步,字符内部各位同步。
同步方式:

①以数据块为单位传送信息。
②在一个数据块(信息帧)内,字符与字符间无间隔。
③因为一次传输的数据块中包含的数据较多,所以接收时钟与发送进钟严格同步,通常要有同步时钟。
全双工?

常见的串口软件的参数
这里的4个数据发送端和接收段必须严格保持一致。否则接收到的就是乱码。
●波特率?
例如9600的波特率意味着每秒钟可以发9600位的数据。

我们这里起始位就是一个位(一个二进制的一个数0或者1),1bit的变量。中间有8个数据为,然后校验位,停止位。速度9600即每秒最快可以发960个这种包,
●数据位? 有几个2进制位的数据
●校验位?
●停止位?


●传输距离
通信距离很短,如何解决?
以下分别为RS232,RS422,RS485的通信原理图。



串口的逻辑电平只有5V或者3.3V,如果单片机是5V供电,逻辑电平只有5V(高电平),因为电平比较低,传输距离受限,
●串口有什么用

2.STC32的串口通信实现原理
引脚选择:实现分时复用

模式选择


每一种模式的配置参考手册,这里不再复述。这里主要讲串口1的模式1(应用最广泛)。
串口1模式1,模式1波特率计算公式
当软件设置SCON的SMO、SM1为“01”时,串行口1则以模式Ⅰ进行工作。此模式为8位UART格式,一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位。波特率可变,即可根据需要进行设置波特率。TxD为数据发送口,RxD为数据接收口,串行口全双工接受/发送。
模式Ⅰ的发送过程:串行通信模式发送时,数据由串行发送端TxD输出。当主机执行一条写SBUF的指令就启动串行通信的发送,写“SBUF”信号还把“1”装入发送移位寄存器的第9位,并通知TX控制单元开始发送。移位寄存器将数据不断右移送TxD端口发送,在数据的左边不断移入“O”作补充。当数据的最高位移到移位寄存器的输出位置,紧跟其后的是第9位“1”,在它的左边各位全为“0”,这个状态条件,使TX控制单元作最后一次移位输出,然后使允许发送信号“SEND”失效,完成一帧信息的发送,并置位中断请求位TI,即 TI=1,向主机请求中断处理。
模式1的接收过程:当软件置位接收允许标志位.REN,即REN=1时,接收器便对RxD端口的信号进行检测,当检测到RxD端口发送从“1”→“O”的下降沿跳变时就启动接收器准备接收数据,并立即复位波特率发生器的接收计数器,将IFFH装入移位寄存器。接收的数据从接收移位寄存器的右边移入,已装入的IFFH向左边移出,当起始位"0O"移到移位寄存器的最左边时,使RX控制器作最后一次移位,完成一帧的接收。若同时满足以下两个条件:
·RI=0;
. SM2=0或接收到的停止位为1。
则接收到的数据有效,实现装载入SBUF,停止位进入RB8,RI标志位被置l,向主机请求中断,若上述两条件不能同时满足,则接收到的数据作废并丢失,无论条件满足与否,接收器重又检测RxD端口上的"1"→"0"的跳变,继续下一帧的接收。接收有效,在响应中断后,RI标志位必须由软件清0。通常情况下,串行通信工作于模式1时,SM2设置为"0"。

串口1的波特率是可变的,其波特率可由定时器1或者定时器2产生。当定时器采用IT模式时(12倍速),相应的波特率的速度也会相应提高12倍。


模式2和模式3,大同小异,不深入展开。
3.串口通信代码实现


RXD和TXD接在了P4.6跟P4.7上,使用的是串口2。
编写串口1通信程序
打开手册15.5 范例程序
15.5.4 串口2使用定时器2做波特率发生器

新建工程16.串口2通信
复制"15.NTC温度采集"工程为"16.串口2通信",HARDWARE目录中新建usart子目录,并将usart文件夹加入include,新建usart2.c和usart2.h,:
插入头文件模板,并修改。
先编写初始化函数声明:void Usart2_Init(void);,入口参数肯定是无。函数实现(先把官方例程的初始化抄写过来):
#define BRT (65536 - (MAIN_Fosc / 115200+2)/4) //加2操作是为了让Keil编译器自动实现四舍五入运算void Usart2_Init(void)
{P_SW2 = 0X80; //0X80=1000 0000S2CFG = 0X01;S2CON = 0X50;T2L = BRT;T2H = BRT>>8;T2x12 = 1;T2R =1;wptr = 0x00;rptr = 0x00;busy = 0;
}
串口要用到主频,将该定义从demo.c中移动到usart2.h中。单独写在串口里面。
初始化代码中有三个小写的变量,属于用户定义变量,需要增加定义。另外,在头文件中也要增加定义(主函数中也会使用到这些变量),使用extern关键字。
extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];
编写中断服务函数,中断函数的名字可以任意取,只要后面的中断号无错误即可。
增加发送函数Usart2_Send和void Usart2_SendStr(char *p),并在头文件中声明。
在主函数中删除上节课无用内容,再调用串口初始化,demo.c中while循环内的usb串口部分可以注释掉,本节不使用。
时间部分可以留着,方便计时。
修改后的源代码如下。
demo.c中的main函数部分:
void main() //程序开始运行的入口
{sys_init(); //USB功能+IO口初始化usb_init(); //usb库初始化delay_ms(500);Timer0_Init(); //定时器0初始化Usart2_Init(); //串口初始化IE2 = 0X01;EA = 1; //CPU开放中断,打开总中断。Usart2_SendStr("Usart2 Test !\r\n");while(1) //死循环{if( TIM_10MS_Flag==1 ) //如果10ms到了{TIM_10MS_Flag = 0; //清空标志位}if (rptr != wptr){Usart2_Send(buffer[rptr++]); //字符发送rptr &= 0x0f;}}
}
Usart2.c:
#include "usart2.h"#define BRT (65536 - (MAIN_Fosc / 115200+2)/4) //加2操作是为了让Keil编译器自动实现四舍五入运算bit busy;
char wptr;
char rptr;
char buffer[16];void Usart2_Init(void)
{P_SW2 = 0X80; //0X80=1000 0000S2CFG = 0X01;S2CON = 0X50;T2L = BRT; //BRT为宏定义,T2H = BRT>>8;T2x12 = 1;T2R =1;wptr = 0x00;rptr = 0x00;busy = 0;
}void Usart_Isr() interrupt 8
{if( S2TI ){S2TI = 0;busy = 0;}if( S2RI ){S2RI = 0;buffer[wptr++] = S2BUF;wptr &= 0X0F;}
}void Usart2_Send(char dat)
{while(busy);busy = 1;S2BUF = dat;
}void Usart2_SendStr(char *p)
{while(*p){Usart2_Send(*p++);}
}
Usart2.h:
#ifndef __USART2_H
#define __USART2_H#include "COMM/stc.h" //调用头文件
#include "COMM/usb.h"#define MAIN_Fosc 11059200UL //定义为无符号长整型,避免计算溢出//------------------------引脚定义------------------------////------------------------变量声明------------------------//extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];//------------------------函数声明-----------------------//
void Usart2_Init(void);
void Usart2_Send(char dat);
void Usart2_SendStr(char *p);#endif
编译成功,下载进去看一下。注意,这里的时钟选择11.0592。使用串口线(使用usb转串口线usb-RS232),按要求接线,并选择正确的串口。

错误排查及代码分析
下载完成后,无反应,看一下代码,在执行主函数之前就应该执行串口发送,但是串口工具里无变化,检查串口工具参数设置,
都是对的,回过头看手册,查找问题原因,先找到初始化Usart2_Init,在手册中使用高级搜索功能,查找P_SW2:

找到定义:3.1.2 外设端口切换控制寄存器2(P_sW2):

使能访问XFR,EAXFR在sys_init中已经使能:EAXFR = 1; //扩展寄存器(XFR)访问使能,所以P_SW2 = 0X80; 不使用也是可以的。
查看S2_S:串口2功能脚选择位,开发板上的串口2需切换到P4.6和P4.7引脚上,S2_S位应置为1,这里可以使用或等于,在不影响最高位的情况下,设置S2_S位,即增加:P_SW2 |= 0X01;
再查找S2CFG,目录对应项跳转至:15.4.3 串口⒉配置寄存器(S2CFG)。这里设置W1为1,解释:W1:当需要使用串口2时,此位必须设置为“1”,否则可能会产生不可预期的错误。若不需使用串口
2,则不用特别设置W1。
搜索S2CON,跳转至15.4.1串口2控制寄存器(S2CON)。

S2CON = 0X50; //0X50=01010000,设置为模式1:可变波特率8位数据方式,S2REN=1:允许串口接收数据
T2L,T2H是定时器相关设置,串口需要用到1个定时器来生成波特率,也就是作为一个基准时钟。具体设置为:首先它传入的是一个数组
T2L = BRT; //BRT为宏定义,T2H = BRT>>8;T2x12 = 1;T2R =1;
接下来是3个变量。如果说TI需要发送数据,发送完了以后把这个变量给他清零。发送时先检测一下busy,如果等于1,说明上次的数据还没有发完,阻塞,继续等待。
如果发送完了,先把busy置1,然后把数据写入S2BUF的位里面,之后开始发送,看一下手册15.3.6串口1模式1,模式1波特率计算公式中的时序图,和串口2同理,数据发送完之后,才会变成高电平,

也就是执行if( S2TI ):S2T:串口2发送中断请求标志位。在模式0中,当串口发送数据第8位结束时,由硬件自动将S2TI置1,向主机请求中断,响应中断后S2TI必须用软件清零。在其他模式中,则在停止位开始发送时由硬件自动将S2TI置1,向CPU发请求中断,响应中断后S2TI必须用软件清零。满足条件后S2TI清0,这个BUSY其实是个忙碌标志位。也就是等于0的时候他才能发送数据,把数据直接写进S2BUF寄存器中就可以自动发送。S2BUF进行读操作,实际是读取串口接收缓冲区,对S2BUF进行写操作则是触发串口开始发送数据。
void Usart2_SendStr(char *p) //发送整个字符。while(*p)可以用这个判断他这个字符是否为空,这里用到了一个指针的技巧,首先传入的是一个数组或者说是地址,把里面的数不断发送出去,直到发送至最后一位。发完之后结束。这样写以后,如果想发字符串只要在双引号内写入即可。
接收到8位数值后,RI会变高,进入中断,if( S2RI ),进入后先清0,将读到的数据存入,只会把地址加1,也就是接收到的数值位数。每接收到1个就加1,接收到的最大值是0x0f=16。
接下来,demo.c中判断:if (rptr != wptr),如果rptr不等于tptr,那就就将rptr的数值不断累加,然后直到等于这个数值。
可以看到,分析过程代码段中仅增加了1行:P_SW2 |= 0X01; //开发板上的串口2需切换到P4.6和P4.7引脚上。
重新编译,手动下载,可以看到数值显示了,需要打印的参数显示出来了,也可以再把需要的数据写进去,可以回显出来,可以试试。
这里的演示功能仅为上电显示一段文字,运行过程中发送什么文字,返回显示同样的文字。重点需要注意默认选择的引脚。写的时候一定要按照实际电路引脚去写。
总结
1.学会串口的一专业名词。
2.学会串口的配置和使用(也可以去学习一下试验箱代码,里面的代码非常全面)
总共有4个串口,例程包里4个串口都有示例代码,基本上所有用的的代码均已涵盖,示例里的初始化也写的非常详细,可以选择不一样的定时器,只有定时器2可以同时为4个串口作为波特率发生器,
课后练习:
1.串口发送字符Ax\r\n,(x表示0-7)板子点亮对应LED
2.串口发送Bxxxx\r\n,xxxx表示一个四位数,四位数码管显示这个4位数
2.串口发送Z\r\n,板子给电脑发送“Hello STC”;
3.串口发送字符Cx\r\n,(x表示0-1)板子打开/关闭蜂鸣
4.串口发送字符Dx\r\n,板子通过串口发送当前温度给电脑。
能独立做出这个实验的话,说明你已经快出师了。
相关文章:
学习笔记|串口通信的基础知识|同步/异步|RS232|常见的串口软件的参数|STC32G单片机视频开发教程(冲哥)|第二十集:串口通信基础
目录 1.串口通信的基础知识串口通信(Serial Communication)同步/异步?全双工?常见的串口软件的参数 2.STC32的串口通信实现原理引脚选择:实现分时复用模式选择串口1模式1,模式1波特率计算公式 3.串口通信代码实现编写串口1通信程序…...
JAVA String 和 String[][]互转的两种方法
第一种方法: <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.40</version> </dependency>字符串转数组: String s "[[22,23,23],[1,10,20]]"…...
推荐几个制作svg的工具
以下是一些用于制作SVG(可缩放矢量图形)的工具和软件,适用于不同技能级别和需求: Adobe Illustrator:作为业界标准之一,Adobe Illustrator是功能强大的矢量图形编辑软件,适用于专业设计师和创意…...
Java实现防重复提交,使用自定义注解的方式
目录 1.背景 2.思路 3.实现 创建自定义注解 编写拦截器 4.使用 5.验证...
Springboot实现Web组件注册
一、前言 在实际开发中,有时候我们可能使用springboot注册web组件,实现某些功能,比如我们需要生成一些api来提供对外的服务,而对应的路径其实是不固定的,那么这种情况下,其实是可以通过这种方式来注册web组…...
Element组件案例 Vue路由 前端打包部署步骤
目录 Element组件案例案例需求与分析环境搭建整体布局顶部标题左侧导航栏核心-右侧导航栏表格编写表单编写分页工具栏编写 异步数据加载异步加载数据性别展示修复图片展示修复 Vue路由Vue路由简介Vue路由入门 打包部署前端工程打包部署前端工程nginx介绍部署 Element组件案例 …...
mysql5.7停止维护时间
mysql5.7将于2023年10月停止官网支持和更新;老项目要准备升级,新项目的mysql必须是mysql8.0(2023-10) 官方升级咨询地址 oracle官方升级咨询地址https://go.oracle.com/LP116153?elq_mid247718&sh1518132002061316121320310…...
解密.kat6.l6st6r勒索病毒:保护数据的关键方法
导言: 网络威胁如雨后春笋,而 .kat6.l6st6r 勒索病毒则是其中一个异常狡猾的恶棍。本文91数据恢复将深入探讨 .kat6.l6st6r 勒索病毒的特点、数据恢复方法以及如何有效地预防这一数字威胁。 数据的重要性不容小觑,您可添加我们的技术服务号&a…...
Godot 添加信号
前言 Godot 里面C#和GDScirpt 的用法完全不一样,网上相关资料太少了。 什么是信号 信号分为信号源,触发,目的节点。信号源在某些条件下触发信号,比如按钮点击,鼠标悬停等事件 #mermaid-svg-wyr9ARVcBFmUUu8y {font-…...
JS如何判断文字是否溢出(被ellipsis)?
如果想要文本超出宽度后用省略号省略,只需要加上以下的css就行了。 .ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap; }3行css搞定,但是问题来了:如果我们想要当文本被省略的时候,也就是当文本超出指定…...
pb:常用函数和语句清单
pb:常用函数和语句清单 PB中提供了600多个函数,这还没有将B/S开发、数据窗口对象中的函数计算在内。但是,只要掌握、熟练运用、真正理解下面的这些函数(包括部分语句)就可以开发软件项目了。这些函数和语句是我给学员讲课时开发的一个完整的管理系统(提供了MIS必须的完整模…...
(8)SpringMVC中的视图类型及其特点,以及视图控制器view-controller的配置
SpringMVC的视图 转发和重定向的区别及其原理,参考文章 视图类型及特点 视图的作用就是将Model中的数据渲染到页面上并展示给用户,SpringMVC中视图对应的View接口有三种实现类对应三种视图解析器 默认有转发视图InternalResourceView和重定向视图RedirectView以及Thymeleaf…...
ansible学习笔记分享
yum install ansible -y #安装,注意yum源问题 yum源: yum install epel-release -y mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.bak >> /dev/null yum clean all rpm -Uvh http://mirrors.ustc.edu.cn/epel/epel-releas…...
以dzzoffice为例设置通过 SOCKET 连接 SMTP 服务器发送(支持 ESMTP 验证)
在测试dzzoffice的过程中,需要配置邮件服务器,dzzoffice的邮件设置有三种选项: 1、通过 PHP 函数的 sendmail 发送(推荐此方式) 2、通过 SOCKET 连接 SMTP 服务器发送(支持 ESMTP 验证) 3、通过 PHP 函数 SMTP 发送 Email(仅 Windows 主机下有…...
加拿大艾伯塔省执法部门利用OpenText Encase显着提高案件效率
艾伯塔省执法部门利用OpenText Encase显着提高案件效率 Internet Child Exploitation Unit (ICE) 使用OpenText EnCase Forensic 加快结案进度并起诉更多罪犯 挑战 从证据收集到报告和起诉的过程非常耗时; 需要工具帮助快速可靠地收集、分析和存储数字证据。 结果 显著提高案…...
【Codeforces】Educational Codeforces Round 156 [Rated for Div. 2]
hh第一次记录cf。 复盘 ab题目比较清晰,只开了这两题,后面看了下cd,即使开了翻译也看不懂题目是什么意思,最后放弃睡觉了。。 a是一道思维题,翻了下别人写的发现大家写的各不相同hh b是一道数学题,过程有点…...
结合swagger的前端架构小记
1.引言 开发中,我们是否经常遇到以下痛点: 项目越大,启动和热更新越来越慢,启动都要花个3-5分钟以上没有类型,接口返回的Object不拿到真实数据都不知道有哪些字段需要手动写很多request函数去调用api,手动…...
Python字典全解析:从基础到高级应用
更多资料获取 📚 个人网站:涛哥聊Python 字典是一种强大而多才多艺的数据类型,它以键-值对的形式储存信息,让我们能够以惊人的效率处理和管理数据。 字典能够将键和值关联在一起,使得数据的存储和检索变得非常高效。…...
Fourier变换中的能量积分及其详细证明过程
Fourier变换中的能量积分及其详细证明过程 在使用Fourier变换分析信号时候,有时需要用到能量积分。本文对Fourier变换的能量积分进行分析。 一、Fourier变换中的能量积分 若 F ( ω ) F [ f ( t ) ] F(\omega)\mathscr F[f(t)] F(ω)F[f(t)],则有 ∫…...
保护 Web 服务器安全性
面向公众的系统(如 Web 服务器)经常成为攻击者的目标,如果这些业务关键资源没有得到适当的保护,可能会导致安全攻击,从而导致巨大的财务后果,并在客户中失去良好的声誉。 什么是网络服务器审核 当有人想要…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
