51单片机——串行口通信

目录

1、51单片机串口通信介绍

2、串行口相关寄存器 

2.1 、串行口控制寄存器SCON和PCON

2.1.1 SCON:串行控制寄存器 (可位寻址)

2.1.2 PCON:电源控制寄存器(不可位寻址)

2.2、串行口数据缓冲寄存器SBUF

2.3、从机地址控制寄存器SADEN和SADDR

2.4、与串行口中断相关的寄存器IE和IPH、IP

2.4.1 IE:中断允许寄存器(可位寻址) 

2.4.2  中断优先级控制寄存器IPH、IP

3、串行口通信实战篇


1、51单片机串口通信介绍

        STC89C52系列单片机内部集成有一个功能很强的全双工串行通信口,与传统8051单片机的串口完全兼容。设有2个互相独立的接收、发送缓冲器,可以同时发送和接收数据。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入,因而两个缓冲器可以共用一个地址码(99H)。两个缓冲器统称串行通信特殊功能寄存器SBUF。
        串行通信设有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。波特率由内部定时器/计数器产生,用软件设置不同的波特率和选择不同的工作方式。主机可通过查询或中断方式对接收/发送进行程序处理,使用十分灵活。
        STC89C52系列单片机串行口对应的硬件部分对应的管脚是P3.0/RxD和P3.1/TxD。
        STC89C52系列单片机的串行通信口,除用于数据通信外,还可方便地构成一个或多个并行I/O口,或作串一并转换,或用于扩展串行外设等。

        了解了51单片机串行通信的大概要点,接下来我们就要进入正题,如何使单片机进行主从机通信呢?当然也是要写驱动程序的,但是该如何写呢?肯定是要对单片机的串行口相关寄存器进行学习的。

2、串行口相关寄存器 

串行口相关寄存器如下表: 

表中其他相关的相信大家都能看得懂,但是这里还是要提一点的是MSB、LSB。

在串行口中,MSB和LSB分别是最高有效位(Most Significant Bit)和最低有效位(Least Significant Bit),它们是对于数据位的描述。
MSB:最高有效位,也被称为高位。在一个多位数据中,MSB是位值最高的一位,其权值最大。
LSB:最低有效位,也被称为低位。在一个多位数据中,LSB是位值最低的一位,其权值最小。
MSB和LSB是用于描述数据位的相对位置的术语。它们在串行通信中往往用于指示数据位从哪一端开始传输。
全称方面,MSB和LSB的全称并没有具体的术语,它们只是描述位的相对位置的标识符。它们的含义在不同的上下文中会有所变化,但通常是通用的、广泛接受的术语。所以这里大家对它有一个概念就行。那么接下来我们就对相关的寄存器进行学习。 

2.1 、串行口控制寄存器SCON和PCON

 STC89C52系列单片机的串行口设有两个控制寄存器:串行控制寄存器SCON和波特率选择特殊功能寄存器PCON。

2.1.1 SCON:串行控制寄存器 (可位寻址)

首先,先来学习SCON串行控制寄存器,SCON是指串行控制寄存器(Serial Control Register)。SCON用于控制和配置串行通信接口的工作模式和参数。具体来说,SCON寄存器通常包含了一些位字段(bits)用于配置串行通信的相关设置,用于选择串行通信的工作方式和某些控制功能。其格式如下:

SM0、SM1——串行口工作模式选择位。

串行口工作模式的作用是定义和控制串行通信的方式和行为,通过选择不同的工作模式,可以适配不同的应用场景和需求,实现灵活的数据传输。通过选择合适的串行口工作模式,可以根据应用需求配置和控制串行通信的参数,实现可靠、高效的数据传输。

SM0和SM1串行口工作模式选择位的使用是需要条件的:

1、当PCON寄存器中的SMOD0/PCON.6位为1时,该位用于帧错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。FE必须由软件清零。

2、当PCON寄存器中的SMOD0/PCON.6位为0时,SM0和SM1一起指定串行通信的工作模式,如下表所示。

其中SM0、SM1按下列组合确定串行口的工作模式: 

简化如下: 

SM0、SM1=00——>方式0——>同步移位寄存器。
SM0、SM1=01——>方式1——>10位异步收发 (8位数据) 波特率可变 (定时器1溢出率控制)。
SM0、SM1=10——>方式2——>11位异步收发 (9位数据) 波特率固定。
SM0、SM1=11——>方式3——>11位异步收发 (9位数据) 波特率可变 (定时器1溢出率控制)。

解读51单片机串行通信4种工作方式:

(1)方式0:同步移位寄存器输入/输出方式,常用于扩展I/O口。波特率固定为振荡频率的1/12,并不受PCON寄存器中SMOD位的影响。

(2)方式1:用于串行发送或接收,为10位通用异步接口。TXD与RXD分别用于发送与接收数据。收发一帧数据的格式为1位起始位、8位数据位(低位在前)、1位停止位,共10位。波特率由定时器T1的溢出率与SMOD值同时决定,即SMOD=1,则波特率加倍;SMOD=0,则波特率不加倍。

(3)方式2:用于串行发送或接收,为11位通用异步接口。TXD与RXD分别用于发送与接收数据。收发一帧数据的格式为1位起始位、8位数据位(低位在前)、1位可编程的第9数据位(也就是1位奇偶校验位)和1位停止位,共11位。波特率取决于PCON中SMOD位的值;即SMOD=1,则波特率加倍;SMOD=0,则波特率不加倍。

(4)方式3:用于串行发送或接收,为11位通用异步接口。TXD与RXD分别用于发送与接收数据。帧格式与方式2相同,波特率与方式1相同。

SM2——多机通信控制位。

SM2:允许方式2或方式3多机通信控制位。在方式2或方式3时,如SM2位为1,REN位为1,则从机处于只有接收到RB8位为1(地址帧) 时才激活中断请求标志位RI为1,并向主机请求中断处理。被确认为寻址的从机则复位SM2位为0,从而才接收RB8为0的数据帧。在方式1时,如果SM2位为1,则只有在接收到有效的停止位时才置位中断请求标志位RI为1;在方式0时,SM2 应为0。

REN——允许串行接收位,由软件置1或者清0。

REN: 允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。

 TB8、RB8——控制和指示串行数据传输。

TB8:TB8(Transmit Bit 8),发送的第9位数据。

在方式2和方式3时,TB8 是要发送的第 9 位数据其值由软件置1或清 0。在双机串行通信时,一般作为奇偶校验位使用;在多机串行通信中用来表示主机发送的是地址顿还是数据,TB8=1为地址,TB8=0为数据。在方式0和方式1中,不使用TB8。

RB8:RB8(Receive Bit 8),接收的第9位数据。

在方式2和方式3时,RB8存放接收到的第9位数据。在方式1时,如SM2=0,RB8 是接收到的停止位。在方式0时,不使用 RB8。

TI ——发送中断标志位,需要在中断服务中软件清0。

TI:发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位。

RI——接收中断标志位,需要在中断服务中软件清0。 

RI:接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1(例外情况见SM2说明),必须由软件复位,即RI=0。

SCON的所有位可通过整机复位信号复位为全“0”。SCON的字节地址尾98H,可位寻址,各位地址为98H~~9FH,可用软件实现位设置。当用指令改变SCON的有关内容时,其改变的状态将在下一条指令的第一个机器周期的S1P1状态发生作用。如果一次串行发送已经开始,则输出TB8将是原先的值,不是新改变的值。
串行通信的中断请求:当一帧发送完成,内部硬件自动置位TI,即TI=1,请求中断处理;当接收完一帧信息时,内部硬件自动置位RI,即RI=1,请求中断处理。由于TI和RI以“或逻辑”关系向主机请求中断,所以主机响应中断时事先并不知道是TI还是RI请求的中断,必须在中断服务程序中查询TI和RI进行判别,然后分别处理。因此,两人中断请求标志位均不能由硬件自动置位,必须通过软件清0,否则将出现一次请求多次响应的错误。 

2.1.2 PCON:电源控制寄存器(不可位寻址)

PCON通常指代特殊功能寄存器(Special Function Register)中的电源控制寄存器(Power Control Register)。电源控制寄存器PCON中的SMOD/PCON.7用于设置方式1、方式2、方式3的波特率是否加倍。

电源控制寄存器格式如下: 

电源控制寄存器与串行口通信相关的位就是B6、B7。

SMOD:波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;SMOD=0,则各工作方式的波特率不加倍。复位时SMOD=0。

SMOD0:帧错误检测有效控制位。当SMOD0=1,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能;当SMOD0=0,SCON寄存器中的SM0/FE位用于SM0功能,和SM1一起指定串行口的工作方式。复位时SMOD0=0。

2.2、串行口数据缓冲寄存器SBUF

对于串行口数据缓冲寄存器SBUF的理解如下:

STC89C52系列单片机的串行口缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。
串行通道内设有数据寄存器。在所有的串行通信方式中,在写入SBUF信号的控制下,把数据装入相同的9位移位寄存器,前面8位为数据字节,其最低位为移位寄存器的输出位。根据不同的工作方式会自动将“1”或TB8的值装入移位寄存器的第9位,并进行发送。串行通道的接收寄存器是一个输入移位寄存器。在方式0时它的字长为8位,其他方式时为9位。当一帧接收完毕,移位寄存器中的数据字节装入串行数据缓冲器SBUF中,其第9位则装入SCON寄存器中的RB8位。如果由于SM2使得已接收到的数据无效时,RB8和SBUF中内容不变。
由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该帧接收结束前从SBUF缓冲器中将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线。

2.3、从机地址控制寄存器SADEN和SADDR

为了方便多机通信,STC89C52系列单片机设置了从机地址控制寄存器SADEN和SADDR。其中SADEN是从机地址掩码寄存器(地址为B9H,复位值为00H),SADDR是从机地址寄存器(地址为A9H,复位值为00H)。这里我们用不到,就不做理解,大概了解就ok了。

2.4、与串行口中断相关的寄存器IE和IPH、IP

2.4.1 IE:中断允许寄存器(可位寻址) 

串行口中断允许位ES位于中断允许寄存器IE中,中断允许寄存器的格式如下:

EA:CPU的总中断允许控制位,EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的中断允许控制位控制。

ES:串行口中断允许位,ES=1,允许串行口中断,ES=0,禁止串行口中断。

2.4.2  中断优先级控制寄存器IPH、IP

IPH代表的是"Interrupt Priority High",IP代表的是"Interrupt Priority"。它们分别对应中断优先级高位寄存器和中断优先级低位寄存器。这两个寄存器用于控制中断的优先级。通过设置IP和IPH寄存器的位,可以确定中断的相对优先级,从而决定中断的触发顺序。注意,当多个中断同时发生时,具有较高优先级的中断将先被处理。 

串行口中断优先级控制位PS/PSH位于中断优先级控制寄存器IP/IPH中,中断优先级控制寄存器的格式如下:

IPH:中断优先级控制寄存器高(不可寻址) 

IP:中断优先级控制寄存器低(可寻址) 

PSH,PS:串口1中断优先级控制位。
当PSH=0且PS=0时,串口1中断为最低优先级中断(优先级0)

当PSH=0且PS=1时,串口1中断为较低优先级中断(优先级1)

当PSH=1且PS=0时,串口1中断为较高优先级中断(优先级2)

当PSH=1且PS=1时,串口1中断为最高优先级中断(优先级3)

3、串行口通信实战篇

我们已经学习了51单片机串行口通信的相关寄存器,接下来,就要把所学知识运用和实战——那就是编写串行口通信的驱动程序,这是最最重要的一步,很多人学会了理论,但是实践一窍不通,要坚决避免要这种情况。首先,我们肯定是要书写串行口的初始化的,但是要从哪一步开始呢?步骤如下:

 第一步:设置串行口控制寄存器SCON:①这里选择串行口工作方式1——>SM0/SCON.7=0,SM1/SCON.6=1;②多机通信控制位不需要——>SM2/SCON.5=0;③允许串行接收位需要(肯定是需要允许串行口处于接收状态的)——>REN/SCON.4=1;④控制和指示串行数据传输不需要——>TB8/SCON.3=0、RB8/SCON.2=0;⑤发送、接收中断标志位初始化需置零——>TI/SCON.1=0,RI/SCON.0=0;综合得:SCON=0x50;如下图:

第二步:设置电源控制寄存器PCON:这里我们需要注意的一点就是串行口与该寄存器有关的就是SMOD/PCON.7、SMOD0/PCON.6;①波特率选择位,选择波特率不加倍——>SMOD/PCON.7=0;②帧错误检测有效控制位,选择SCON寄存器中的SM0/FE位用于SM0功能,和SM1一起指定串行口的工作方式——>SMOD0/PCON.6=0;综合得:PCON&=0x7F(这里使用了位与的表示方法,等同于PCON=0x00);如下图:

第三步:因为串行口通信属于异步通信,通信双方各自约定通信速率,所以需要使用到定时器1溢出率,所以这里我们需要配置定时器1,那就是操作与定时器/计数器有关的两个寄存器——>定时器/计数器控制寄存器TCON、定时器/计数器工作模式寄存器TMOD(这两个寄存器上面没有讲,可以自己查询一下,因为是属于定时器/计数器的内容的)①先配置定时器/计数器控制寄存器TCON;既然用到定时器1,那么肯定是要开启定时器1的——TR

1/TCON.6=1,单纯的用到该位,其他位没有用到,就不需要动了;综合得:TR1=1;如下图:

 ②接下来配置定时器/计数器工作模式寄存器TMOD:GATE/TMOD.7控制定时器1,置1时只有在INT1脚为高及TR1控制位置1时才可打开定时器/计数器1,这里不需要——>GATE/TMOD.7=0;C/T/TMOD.6控制定时器1用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),置1用作计数器(从T1/P3.5脚输入),这里也不需要——>C/T/TMOD.6=0;使用定时器1,并且设定定时器1位8位自动重装方式——>M1/TMOD.5=1,M0/TMOD.4=0;综合得:TMOD=0x20;如下图:

第四步:设定计数寄存器的初值:因为使用的是定时器1,需设定计数寄存器:TL1、TH1的初始值;这里我以单片机晶振为11.0592、波特率为9600bps为例(注意:不同晶振的初始值设定的会有不一样)——>TL1=0xFD、TH1=0xFD;定时器1计数寄存器的初值为:TL1=0xFD;TH1=0xFD;这里无图;

第五步:配置中断允许寄存器IE:①开启CPU的总中断允许控制位——>EA/IE.7=1;②开启串行口中断允许位——>ES/IE.4=1;③禁止定时器1中断——>ET1/IE.3=0;其他位都不需要,全部置零;综合得:IE=0x90(等同于:ET1=0;ES=1;EA=1);如下图:

 综合上述所有步骤,串口初始化,我们将它封装成一个函数,如下:

/**
  * @brief  串口初始化,9600bps@11.0592MHz
  * @param  无
  * @retval 无
  */
void Uart_Init(void)		//9600bps@11.0592MHz
{
    PCON &= 0x7F;		//波特率不倍速
    SCON = 0x50;		//8位数据,可变波特率
    TMOD &= 0x0F;		//清除定时器1模式位(可有可无)
    TMOD |= 0x20;		//设定定时器1为8位自动重装方式(位或也是一样的)
    TL1 = 0xFD;		    //设定定时初值
    TH1 = 0xFD;		    //设定定时器重装值
    TR1 = 1;		    //启动定时器1
    ET1 = 0;		    //禁止定时器1中断
    ES=1;		        //串口中断允许控制位
    EA=1;		        //中断允许总控制位
    //IE=0x90;          //也可这样代替倒数的三个,分别是ET1=0;ES=1;EA=1;
}

串行口数据缓冲寄存器SBUF、从机地址控制寄存器SADEN和SADDR、中断优先级控制寄存器IPH、IP初始化用不到,我们这里不需要配置。

 下面我们开始用我们写好的串行口初始化驱动程序进行实操了,实操内容为:电脑通过串口控制LED;程序如下:

#include <REGX52.H>

/**
  * @brief  串口初始化,9600bps@11.0592MHz
  * @param  无
  * @retval 无
  */
void Uart_Init(void)		//9600bps@11.0592MHz
{
    PCON &= 0x7F;		//波特率不倍速
    SCON = 0x50;		//8位数据,可变波特率
    TMOD &= 0x0F;		//清除定时器1模式位(可有可无)
    TMOD |= 0x20;		//设定定时器1为8位自动重装方式(位或也是一样的)
    TL1 = 0xFD;		    //设定定时初值
    TH1 = 0xFD;		    //设定定时器重装值
    TR1 = 1;		    //启动定时器1
    ET1 = 0;		    //禁止定时器1中断
    ES=1;		        //串口中断允许控制位
    EA=1;		        //中断允许总控制位
    //IE=0x90;          //也可这样代替倒数的三个,分别是ET1=0;ES=1;EA=1;
}
/**
  * @brief  串口发送一个字节数据
  * @param  Byte 要发送的一个字节数据
  * @retval 无
  */
void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;
	while(TI==0);
	TI=0;
}
void main()
{
	Uart_Init();		//串口初始化
	while(1);
}

void UART_Routine() interrupt 4
{
	if(RI==1)					//如果接收标志位为1,接收到了数据
	{
		P2=~SBUF;				//读取数据,取反后输出到LED
		UART_SendByte(SBUF);	//将受到的数据发回串口
		RI=0;					//接收标志位清0
	}
}

 将上面的代码例程的hex文件下载到我们单片机开发板中,就可以通过串口助手发送数据控制单片机的LED的亮灭了,前提是开发板和电脑已经建立起连接了,如下图:

 现象图如下:

通过上例:就发现了串行口数据缓冲寄存器SBUF是如此用的,写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器;意思就是,单片机要接收外部设备发送过来的数据时,就将SBUF赋值给一个变量,就如本例子的:P2=~SBUF; 读取数据,取反后输出到P2口;反之也是,单片机要将数据发送给外部设备,那么就将需要发送的数据赋值给SBUF就可以了,如本例子的:SBUF=Byte;将Byte的值赋值给SBUF就可以了;这个串口数据缓存寄存器就是这么用来着,很简单,相信看了就都懂的,串口通信能做很多有趣的事情,比如我们可以在单片机上装一个蓝牙,然后拿手机来远程控制单片机,这个时候我们就可以拿来做一个遥控小车,手机控制小车等等,具体的拓展看个人;

为了更加方便大家的理解,可以结合下图进行对51单片机串行口的理解:

51单片机串行口发送接收数据数字、字符、符号等等各个进制之间的关系如下图:

突然想到一个问题,最后提醒一下大家,定时器/计数器的工作模式和串行口的工作模式不是同一个概念的,大家不要混淆了,有的人就很容易弄乱的。51单片机串行口就是这么简单,只要把几个相关寄存器的功能作用弄明白了,就按自己需求配置寄存器初始化就可以了。

  • 3
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值