51 串行通信
串行口结构
51 单片机内置全双工串行口,主要组成部分:
| 模块 | 说明 |
|---|---|
| 数据缓冲器 SBUF | 发送/接收各一个,共用一个地址 99H |
| 波特率发生器 | 方式 1 和 3 由定时器 T1 溢出率产生 |
| 发送控制器 | 写入 SBUF 即启动发送 |
| 接收控制器 | 接收一帧数据后存 SBUF |
| 移位寄存器 | 串/并转换 |
功能脚:
- TxD(P3.1):发送数据
- RxD(P3.0):接收数据
写数据到 SBUF → 发送完成 → 硬件置 TI=1(中断标志) 收到一帧数据 → 存入 SBUF → 硬件置 RI=1
串口结构

相关寄存器
SBUF — 串行口数据缓冲器(99H)
- 发送 SBUF 和接收 SBUF 物理上是两个独立的寄存器
- 共用一个地址 99H
- 写操作 = 发送,读操作 = 接收
SCON — 串行口控制寄存器(98H,可位寻址)
| 位 | 名称 | 功能 |
|---|---|---|
| 7 | SM0 | 方式选择 |
| 6 | SM1 | 方式选择(与 SM0 组合) |
| 5 | SM2 | 多机通信使能(方式 2/3) |
| 4 | REN | 允许接收(1=允许,需软件置 1) |
| 3 | TB8 | 方式 2/3 的第 9 位发送数据 |
| 2 | RB8 | 方式 2/3 的第 9 位接收数据 |
| 1 | TI | 发送完成标志(必须软件清零) |
| 0 | RI | 接收完成标志(必须软件清零) |
PCON — 电源控制寄存器(87H,不可位寻址)
| 位 | 功能 |
|---|---|
| 7(SMOD) | 波特率加倍位。1 = 方式 1/2/3 波特率加倍;0 = 不变 |
只有 SMOD 位与串口相关。
四种工作方式
| 方式 | 特点 | 波特率 |
|---|---|---|
| 方式 0 | 8 位移位寄存器模式,同步 | 固定: |
| 方式 1 | 10 位异步(8N1),最常用 | 可变: 溢出率 |
| 方式 2 | 11 位异步(9 位数据) | 固定: |
| 方式 3 | 11 位异步(9 位数据) | 可变:同方式 1 |
方式 1 数据帧格式
起始位(0) + 8位数据 + 停止位(1)D0 最低位,先发送最低位,先接收最低位。
波特率配置
方式 1 波特率公式
常用配置(11.0592MHz)
| 波特率 | SMOD | T1 方式 | T1 初值(TH1) |
|---|---|---|---|
| 1200 | 0 | 方式 2 | 0xE8 |
| 2400 | 0 | 方式 2 | 0xF4 |
| 4800 | 0 | 方式 2 | 0xFA |
| 9600 | 0 | 方式 2 | 0xFD |
| 19200 | 1 | 方式 2 | 0xFD |
示例:配置方式 1,波特率 9600
c
TMOD = 0x20; // T1 工作方式 2(8 位自动重装)
TH1 = 0xFD; // 9600 bps
TL1 = 0xFD;
TR1 = 1; // 启动 T1
SCON = 0x50; // 方式 1,允许接收(REN=1)
// SM0=0, SM1=1 → 方式 1
// REN=1 → 允许接收发送 / 接收数据
发送(轮询方式)
c
void UART_SendChar(uchar dat)
{
SBUF = dat; // 写数据到 SBUF,启动发送
while(TI == 0); // 等待发送完成(TI = 1)
TI = 0; // 手动清标志位
}接收(轮询方式)
c
uchar UART_RecvChar(void)
{
while(RI == 0); // 等待接收完成(RI = 1)
RI = 0; // 手动清标志位
return SBUF; // 读接收数据
}中断方式
c
void UART_ISR() interrupt 4
{
if(TI)
{
TI = 0; // 清发送标志
// 处理发送完成
}
if(RI)
{
RI = 0; // 清接收标志
dat = SBUF; // 读接收数据
// 处理接收数据
}
}中断服务函数中 TI 和 RI 必须软件清零,硬件不会自动清除!
要点总结
| 要点 | 说明 |
|---|---|
| SBUF 双缓冲 | 发送/接收独立,共用一个地址 |
| TI/RI 清零 | 必须软件清零,中断和查询都需要 |
| 波特率 | 方式 1/3 依赖 T1,推荐 11.0592MHz 晶振 |
| 数据位序 | D0 为最低位,先发低位,先收低位 |
| 中断号 | 串行口中断号为 4 |
题目
51单片机A和51单片机B通过串口通信,A每隔100ms向单片机B发送本人学号的后两位(十进制)。假设晶振频率为11.0592MHz,试编程实现A的功能。
c
#include<reg51.h>
void delayms(unsigned int n) //ms延时函数
{
unsigned int i, j;
for(i=0; i<=n; i++) //延时n个1ms
for(j=0; j<123; j++); //本层循环实现延时1ms
}
void main()
{
SCON = 0x50; // 设置为串口方式1,允许收/发
TMOD = 0x20; // 设置T1为定时方式2,8位初值重装;T1用于产生串口波特率
TL1 = 0xfd;
TH1 = 0xfd; // 9600bps@11.0592MHz 定时初值
TR1 = 1; // 启动T1
while(1)
{
SBUF = 23; // 串口发送学号,假设学号是23
while(TI==0); // 等待发送完成
TI = 0; // 清零TI,便于下一次发送
delayms(100); // 延时100ms
}
}