51单片机之串口通信

目录

1.串口简介

1.1TXD和RXD

1.2通讯接口

1.3通信方式

1.4 51单片机的UART模式

2.串口配置

2.1寄存器简介

        SCON寄存器配置

        PCON配置

2.2代码配置串口

2.2.1  配置串口发送数据

2.2.2配置电脑向单片机发送数据点亮LED


1.串口简介

        串口是一个应用十分广泛的通讯接口,它可以实现两个设备之间的相互通信,大大提高了单片机的硬件实力。前面讲述中断的时候顺便提过51单片机的串口中断,我们使用的51单片机使用的是UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可以实现单片机的串口通信。

1.1TXD和RXD

        简单的两个设备之间的通信可以简化成下面的图:

        VCC与GND的连接就不多说, 主要是为了供电,TXD和RXD需要解释一下:TXD可以展开成Transmit Exchange Data,即传输数据端;RXD可以展开成Receive Exchange Data,即接收数据端。也就是我们使用TXD输出数据,RXD接收数据,实现两个设备之间的相互通信。

1.2通讯接口

        就像学校机房老式台式机就有接口这样一个东西:这就是我们所说的接口

        我们设备之间的通信也是通过接口进行的,像这里列举出的常见的接口:

        UART就是我们单片机上的通讯接口,I2C也是一个常见的接口,未来会接触很多。

        此外,设备之间通信还有CANUSB.USB就是我们常用的一个简单易用的通讯工具,就像我们使用的U盘,USB数据线,很多都是USB通讯使用的。

1.3通信方式

        上面表格里写了通信接口的通信方式,这里介绍一下这个通信方式的意思:

  • 全双工:通信双方可以在同一时刻互相传输数据
  • 半双工:通信双方可以互相传输数据,但必须分时复用一根数据线
  • 单工:通信只能有一方发送到另一方,不能反向传输

1.全双工就类似有两根线 ,像这样:

        因为有两个可以相互通信的通道,所以就可以进行两个设备之间的通信,并且可以在同一时刻进行相互通信

2.半双工就是类似只有一根线,但是却又可以进行两端的通信

        因为只有一个通信的通道,所以两设备之间的通信不能在同一时间完成,需要一次进行一个单方向的通信,完成后才可以进行下一个通信。

3.单工就比较简单了,就是只能进行单方向的通信

        就好比我们的电视机遥控器向电视发送信息,这就是单工。


  • 异步:通信双方各自约定通信速率
  • 同步:通信双方靠一根时钟线来约定通信速率

1.异步就是通信双方互相约定一个速率,让两边设备虽然运作方式不同,但是可以通过约定的规则进行采样获得数据

        比如这里就是对同一个数据不同的采样方式,前一个得到的是1100,后一个得到的是10,再把这个数据变得更加复杂一点,我们使用不同的采样方式,得到的数据会完全不同,所以我们使用异步约定速率还是很重要的,并且一般异步的两个设备是可以不使用线连接的。  

2.同步是双方使用一根时钟线直接约定速率,所以一般同步都是使用线连接的。这里就不多讲


  • 总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)

总线就是一种运输方式,这里只是做一个简单介绍,后面会详细介绍 。

就像是一个大马路连接了路边所有住户,所有设备可以通过这条总线进行相互通信。

1.4 51单片机的UART模式

STC89C52有1个UART

STC89C52的UART有四种工作模式:

  •   模式0:同步移位寄存器
  •   模式18UART,波特率可变(常用)
  •   模式29UART,波特率固定
  •   模式39UART,波特率可变
  •  
    •         波特率又是一个我们经常听到的东西,那么它是什么呢?其实就是一个约定的速率,就是我们串口通信的速率(发送和接收各数据位的间隔时间)

      •         还有检验位是用于数据验证的。打开这个软件

      • 打开

      • 这里有几个校验位:就是用来检测数据的正确性的。

      • 这里主要介绍最常用的两个:奇校验和偶校验

      • 奇校验:

        •         给定一串二进制数据如1001 1100,设置该数据的1的个数为奇数个,如果原本的数据中1的个数就是奇数,那么设置校验位为0,否则设置为1,这里的1001 1100就可以把校验位设置为1,然后再把传输后的数据进行同样的操作,比较校验位是否相同,如果不相同则说传输数据出错了。

      • 偶校验:

        •         和奇校验类似,控制二进制数据中1的个数为偶数个,设置校验位。然后再在传输数据之后设置校验位。

          •         很显而易见的是,奇校验和偶校验是可以一定程度上检验数据的准确性的,但是还是有很多情况是无法检测错误的,比如1111 0011变成1100 0011,这样我们的奇校验和偶校验都无法检验出来。

停止位用于数据帧的间隔,即数据之间有间隔,我们使用停止位来占用这部分位。

8位数据和9位数据格式的区别就是9位数据可以用来设置一位为校验位。

2.串口配置

2.1寄存器简介

        我们这里配置最常见的串口模式——模式1

        这是串口模式配置图,这里有一个很重要的寄存器,就是SBUF寄存器,也叫串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器

        最左边的就是总线,两个不同意义上的SBUF寄存器使用一个总线连接,从输入端进入就会从输出端出。

        其中的这部分是使用定时器1实现的,主要作用就是控制波特率,也就是我们的数据收发速率。

       有了前面配置定时器0的经验,现在我们来配置这个串口的中断也是比较简单的,还是配置一下寄存器和使能还有中断优先级。所以我们来直接看寄存器表格:

        首先来介绍一下SCON寄存器:

        SCON 还是可位寻址,所以我们还是可以直接一位一位的配置这个寄存器。但是我们一般都是直接配置SCON的,如果想要一个一个配也是可以的。

        再来看看PCON寄存器:

        这个寄存器本来是用来控制电源的,但是这里多了两个控制模式的位SMOD和SMOD0,原因就是SCON寄存器的位满了,而中国PCON还有几个空闲的位,所以干脆就直接把这两个模式控制的就放在PCON里了。


        SCON寄存器配置

        我们一般使用的是方式1,所以这里我们要把SM0设为0,SM1设为1。并且,我们需要SM0为方式判断的位,我们还要把PCON中的第六位置为0。

        REN即允许/禁止串口接收数据,我们需要使用软件置位,我们需要使用接收数据就置REN为1,否则我们就置REN为0.

 

TI和RI我们在前面原理图的地方有见到过:

        TI和RI任意一个为1,就会导致跳转到中断函数,其中TI为发送中断请求标志位,RI为接收中断请求标志位。我们需要把这两个在初始时都标为0,然后一般由硬件置为1,当中断启用的时候,我们就必须把它们再次在软件中置为0.

 

        这三个我们是不需要管的,这三个是和方式2和方式3相关联,我们使用的是方式1,所以我们不配置,直接置为0都可以。

        总的来说,如果我们只需要串口发送数据,我们只要把SCON中的SM1置为1,其他的置为0就可以了,这样我们就可以直接配置SCON = 0x40;或者是分开来。如果我们需要串口接收数据,就还要加一个REN = 1,即SCON = 0x50.


        PCON配置

        上面讲到说我们的SCON中需要SM0和SM1共同配置我们的串口运作的方式,而不是用来检测错误,我们就需要把PCON中的第六位置为0.

        所以我们就要把SMOD0 = 0先设好。

        而PCON的第七位SMOD是用来设置方式123的波特率是否加倍:

        这一点我们在原理图上也可以看到: 

        我们让SMOD = 0,就说明我们的波特率需要除以2,也就是我们说的“不加倍”,然后SMOD=1就说明我们的波特率不用除以2,也就是要加倍。


         最后还有几个寄存器就简要介绍一下:

SADEN (Slave Address Enable):SADEN是一个特殊功能寄存器,用于启用或禁用I2C总线中从设备的地址匹配。当SADEN为1时,从设备的地址将参与地址匹配过程;当SADEN为0时,该从设备的地址将被忽略。

SADDR (Slave Address):SADDR是用于设置51单片机作为I2C从设备时的从设备地址。通过配置SADDR,可以将从设备的地址与主设备进行匹配,以便进行通信。SADDR的值可以是7位或10位,取决于所使用的I2C工作模式。

SADEN和SADDR都是用于配置51单片机作为I2C从设备时的地址匹配功能。SADEN用于启用或禁用地址匹配,而SADDR用于设置从设备的地址。这些功能使得51单片机能够与其他I2C设备进行通信。

然后就是老生常谈的IE使能位

        这里我们只要把EA和ES单独拿出来配置就好了,两个为0就禁止中断,两个为1就开放中断,EA主要是针对CPU的中断允许控制,ES则是针对串口的中断允许控制只要我们需要开放中断系统,我们就要把这两个都设置为1.

最后就是IP/IPH配置中断优先级,我们只有一个中断的时候就不用管,不用配置都可以,需要的时候按照下面配置一下就好了:

2.2代码配置串口

2.2.1  配置串口发送数据

        我们先根据上面的介绍,配置一个简单的单片机串口向电脑端发送数据的代码。

        首先,我们讲过,我们如果串口只要发送数据,我们就只要配置SCON为0x40,然后我们的PCON中波特率要加倍就把SMOD配置为1,这里我们就不加倍配置为0,然后SMOD0是控制SCON的SM0和SM1对应模式还是检验的前提,我们需要使用SM0和SM1把串口配置为模式1,所以我们的SMOD0必须为0,至于PCON里的其他配置暂时我们先不考虑,我们一会会通过软件生成

就有:        

SCON = 0x40;

        这里我们只要单片机向电脑发送数据,所以我们不需要使用中断,但是我们发送数据需要一定的波特率即发送的速率,这样的速率需要很精确的时钟计时,否则会发生数据传输出错的严重失误。

        我们在这里就使用定时器实现严格的时序控制,从而确保串口通信的稳定性和可靠性。并且我们需要更加精确的定时器,所以我们这里选择定时器1并且使用8位自动重载实现更加精确的计时。

        但是波特率的配置时比较复杂的,所以我们使用软件工具:

        像这样实现了我们的配置之后,我们就可以把代码复制出来使用了。一般来说,波特率设置越高误差越大,当然这个针对其他频率的51单片机而言的,我们的这个11.0592MHz是非常精确的一个频率,所以我们使用9600就可以了,其他频率的单片机比如12MHz的就需要使用4800在点击波特率加倍来使得这个误差减小,我们的11.0592就直接选9600就好了。

生成代码:

void UartInit(void)		//9600bps@11.0592MHz
{PCON &= 0x7F;		//波特率不倍速SCON = 0x50;		//8位数据,可变波特率AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12TAUXR &= 0xFE;		//串口1选择定时器1为波特率发生器TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xFD;		//设定定时初值TH1 = 0xFD;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1
}

同样的,这里有的东西是需要更改的比如这个AUXR是更高级的单片机寄存器,我们就可以删掉,因为我们单片机没有这个东西,SCON可以配置为0x40,取决于自己的需求。

更改之后代码为:

void UartInit(void)		//9600bps@11.0592MHz
{PCON &= 0x7F;		//波特率不倍速SCON = 0x40;		//8位数据,可变波特率TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xFD;		//设定定时初值TH1 = 0xFD;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1
}

        这里我们设置ET1 = 0是因为我们实现单片机发送数据只需要定时器1作为一个时钟计算波特率,而不需要定时器1实现中断,所以就把它置为0禁止定时器1中断。


        配置好初始化函数,我们就再来配置一个发送数据的子函数,使用这个函数就可以在TI发送标志位被置为1的时候发送数据,并且在函数内把它重新置为0。发送数据要我们把数据发送到SBUF寄存器中。这样一个简单的发送数据的函数就写好了:

void SendByte(unsigned char buffer)
{SBUF = buffer;while(TI== 0);//标志位为0时停留在函数内部TI = 0;//在此处TI变为1,我们需要在函数中将其置为0
}

        注意,我们这里需要发送的数据应该是个8位的二进制,又因为我们在单片机中二级制无法直接表示,所以我们转化成十六进制再发送到SBUF中。

#include <REGX52.H>
void UartInit(void)	
{PCON &= 0x7F;	SCON = 0x50;	TMOD &= 0x0F;	TMOD |= 0x20;	TL1 = 0xFD;	TH1 = 0xFD;	ET1 = 0;		TR1 = 1;		
}void SendByte(unsigned char buffer)
{SBUF = buffer;while(TI== 0);TI = 0;
}void main()
{UartInit();SendByte(0x12);while(1){}
}

        这里就是一个发送0x12的程序,我们这里没有把发送数据的子函数放在while循环中是因为我们把它放在while循环中就会导致一次发太多数据,不好观察,而且会出错,所以我们把它放在while循环前面,并且使用按下单片机上的复位按键来重置发送数据。

然后打开串口调试小助手,看一下发送的是不是对的。

STC-ISP在这里,要注意这些需要注意的东西,而且使用前串口是关闭的,需要我们手动打开串口,这个串口就是我们用来下载程序的CH340驱动的接口。

PZ-ISP就注意这里:

        大部分的都是一样的,只是两个软件不能同时使用,所以需要注意一下

注意:到这里看一下是不是发送的数据都是想要的值,如果按下复位键还是没有显示,检查一下是不是开启的是字符发送,需要改成HEX才可以看的到,或者是串口没有打开。这里如果显示的和自己的不太一样,检查一下波特率设置是否正确,如果还是不一样,建议重新生成代码,并且检查是不是选择的是定时器1的8位自动重载模式。

如果想要把发送的函数放在while循环中,可能会出现发送的数据不对的情况,这个可能是因为发送的速度太快,可以在函数后面加个Delay函数试试。

2.2.2配置电脑向单片机发送数据点亮LED

        还是按照上面的流程,我们直接在工具里生成代码:这里把多余的寄存器AUXR删除,其他的就不要变了,SCON保持0x50

        或者是直接把前面的代码复制下来,直接把SCON改成0x50也可以

void UartInit(void)		//9600bps@11.0592MHz
{PCON &= 0x7F;		//波特率不倍速SCON = 0x50;		//8位数据,可变波特率TMOD &= 0x0F;		//清除定时器1模式位TMOD |= 0x20;		//设定定时器1为8位自动重装方式TL1 = 0xFD;		//设定定时初值TH1 = 0xFD;		//设定定时器重装值ET1 = 0;		//禁止定时器1中断TR1 = 1;		//启动定时器1
}

        然后这里我们还需要配置串口中断,注意:是串口的中断而不是定时器的中断,即我们的电脑向单片机发送数据之后,单片机接收到这个串口数据的那一时刻,就处理这个信息让这个LED点亮,使用串口的中断会更好实现一点。

        主要是这里几个寄存器,IE使能中,我们只要设置EA和ES为1允许中断即可。

        于是就写好了初始化函数:

void UartInit(void)	
{PCON &= 0x7F;	SCON = 0x50;	TMOD &= 0x0F;	TMOD |= 0x20;	TL1 = 0xFD;	TH1 = 0xFD;	ET1 = 0;		TR1 = 1;	EA = 1;ES = 1;
}

然后是中断函数:

        查询中断号,我们可以知道我们要使用的是4号中断。

开始配置函数:

void UART_Routine() interrupt 4
{if(RI == 1){P2 = SBUF;RI = 0;}
}

然后我们使用电脑端发送数据就可以控制我们的单片机LED了。这里注意我们要控制这个RI的取值在为1的时候才算接收到数据,之后就要把它重新置为0

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

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

相关文章

数据恢复与数据取证的便携工具:PC-3000 Portable III

天津鸿萌科贸发展有限公司从事数据安全业务20余年&#xff0c;在数据恢复、数据取证、数据备份等领域有丰富的案例经验、前沿专业技术及良好的行业口碑。同时&#xff0c;公司面向取证机构及数据恢复同行&#xff0c;提供实验室建设方案&#xff0c;包含数据恢复与数据取证硬件…

怎么把学浪的视频保存到手机

越来越多的人在学浪app里面购买了课程并且想要下载下来&#xff0c;但是苦于没有方法或者工具&#xff0c;所以本文将教大家如何把学浪的视频保存到手机随时随地的观看&#xff0c;再也不用担心课程过期的问题。 本文将介绍工具来下载&#xff0c;因为下载方法太复杂&#xff…

4.6java学习总结

内部类(补充) 局部内部类 如果在外界定义会检测不到你所定义的局部内部类,直接报错. public class Main {public static void print(int age,int b){class person{int age;public person(int age) {this.age age;}void show(){System.out.println("内部类输出: "a…

鸿蒙学习记录

问题小测记录 总结链接&#xff1a;小测总结 学习笔记&#xff1a;鸿蒙开发学习记录 1、 main_pages.json存放页面page路径配置信息。 2、在stage模型中&#xff0c;下列配置文件属于AppScope文件夹的是&#xff1f; app.json5 3、module.json5配置文件中&#xff0c;包含…

34-4 CSRF漏洞 - CSRF跨站点请求伪造

一、漏洞定义 CSRF(跨站请求伪造)是一种客户端攻击,又称为“一键式攻击”。该漏洞利用了Web应用程序与受害用户之间的信任关系,通过滥用同源策略,使受害者在不知情的情况下代表攻击者执行操作。与XSS攻击不同,XSS利用用户对特定网站的信任,而CSRF则利用了网站对用户网页…

Vue - 你知道Vue中key的工作原理吗

难度级别:中级及以上 提问概率:80% 在Vue项目开发中,并不推荐使用索引做为key,以为key必须是唯一的,可以使用服务端下发的唯一ID值,也不推荐使用随机值做为key,因为如果每次渲染都监听到不一样的key,那么节点将无法复用,这与Vue节…

HCLR-Net: 混合对比学习正则化与局部随机扰动用于水下图像增强

论文地址&#xff1a;https://doi.org/10.1007/s11263-024-01987-y 源码&#xff1a;https://github.com/zhoujingchun03/HCLR-Net 摘要&#xff1a; 由于水下环境复杂多样&#xff0c;导致光吸收、散射和色彩失真等严重退化现象&#xff0c;因此水下图像增强是一项重大挑战…

python 06实验

实验目的 &#xff08;1&#xff09;掌握Python流程控制语句&#xff0c;合理使用循环进行程序设计 &#xff08;2&#xff09;掌握Python数据结构&#xff0c;能熟练运用进行程序设计 &#xff08;3&#xff09;掌握Python的文件读写&#xff0c;能编写读取数据集的程序 1…

html5分步问卷调查表模板源码

文章目录 1.设计来源1.1 问卷调查11.2 问卷调查21.3 问卷调查31.4 问卷调查41.5 问卷调查51.6 问卷调查6 2.效果和源码2.1 完整效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/137454703 html5分…

【Linux】有关时间的命令(date、timedatectl)

专栏文章索引&#xff1a;Linux 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、data命令 1.介绍 2.常用参数 3.常用选项 二、timedatectl命令 1.介绍 2.常用子命令 一、data命令 1.介绍 date命令用于显示或设置系统的时间与日期&#xff0c;语法格式为&a…

影响力营销与AI的结合:Kompas.ai在搭桥角色中的独特价值

在数字化营销的新时代&#xff0c;影响力营销已经成为品牌建立信任和提升市场影响力的有效手段。通过与关键意见领袖&#xff08;KOL&#xff09;的合作&#xff0c;品牌能够利用KOL的信誉和影响力来扩大其市场覆盖范围和提升品牌认知度。然而&#xff0c;寻找与品牌价值观相契…

Embedding:跨越离散与连续边界——离散数据的连续向量表示及其在深度学习与自然语言处理中的关键角色

Embedding嵌入技术是一种在深度学习、自然语言处理&#xff08;NLP&#xff09;、计算机视觉等领域广泛应用的技术&#xff0c;它主要用于将高维、复杂且离散的原始数据&#xff08;如文本中的词汇、图像中的像素等&#xff09;映射到一个低维、连续且稠密的向量空间中。这些低…