串行接口详解
-
- 1. 引言
- 2. 结构
- 3. 串行控制接口寄存器
-
- 3.1 SCON 串行口控制寄存器
- 3.2 PCON 电源控制寄存器
- 4. 工作方式
-
- 4.1 方式0(单机)
- 4.2 方式1(双机)
- 4.3 方式2、方式3(多机)
- 6. 编程及应用
-
- 6.1 初始化编程
-
- 6.1.1 串行口控制器SCON位的确定
- 6.1.2 波特率
- 6.2 单机
-
- 6.2.1 参考代码
- 6.2.2 运行效果
- 6.2.2 例2参考代码
- 6.2.3 例2运行效果
- 6.3 双机
-
- 6.3.1 参考代码
- 6.3.2 运行效果
- 6.4 多机
-
- 6.4.1 参考代码
- 6.4.2 运行效果
- 总结
1. 引言
单片机的引脚很珍贵,若传输使用并行通信,那么一次就得消耗8个引脚。所以串行接口与并行接口相比更节省引脚资源。
51系列单片机是一个全双工的串行异步通信接口,可以同时发送、接收数据。
2. 结构
51单片机主要由发送数据寄存器、发送控制器、输出控制们、接收数据寄存器、接收控制器、输入移位寄存器。
- 发送数据寄存器+接收数据寄存器 = 特殊功能寄存器SBUF(串行口数据寄存器)
- 串行口数据寄存器SBUF,字节地址为99H,实际对应两个寄存器,即发送数据寄存器和接收数据寄出去。故能实现全双工通信。
- TI(Transmit Interrupt)
- RI(Receive Interrupt)

3. 串行控制接口寄存器
3.1 SCON 串行口控制寄存器
-
SCON (Serial Port Control Register):字节地址98H,可按位寻址
-
SM0、SM1 串行口工作方式选择位
-
SM2 多机通信控制位
-
REN(receive enable) 允许接收控制位。
-
TB8 (Transmit Bit 8)发送数据的第9位。
-
RB8 接收数据第9位。
-
TI 发送中断标志位
-
RI 接收中断标志位。
表 串行口工作方式的选择
| 0 | 0 | 方式0 | 移位寄存器方式(用于扩展IO口) | fosc/12 |
| 0 | 1 | 方式1 | 8位异步通信方式 | 可变 |
| 1 | 0 | 方式2 | 9位异步通信方式 | fosc/32或fosc/64 |
SM2 多机通信控制位(数据第9位是来判断接收是否有效):
- SM2 = 1 在方式2和方式3接收数据时,RB8 =0 ,接收无效
- SM2 = 1 在方式2和方式3接收数据时,RB8 =1 ,接收有效
- SM2 = 0 无论RB8=1还是RB8 = 1,接收有效
REN, 允许接收控制位(串口通信开关)。当REN=1,则允许接收;当REN=0,则禁止接收。
TB8 发送数据第9位 。方式2和方式3中,TB8为发送数据第9位,它可以作为奇偶校验位。在多机通信中,用来表示主机发送的是地址还是数据:TB=0 为数据,TB8=1为地址。
RB8 接收数据的第9位。在方式2和3中,用于存放数据的第9位。
TI 发送中断标志位。
- 在一组数据发送完后被硬件置位
- 在方式0时,当发送数据第8位结束后,TI置位。
- 在方式123时,当发送数据开始发送停止位时,TI置位。(和上面的对比有微小的差距)
- TI置位,标志着上一个数据发送完成,告诉CPU可以发送下一个数据
- TI不能自动清零,必须用软件清零。
RI 接收中断标志位
- 当数据接收有效后由硬件置位。
- 方式0时,当接收数据的第8位结束后,RI置位
- 方式123时,当接收有效后,RI置位。
- RI不能自动清零,必须用软件清零
系统复位时,SCON所有位被清零。

3.2 PCON 电源控制寄存器
-
PCON (Power Control Register):字节地址87H,不可按位寻址。主要用于电源控制。
-
SMOD 波特率加倍位

4. 工作方式
51单片机有4种工作方式,由串口控制器SCON中的SM0位和SM1位决定。
4.1 方式0(单机)
- 通常用来外接移位寄存器
- 波特率固定fosc/12
- 串行数据通过RXD输入和输出,同步时钟通过TXD输出。
发送过程: 在TI=0时,当CPU执行一条向SBUF写数据的指令时,如 ‘SBUF =i;’,就启动了发送过程。写入发送数据寄存器中的数据按低位在前、高位在后的顺序从RXD 依次发送出去,同步时钟从TXD发送。8位数据(一帧)发送完毕后,由硬件TI置位,向CPU申请重度。如果再次发送数据,必须要用软件(编程)将TI清零,并再次执行写SBUF指令。
接收过程: 在RI=0的条件下,将REN(SCON.4) 置1,启动接收。串行数据通过RXD接收,同步移位脉冲通过TXD输出。在移位脉冲的控制下,RXD上的串行数据一次移入移位寄存器。当8位数据(一帧)全部移入移位寄存器后,接收控制器发出“装载SBUF”的信号,将8位数据并行送入数据缓冲SBUF中。同时,由硬件使接收中断标志RI置位,向CPU申请重度。CPU响应中断后,从接收数据寄存器中取出数据,然后用软件RI复位,使移位寄存器接收下一帧数据。
4.2 方式1(双机)
方式1是10位异步通信方式,也是最常用的双机点对点通信模式。一帧数据包含1位起始位(低电平)、8位数据位(低位在前)、1位停止位(高电平),共10位。
帧格式:
起始位(0) | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | 停止位(1)
波特率: 波特率可变,由定时器T1(通常工作在方式2,即8位自动重装模式)的溢出率决定。计算公式为:
波特率 = (2^SMOD / 32) × (定时器T1溢出率)
其中,SMOD是PCON寄存器的最高位(波特率加倍位)。当SMOD=0时,波特率不加倍;当SMOD=1时,波特率加倍。
典型波特率设置(使用11.0592MHz晶振):
- 9600 bps: TH1 = TL1 = 0xFD, SMOD = 0
- 19200 bps: TH1 = TL1 = 0xFD, SMOD = 1
- 4800 bps: TH1 = TL1 = 0xFA, SMOD = 0
发送过程:
接收过程:
- RI = 0(上一帧数据已被取走)
- SM2 = 0 或 接收到的停止位为1(方式1中停止位固定为1,此条件通常满足)
4.3 方式2、方式3(多机)
方式2和方式3是11位异步通信方式,支持多机通信。它们的主要区别在于波特率:
- 方式2:波特率固定为 fosc/32 或 fosc/64(由PCON寄存器中的SMOD位决定)。
- 方式3:波特率可变,由定时器T1的溢出率决定,计算公式与方式1相同:波特率 = (2^SMOD / 32) × (定时器T1溢出率)。
帧格式: 一帧数据包含1位起始位(低电平)、8位数据位(低位在前)、1位可编程的第9位数据(TB8/RB8)、1位停止位(高电平),共11位。
起始位(0) | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 (TB8/RB8) | 停止位(1)
其中,第9位(D8)在发送时由TB8(SCON.3)提供,在接收时存入RB8(SCON.2)。该位在多机通信中用作地址/数据标识位(TB8=1为地址帧,TB8=0为数据帧),或在单机通信中用作奇偶校验位。
发送过程(方式2/3):
接收过程(方式2/3):
- RI = 0
- 且满足以下任一条件:
- SM2 = 0
- SM2 = 1 且 RB8 = 1(即接收到地址帧)
6. 编程及应用
6.1 初始化编程
51串行口使用之前必须对它进行初始化,设定串口的工作方式和波特率。
6.1.1 串行口控制器SCON位的确定
6.1.2 波特率
波特率=2SMOD × (T1的溢出率)/32
T1的溢出率 = 波特率 * 32/2SMOD
6.2 单机
【例】用51单片机的串行口外接串入并出的芯片74HC164扩展并行输出口控制一组发光二极管,使发光二极管从右至左延时轮流显示。
6.2.1 参考代码
# include <reg51.h>
# include <intrins.h>
void main()
{
unsigned char i;
unsigned int j;
SCON =0x00;//初始化
i = 0xFE;
for(;;)
{
SBUF =i;//串口发送数据
while(!TI){;}//发送中
TI =0;//软件清零TI位
for(j=0;j<=20000;j++)
{
_nop_();
i=_crol_(i,1);
}
}
}
6.2.2 运行效果
【例】用51单片机的串行口外接并入串出的芯片74HC165扩展8位并行输入口,输入一组开关的状态,并通过二极管显示出来。
6.2.2 例2参考代码
# include <reg51.h>
# include <intrins.h>
sbit P2_0 = P2^0;
void main()
{
unsigned char i;
while(1)
{
P2_0 =0;
_nop_();
_nop_();
_nop_();
P2_0 = 1;
_nop_();
_nop_();
_nop_();
SCON = 0x10;//初始化, 接收允许
while(!RI){;}//接收中
RI =0;//软件置位
i = SBUF;
P1=i;
}
}
6.2.3 例2运行效果

6.3 双机
【例】设计双机通信系统。要求:甲机P1口开关的状态通过串行口发送到乙机,乙机接收到后通过P2口的发光二极管显示;乙机P1口开关的状态发送到甲机,甲机接收到后通过P2口的发光二极管显示。
6.3.1 参考代码
# include <reg51.h> // 包含51单片机寄存器定义头文件
void main (void) // 主函数,程序入口
{
unsigned char i; // 定义无符号字符型变量i,用于暂存P1口数据
SP = 0x60; // 将堆栈指针SP设置为0x60,避开默认的00~0x5F区域,防止与工作寄存器区冲突
SCON = 0x50; // 串口控制寄存器初始化:方式1(8位UART,可变波特率),允许接收(REN=1)
TMOD = 0x20; // 定时器模式寄存器设置:定时器1工作于方式2(8位自动重装),用于产生波特率
TL1 = 0xE6; // 定时器1低8位初值,与TH1配合,设置波特率(常见为9600bps @ 11.0592MHz晶振)
TH1 = 0xE6; // 定时器1高8位初值(自动重装载值)
TR1 = 1; // 启动定时器1,开始计数
EA = 1; // 开启总中断(允许所有中断)
ES = 1; // 开启串行口中断(允许串口发送/接收中断)
while(1) // 主循环,无限重复执行
{
P1 = 0xFF; // 将P1口全部置为高电平(即设置为输入状态,读取外部引脚电平)
i = P1; // 读取P1口当前的电平值,存入变量i
SBUF = i; // 将读取到的i值写入串口发送缓冲区,启动串口发送
while(TI == 0); // 等待发送完成标志TI变为1(TI由硬件在发送完成后置1)
TI = 0; // 软件清0发送中断标志,以便下次发送
}
}
void funins(void) interrupt 4 // 串行口中断服务函数,中断号4
{
EA = 0; // 关闭总中断,防止中断嵌套(可选,也可不用)
RI = 0; // 清0接收中断标志,表示已处理接收中断
P2 = SBUF; // 将接收到的数据(SBUF中的值)直接输出到P2口
EA = 1; // 重新开启总中断(恢复中断响应)
}
6.3.2 运行效果

6.4 多机
【例】设计多机通信系统。要求:一台主机,16台从机,从机地址00H~OFH。对于主机,能够根据P1口的四位拨码开关的编码状态从16个从机中选择一个,读取P2开关的状态并从串口发送出去;对于从机,只有被选中的从机可以接收主机发送的开关状态,通过P2口的发光二极管显示。
6.4.1 参考代码
主机代码
# include <reg51.h>
void main(void)
{
unsigned char i;
SCON =0xC0;// 串口控制寄存器设为方式3(9位UART),禁止接收
TMOD =0x20;// 定时器模式寄存器设为定时器1方式2(8位自动重装)
TL1= 0xF3;// 定时器1低8位初值设为0xF3,决定波特率低位
TH1= 0xF3;// 定时器1高8位重装值设为0xF3,决定波特率高位
TR1 = 1;// 启动定时器1,开始产生串口波特率时钟
while(1)
{
P1 =0x0F;// P1口高4位输出0,低4位置1准备读取拨码开关
i = P1;
i = i & 0x0F; // 保留低4位地址,屏蔽高4位无效数据
TB8 = 1;// 第9位设为1,标志当前发送的是地址帧
SBUF =i;// 将地址数据送入发送缓冲区,启动串口发送
while(TI == 0);// 等待发送完成标志TI变为1
TI =0;// 软件清0发送中断标志,准备下次发送
P2 =0xFF;// P2口全部置1,设置为输入状态读取开关
i = P2;// 读取P2口开关状态数据存入变量i
TB8= 0;
SBUF =i;
while(TI ==0);
TI =0;// 软件清0发送中断标志,准备下次发送
}
}
从机代码
# include <reg51.h>
void main(void)
{
unsigned char i,j,k;
SCON = 0xF0;
TMOD = 0x20;
TL1= 0xF3;
TH1= 0xF3;
TR1 = 1;
while(1)
{
P1 = 0x0F;
i = P1;
i = i & 0x0F;
while(RI ==0);
RI = 0;
j = SBUF;
if (j == i)
{
SM2=0;
while(RI == 0);
RI =0;
k=SBUF;
P2 = k;
}
}
}
6.4.2 运行效果

总结
讲解了其核心控制寄存器SCON和PCON的功能与各位定义,特别是工作方式选择位(SM0、SM1)、多机通信控制位(SM2)以及中断标志位(TI、RI)的作用。最后,通过单机扩展I/O、双机数据互传以及一主多从的多机通信三个由浅入深的编程实例,结合完整的C语言代码和运行效果图,直观地展示了51单片机串行接口在不同场景下的具体应用方法,为读者提供了从理论到实践的完整学习路径。



