目录
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单片机串行口就是这么简单,只要把几个相关寄存器的功能作用弄明白了,就按自己需求配置寄存器初始化就可以了。