Skip to content

51 串行通信

串行口结构

51 单片机内置全双工串行口,主要组成部分:

模块说明
数据缓冲器 SBUF发送/接收各一个,共用一个地址 99H
波特率发生器方式 1 和 3 由定时器 T1 溢出率产生
发送控制器写入 SBUF 即启动发送
接收控制器接收一帧数据后存 SBUF
移位寄存器串/并转换

功能脚:

  • TxD(P3.1):发送数据
  • RxD(P3.0):接收数据

写数据到 SBUF → 发送完成 → 硬件置 TI=1(中断标志) 收到一帧数据 → 存入 SBUF → 硬件置 RI=1

串口结构

alt text


相关寄存器

SBUF — 串行口数据缓冲器(99H)

  • 发送 SBUF 和接收 SBUF 物理上是两个独立的寄存器
  • 共用一个地址 99H
  • 写操作 = 发送,读操作 = 接收

SCON — 串行口控制寄存器(98H,可位寻址)

名称功能
7SM0方式选择
6SM1方式选择(与 SM0 组合)
5SM2多机通信使能(方式 2/3)
4REN允许接收(1=允许,需软件置 1)
3TB8方式 2/3 的第 9 位发送数据
2RB8方式 2/3 的第 9 位接收数据
1TI发送完成标志(必须软件清零
0RI接收完成标志(必须软件清零

PCON — 电源控制寄存器(87H,不可位寻址)

功能
7(SMOD)波特率加倍位。1 = 方式 1/2/3 波特率加倍;0 = 不变

只有 SMOD 位与串口相关


四种工作方式

方式特点波特率
方式 08 位移位寄存器模式,同步固定:
方式 110 位异步(8N1),最常用可变: 溢出率
方式 211 位异步(9 位数据)固定:
方式 311 位异步(9 位数据)可变:同方式 1

方式 1 数据帧格式

起始位(0) + 8位数据 + 停止位(1)

D0 最低位,先发送最低位,先接收最低位


波特率配置

方式 1 波特率公式

常用配置(11.0592MHz)

波特率SMODT1 方式T1 初值(TH1)
12000方式 20xE8
24000方式 20xF4
48000方式 20xFA
96000方式 20xFD
192001方式 20xFD

示例:配置方式 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
    }
}

Copyright © 2026