1,51 单片机串口 核心基础总览

(1)什么是串口?

STC89C51C 内置 1 个全双工通用异步收发器(UART),是单片机与电脑、传感器、蓝牙模块等设备串行通信的专用硬件。

  • 异步通信:无需时钟线,仅通过两根线完成数据收发
  • 全双工:发送和接收可同时进行,互不干扰
  • 标准引脚:TXD(发送)、RXD(接收)
(2)串口核心参数总览表
通信名称 硬件引脚 中断号 入口地址 核心控制寄存器 中断标志位 波特率发生器 数据缓冲器
串口 UART TXD(P3.1)RXD(P3.0) 4 0023H SCON、PCON、TMOD RI (接收)TI (发送) 定时器 1 (模式 2) SBUF
(3)串口核心特性

<1> 全双工通信:发送、接收可独立同时工作

<2> 4 种工作模式模式 1(8 位 UART)最常用(波特率可变)

<3> 波特率由定时器 1 模式 2(8 位自动重装)生成,精度高

<4>独立收发中断,支持查询方式中断方式

<5> 专属数据缓冲器 SBUF(写 = 发送,读 = 接收)

**<6> 中断标志 RI/TI:**硬件置 1,必须软件手动清零

<7> 支持 9600/4800/2400 等标准波特率(11.0592MHz 晶振最优)

2,核心控制寄存器(表格逐位详解)

(1)SCON 串口控制寄存器(地址:98H,可位寻址)
位序号 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
位符号 SM0 SM1 SM2 REN TB8 RB8 TI RI
功能含义 模式选择 模式选择 多机通信 接收使能1 = 允许接收 发送第 9 位 接收第 9 位 发送完成标志 接收完成标志
(2)PCON 电源控制寄存器
位序号 bit7 bit6~0
位符号 SMOD 保留
功能含义 波特率加倍1 = 加倍,0 = 不加倍
(3)定时器 1 专用寄存器(波特率核心)
寄存器 功能 配置
TMOD 定时器模式 0x20(模式 2,8 位自动重装)
TH1 波特率重装值 9600 波特率 = 0xFD
TL1 自动计数寄存器 与 TH1 赋值相同
TR1 启动定时器 1 = 启动
(4)SBUF 串口数据缓冲器

发送 SBUF:写入数据 → 自动启动发送

接收 SBUF:硬件接收数据 → 读取数据

两个寄存器共用名字 SBUF,硬件自动区分

3,特别注意

  • 一旦把 Timer1 设为串口波特率发生器(模式 2 自动重装):

<1> Timer1 就不能再同时做普通定时器使用了!

<2> Timer1 的中断函数也不能再用了!

  • Timer1 做串口的波特率发生器,它就必须:

<1> 工作在 模式 2(8 位自动重装)

<2> 一直连续、稳定、不停地产生时钟

<3> 不能被打断、不能重新赋值、不能做别的任务

  • 此时你还要用它做普通定时中断,就会:

<1> 波特率错乱

<2> 串口收发失败

<3> 定时不准

<4> 程序直接崩溃

4,串口中断标志 + 查询方法

(1)标志位功能
  • RI:接收完成 → 硬件置 1 → 软件必须清 0
  • TI:发送完成 → 硬件置 1 → 软件必须清 0
(2)查询方式(主程序轮询)
    // 查询接收
    if(RI){
        unsigned char dat = SBUF;
        RI = 0;
    }
    // 查询发送
    if(TI){
        TI = 0;
    }

5,串口中断服务函数

    // 串口中断号:4
    void UART_ISR(void) interrupt 4
    {
        if(RI){       // 接收中断
            // 读取数据
            RI = 0;   // 强制清零
        }
        if(TI){       // 发送中断
            TI = 0;   // 强制清零
        }
    }

6,示例程序

(1)示例 1:查询方式串口收发
    #include <reg52.h>

    // 串口初始化:9600波特率,定时器1模式2
    void UART_Init(void)
    {
        SCON = 0x50;   // 模式1,允许接收
        PCON = 0x00;   // 波特率不加倍
        TMOD = 0x20;   // 定时器1模式2
        TH1  = 0xFD;   // 9600波特率重装值
        TL1  = 0xFD;
        TR1  = 1;      // 启动定时器1
    }

    // 串口发送1字节
    void UART_Send(unsigned char dat)
    {
        SBUF = dat;
        while(!TI);    // 等待发送完成
        TI = 0;        // 清标志
    }

    void main(void)
    {
        unsigned char dat;
        UART_Init();

        while(1)
        {
            if(RI)     // 查询是否收到数据
            {
                dat = SBUF;
                RI = 0;
                UART_Send(dat); // 回发数据
            }
        }
    }
(2)示例 2:中断方式串口收发(推荐)
    #include <reg52.h>
    unsigned char rec_dat;

    void UART_Init(void)
    {
        SCON = 0x50;
        PCON = 0x00;
        TMOD = 0x20;
        TH1  = 0xFD;
        TL1  = 0xFD;
        TR1  = 1;

        ES = 1;   // 开启串口中断
        EA = 1;   // 开启总中断
    }

    // 串口发送函数
    void UART_Send(unsigned char dat)
    {
        ES = 0;
        SBUF = dat;
        while(!TI);
        TI = 0;
        ES = 1;
    }

    // 串口中断服务函数
    void UART_ISR(void) interrupt 4
    {
        if(RI)
        {
            rec_dat = SBUF;
            RI = 0;
            UART_Send(rec_dat); // 接收后自动回发
        }
        if(TI) TI = 0;
    }

    void main(void)
    {
        UART_Init();
        while(1); // 主程序空闲
    }
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐