学习笔记|串口通信的基础知识|同步/异步|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,板子通过串口发送当前温度给电脑。
能独立做出这个实验的话,说明你已经快出师了。

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

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

相关文章

前端 | AjaxAxios模块

文章目录 1. Ajax1.1 Ajax介绍1.2 Ajax作用1.3 同步异步1.4 原生Ajax 2. Axios2.1 Axios下载2.2 Axios基本使用2.3 Axios方法 1. Ajax 1.1 Ajax介绍 Ajax: 全称(Asynchronous JavaScript And XML),异步的JavaScript和XML。 1.2 Ajax作用 …

vue3+elementPlus:el-tree复制粘贴数据功能,并且有弹窗组件

在tree控件里添加contextmenu属性表示右键点击事件。 因右键自定义菜单事件需要获取当前点击的位置&#xff0c;所以此处绑定动态样式来控制菜单实时跟踪鼠标右键点击位置。 //html <div class"box-list"><el-tree ref"treeRef" node-key"id…

python+selenium实现UI自动化(入门篇)

一、基础准备。 python环境安装&#xff0c;参考&#xff1a;CSDN pycharm安装&#xff0c;参考&#xff1a;CSDN 谷歌浏览器驱动配置&#xff0c;参考&#xff1a;CSDN二、新建pycharm项目 截图中&#xff0c;上面是项目地址&#xff08;可以提前在指定位置创建文件夹&#xf…

Redis 主从复制及哨兵模式

目录 1 Redis 主从复制 1.1 主从复制的作用 1.2 主从复制流程 2 搭建Redis 主从复制 2.1 安装 Redis 2.2 修改 Redis 配置文件&#xff08;Master节点操作&#xff09; 2.3 修改 Redis 配置文件&#xff08;Slave节点操作&#xff09; 2.4 验证主从效果 3 Redis 哨兵模…

数据结构——排序算法(C语言)

本篇将详细讲一下以下排序算法&#xff1a; 直接插入排序希尔排序选择排序快速排序归并排序计数排序 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某写关键字的大小&#xff0c;按照递增或递减0排列起来的操作。 稳定性的概念…

JAVA开发中常用RDMS

一、前言 JAVA的开发离不开数据库的支持&#xff0c;常见的有关系型数据库和非关系型数据库。java除了处理不依赖与数据库的通信技术。很多的java项目或者应用程序都需要建立在数据库的基础上。所以java开发早已经不是单纯的java开发&#xff0c;更多的是基于对数据的处理&…

一文教你如何快速备考云计算HCIE 3.0 !

大家好&#xff0c;在誉天实验辅导老师的耐心帮助下&#xff0c;本人在9月21日的云计算HCIE 3.0考试已顺利通过&#xff0c;很高兴有这个机会给大家分享备考的经历&#xff0c;希望对还在备考的同学能有一定的帮助。 备考准备 在云计算HCIE3.0的课程学习结束之后&#xff0c;就…

一款构建Python命令行应用的开源库

1 简介 当我们编写 Python 程序时&#xff0c;我们经常需要与用户进行交互&#xff0c;接收输入并输出结果。Python 提供了许多方法来实现这一点&#xff0c;其中一个非常方便的方法是使用 typer 库。typer 是一个用于构建命令行应用程序的 Python 库&#xff0c;它使得创建命令…

使用MATLAB进行傅里叶变换

1、定义 T1;% 周期0-1 N20;% 最大谐波 k-N:N;% -20:20——-20表示a_(20)e^(j*20*w0*t) N1length(k);%N141 % ceil(N1/2)21%即21是N1的中位数tlinspace(0,T,100); Ntlength(t); ttlinspace(-4*T,4*T,1024); Nttlength(tt);2、原函数 w02*pi/T; % 0-T xt(t>T/4).* 1.0; fig…

嵌入式学习笔记(49)由I2C学通信时序

10.2.1什么是时序&#xff1f; 字面意思&#xff0c;时序就是时间顺序&#xff0c;实际上在通信中时序就是通信线上按照时间顺序发生的电平变化&#xff0c;以及这些变化对通信的意义就叫时序。 10.2.2 I2C总线空闲状态、起始位、结束位 (1)I2C总线上有1个主设备&#xff0c…

二叉树的顺序存储——堆——初识堆排序

前面我们学过可以把完全二叉树存入到顺序表中&#xff0c;然后利用完全二叉树的情缘关系&#xff0c;就可以通过数组下标来联系。 但是并不是把二叉树存入到数组中就是堆了&#xff0c;要看原原来的二叉树是否满足&#xff1a;所有的父都小于等于子&#xff0c;或者所有的父都…

2023年铷铁硼行业分析:低端供应过剩,高性能材料供应不足[图]

铷铁硼材料是一种Fe基磁性材料&#xff0c;主要由钕铁硼按一定比例组成的四方晶体结构&#xff0c;其中Fe元素约占总质量的三分之二&#xff0c;Nd元素约占总量的三分之一&#xff0c;而B等含量最少&#xff0c;约占1%。铷铁硼是现今磁性最强的永久磁铁&#xff0c;也是最常使用…

记录vue开发实例

封装的表格组件 <template><div><div style"width: 100%" v-if"showList"><el-table v-loading.lock"loading" :data"dataList":header-cell-style"{background: #F2FCFE,fontSize: 14px,color: #50606D}&…

sed 命令

sed是Stream Editor&#xff08;字符流编辑器&#xff09;的缩写&#xff0c;简称流编辑器。 sed 命令是一个面向行处理的工具&#xff0c;它以“行”为处理单位&#xff0c;针对每一行进行处理&#xff0c;处理后的结果会输出到标准输出stdout。sed 命令是很懂礼貌的一个命令&…

【微服务】七. http客户端Feign

7.1 基于Feign远程调用 RestTimeplate方式调用存在的问题 先来看以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http://userservice/user"order.getUserId(); User user restTemplate.getForObject(url,User.class);存在下面的问题&#xf…

世界前沿技术发展报告2023《世界信息技术发展报告》(六)网络与通信技术

&#xff08;六&#xff09;网络与通信技术 1. 概述2. 5G与光通讯2.1 美国研究人员利用电磁拓扑绝缘体使5G频谱带宽翻倍2.2 日本东京工业大学推出可接入5G网络的高频收发器2.3 美国得克萨斯农工大学通过波束管理改进5G毫米波通信2.4 联发科完成全球首次5G NTN卫星手机连线测试2…

SpringBoot, EventListener事件监听的使用

1、背景 在开发工作中&#xff0c;会遇到一种场景&#xff0c;做完某一件事情以后&#xff0c;需要广播一些消息或者通知&#xff0c;告诉其他的模块进行一些事件处理&#xff0c;一般来说&#xff0c;可以一个一个发送请求去通知&#xff0c;但是有一种更好的方式&#xff0c;…

【WinRAR】去除请购买WinRAR许可

新建rarreg.key文件 在WinRAR安装目录新建rarreg.key文件&#xff0c;文件内容如下: RAR registration datawncnUnlimited Company LicenseUID1b064ef8b57de3ae9b5264122122509b52e35fd885373b214a4a64cc2fc1284b77ed14fa2066ebfca6509f9813b32960fce6cb5ffde62890079861be57…

Win11右键恢复Win10老版本

Win11右键恢复Win10老版本 最近自己更新了windows11的OS,整体感觉都是不错的,但是就是每次右键菜单我都要再次点击下展开更多选项,这对追求极简主义的我,就是不爽, 手动恢复win10操作吧! 第一种:创建文件(简单快速) 1.新建一个resoreRightKey.reg文件,并在里面填入如下代码 W…

【系统架构】软件架构的演化和维护

导读&#xff1a;本文整理关于软件架构的演化和维护知识体系。完整和扎实的系统架构知识体系是作为架构设计的理论支撑&#xff0c;基于大量项目实践经验基础上&#xff0c;不断加深理论体系的理解&#xff0c;从而能够创造新解决系统相关问题。 目录 1、软件架构演化和定义 …