欢迎光临
我们一直在努力

单片机:串行接口详解

串行接口详解

    • 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 接收中断标志位。

表 串行口工作方式的选择

SM0SM1方式功能波特率
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所有位被清零。

SCON

3.2 PCON 电源控制寄存器

  • PCON (Power Control Register):字节地址87H,不可按位寻址。主要用于电源控制。

  • SMOD 波特率加倍位

PCON

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

发送过程:

  • 将数据写入发送缓冲器SBUF(例如 SBUF = 0x55;),启动发送。
  • 硬件自动添加起始位和停止位,构成一帧数据,通过TXD引脚串行发送。
  • 一帧发送完毕后,硬件自动置位发送中断标志TI(SCON.1),向CPU申请中断。
  • 必须用软件将TI清零(TI = 0;),才能发送下一帧数据。
  • 接收过程:

  • 将REN(SCON.4)置1,允许接收。
  • 硬件检测RXD引脚,当采样到从1到0的跳变(起始位)时,开始接收一帧数据。
  • 接收完一帧(10位)后,如果满足以下条件,则硬件将接收到的8位数据装入SBUF,并置位接收中断标志RI(SCON.0):
    • RI = 0(上一帧数据已被取走)
    • SM2 = 0 或 接收到的停止位为1(方式1中停止位固定为1,此条件通常满足)
  • 必须用软件将RI清零(RI = 0;),才能接收下一帧数据。
  • 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):

  • 将待发送数据写入SBUF,同时将第9位数据写入TB8。
  • 硬件自动添加起始位、第9位(TB8)和停止位,构成一帧,通过TXD引脚发送。
  • 一帧发送完毕后,硬件置位TI(SCON.1)。
  • 必须用软件将TI清零,才能发送下一帧。
  • 接收过程(方式2/3):

  • 置位REN(SCON.4),允许接收。
  • 硬件检测RXD引脚起始位,开始接收。
  • 接收完一帧(11位)后,硬件将前8位数据存入SBUF,第9位存入RB8,并置位RI(SCON.0)的条件为:
    • RI = 0
    • 且满足以下任一条件:
      • SM2 = 0
      • SM2 = 1 且 RB8 = 1(即接收到地址帧)
  • 必须用软件将RI清零,才能接收下一帧。
  • 6. 编程及应用

    6.1 初始化编程

    51串行口使用之前必须对它进行初始化,设定串口的工作方式和波特率。

    6.1.1 串行口控制器SCON位的确定
  • 工作方式确定SM0、SM1位。
  • 方式2、3还需要确定SM2位。发送数据的第9位写入TB8.
  • 接收端,则REN置1.
  • 初始化TI位和RI位抖音写入0.
  • 6.1.2 波特率
  • 方式0 ,不需要设置波特率
  • 方式2,这种波特率仅需对PCON中SMOD位进行设置。
  • 方式1、3设置波特率。需要设置PCON中的SMOD,还需对定时器T1进行设置,定时器一般工作于方式2(8位自动重置方式)
  • 波特率=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单片机串行接口在不同场景下的具体应用方法,为读者提供了从理论到实践的完整学习路径。

    赞(0)
    未经允许不得转载:171主机测评 » 单片机:串行接口详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址