【蓝桥杯】单片机学习(7)——UART串口通信

UART串口通信

    • 一、基础知识介绍
      • 1、通信方式的分类
      • 2、RS232通信接口
      • 3、UART模块介绍
        • (1)串口控制寄存器SCON(可位寻址)
        • (2)电源控制寄存器PCON(不可位寻址)
        • (3)辅助寄存器AUXR(不可位寻址)
        • (4)数据的发送和接收过程。
        • (5)定时器重载值的计算
    • 二、代码实例(UART+SMG)

一、基础知识介绍

1、通信方式的分类

(1)通信方式可分为并行通信和串行通信。由于并行通信占用资源过多且成本高,故串行通信更为普遍。

  • 并行通信:数据的各个位同时传送,以字节为单位通信。例如P0 = 0xFE,即一次给P0的八个口同时赋值,同时进行信号输出,类似于有8个车道同时可以过去8辆车(直升电梯,一次可以同时运送多个人)。
  • 串行通信:一次只能传送数据的一位。就如同一条车道,车辆只能一辆一辆的过(扶梯)。倘若要发送一个字节0xFE,规定低位在前高位在后,发送方式就是0-1-1-1- 1-1-1-1,一次只能发送一位,一个字节要发送8次。

(2)通信方式从传输方向上又可以分为单工通信、半双工通信和全双工通信三类。

  • 单工通信:只允许一方向另一方传送信息,另一方不能回传信息。电视遥控器,收音机广播使用的都是单工通信。
  • 半双工通信:数据可以在双方之间相互传播,但同一时刻只能其中一方发给另一方。对讲机就是典型的半双工。
  • 全双工通信:发送数据的同时也能够接收数据,两者同步进行。比如电话,说话的同时也能听到对方的声音。

2、RS232通信接口

关于UART模块,STC89C52有两个专门引脚,P3^ 0和P3^ 1,即RXD和TXD。RXD是串行接收引脚,TXD是串行发送引脚。在计算机上一般有个9针的串行接口,如下图:
【蓝桥杯】单片机学习(7)——UART串口通信_第1张图片它的9个引脚分别为:

引脚 1 2 3 4 5 6 7 8 9
定义 载波检测DCD 接收数据RXD 发送数据TXD 数据终端准备好DTR 信号地线 数据准备好DSR 请求发送RTS 清除发送CTS 振铃提示RI

常用的引脚是2、3、5。虽然这三个引脚和单片机上的串口名称相同,却不能直接和单片机的串口连接。因为单片机是正逻辑,而RS-232是负(反)逻辑,即1代表﹣3V ~ ﹣15V电压, 0代表﹢3V~﹢15V电压。所以需要借助一个电平转换芯片MAX232,如下图:
【蓝桥杯】单片机学习(7)——UART串口通信_第2张图片MAX232芯片在这里起到的就是“中间人”的作用,将RS-232电平转换成UART电平,也把UART电平转换成RS-232电平,从而实现标准RS-232接口和单片机UART之间的通信连接。

3、UART模块介绍

由于我们并不关心通信的具体过程,只需一个通信的结果,这意味着我们可以在单片机内部做一个硬件模块,让它自动接收数据,接收完成后,通知我们即可。51单片机的内部也恰好存在这样一个UART模块,UART串口的结构由串行口控制寄存器SCON、发送和接受电路三部分组成,与串口相关的寄存器有SCON、PCON、AUXR

(1)串口控制寄存器SCON(可位寻址)

串行控制寄存器用以选择串行通信的工作方式和某些控制功能。其格式如下:

7 6 5 4 3 2 1 0
符号 SM0 SM1 SM2 REN TB8 RB8 TI RI
  • SM0&SM1:串行口工作方式控制位,共模式0~模式3四种方式。常用的是模式1,即SM0= 0,SM1=1。
  • SM2:多机位通信控制位(极少用),模式1直接清0。
  • REN:串行接收允许位。0—禁止接收;1—允许接收。
  • TB8:模式2和3中要发送的第九位数据(极少用)。
  • RB8:模式2和3要接收的第九位数据(极少用),模式1用来接收停止位。
  • TI:发送中断标志位。发送前必须用软件清零,发送过程中TI保持零电平,发送完一帧数据后,硬件自动置 “1”,如果再发送必须用软件再清零。
  • RI:接收中断标志位。接收前,必须用软件清零,接收过程中RI保持零电平,接收完一帧数据后,硬件自动置“1”,如果再接收必须用软件再清零。

常用的配置是:定时器T1用于波特率发生器,一般使用模式2(8位制动重载),串口为模式1,允许接收。

TMOD =TMOD & 0x0F| 0x20;//T1工作在模式2
SCON = 0x50; //串口工作在模式1,且允许接收

(2)电源控制寄存器PCON(不可位寻址)

电源控制寄存器PCON中的SMOD/PCON.7用于设置方式1、方式2、方式3的波特率是否加倍。PCON = 0x80时,波特率加倍。其他位在这里用不到,先不做介绍。

(3)辅助寄存器AUXR(不可位寻址)

对于IAP15F2K61S2单片机,需要对新增的AUXR寄存器进行配置(注意!!!)各位格式及含义如下:

7 6 5 4 3 2 1 0
符号 T0x12 T1x12 UART_M0x6 T2R T2_C/T RB8 T2x12 SIST2

T0x12:定时器0速度控制位 .清零,传统速度12分频;置1,不分频

T1x12:定时器1速度控制位 .清零,传统速度12分频;置1,不分频

UART_M0x6:串口模式0的通信速度设置位。 清零,传统速度12分频;置1,不分频。

T2R:定时器2允许控制位。清零,不允许T2运行;置1,允许。

T2_C/T:控制定时器2用作定时器或计数器。清零,用作定时器(对内部系统时钟进行计数);置1,用作计数器,对引脚T2/P3.1的外部脉冲进行计数。

T2x12:定时器2速度控制位 .清零,传统速度12分频;置1,不分频

常用的选择是:串口工作在模式1,T1(或者T2)用作波特率发生器,并且采用传统速度12分频。

sfr AUXR = 0x8E ; //首先定义AUXR寄存器
//串口配置函数中
AUXR = 0x00;//如果使用T2作波特率发生器,则写为AUXR = 0x40

如果使用的是CT107D的开发板(蓝桥),忘了这两条语句,烧录完一定是失败的,泪的教训。

(4)数据的发送和接收过程。

以串口工作在模式1为例:UART通信过程中,遵循先低后高的原则(低位先发,高位后发)。例如发送数据0xE4,即0b11100100,先让串行发送引脚TXD拉低电平,持续一段时间后,发送一位0,拉低,持续一段时间,发送0,拉高电平,持续一段时间,发送1…直到8位发送完。1/持续时间即为波特率(baud),也就是发送二进制数据位的速率,串口每秒钟传输的位数。在通信之前,双方约定好波特率,保持一致,即可正常通信。

约定好发送速度后,还需要约定好起始标志和结束标志,不管是提前接收还是延迟接收,都会导致数据传送错误。UART通信中,规定没有通信信号发生时,通信线路保持高电平(发送方和接收方均为高电平)。发送方在发送数据之前,先发一位0表示起始位,然后发送8位数据位(先低后高)(一个字节),之后再发送一位1表示停止位。也就是说,每帧数据由1个起始位 “0”、8个数据位 和1个停止位“1”(共10位)构成,其中起始位和停止位在发送时是自动插入。接收方原本保持高电平,一旦检测到一位低电平,便开始准备接收数据,接收到8位数据位后,检测到停止位,再准备下一个数据的接收。时域示意图如下:
【蓝桥杯】单片机学习(7)——UART串口通信_第3张图片
对于发送引脚而言,左边是先发生的,右边是后发生的,数据位的切换时间分即为波特率分之一秒。

(5)定时器重载值的计算

在具体使用UART模块时,串口的波特率是使用定时器T0中断体现的。硬件串口模块中,有一个专门的波特率发生器用来产生控制波特率,对于STC89C52系列单片机而言,这个波特率发生器只能是定时器T1或T2(需额外配置寄存器),不能是T0,默认使用T1。方式1下的波特率发生器必须使用T1的模式2,即自动重装载模式,定时器T1重载值计算公式为:

TH1=TL1=256 - 晶振值/12/32/波特率

电源管理寄存器PCON的最高位可以把波特率提高一倍,如果PCON |= 0x80,则定时器T1重载值计算公式为:

TH1=TL1=256 - 晶振值/12/16/波特率

关于“16”的解释:接收数据时把一位信号采集16次,取出第7、8、9次数据,如果这三次中有两次是高电平,则认为此位是1,如果两次是0,认为此位是0。这样即使受到干扰读错了一位数据,也依然保证最终结果的正确性。

串口通信的发送和接收电路有两个名称(地址)相同的SBUF寄存器,一个作为发送缓冲,一个作为接收缓冲。相当于有两个门牌号相同的房间,一个只进不出,一个只出不进。相互之间不干扰,实现UART的全双工通信。

二、代码实例(UART+SMG)

代码功能:计算机以十六进制发送数据 ,单片机接收后以十进制在数码管上显示,并且将数据再发送到计算机

#include"reg52.h"

sfr AUXR = 0x8E;

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
 
u8 code SMG[] = {
     0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,
                 0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f}; //共阳数码管显示字符转换表
u8 LedBuff[8] = {
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};      //数码管显示缓冲区
u8 RxdByte = 0;
u8 T0RH = 0;
u8 T0RL = 0;

void Timer0Init(u16 ms);
void T1_UART_Init(u16 baud);
void LedScan();
void main()
{
     
    EA = 1;                      //打开使能总中断
    Timer0Init(1);               //配置T0定时1ms
    T1_UART_Init(9600);            //T1配置波特率为9600
    while(1)
    {
     
        LedBuff[1] = SMG[RxdByte & 0x0F];         //在数码管上显示接收字节的低四位
        LedBuff[0] = SMG[RxdByte >> 4];           //在数码管上显示接收字节的高四位
    }
}

void Timer0Init(u16 ms) //定时器0初始化函数
{
     
    T0RH = (65536 - 11059200/12*ms/1000)/256;     //T0定时器的高8位
    T0RL = (65536 - 11059200/12*ms/1000)%256;     // T0定时器的低8位
    TMOD = (TMOD & 0x0F)|0x01;                    //定时器T0工作在模式1
    TH0 = T0RH;                                   //加载T0重载值
    TL0 = T0RL;
    TR0 = 1;                                      //打开T0定时器
    ET0 = 1;                                      //允许T0中断
}

void LedScan()
{
     
    static u8 i = 0;
    P2 = (P2&0x1f)|0xe0;    //打开段选通道
    P0 = 0xff;              //关闭所有段选,消隐
    P2 = (P2&0x1f)|0xc0;    //打开位选通道
    P0 = 0x01<<i;           //位选
    P2 = (P2&0x1f)|0xe0;    //打开段选通道
    P0 = LedBuff[i];        //段选
    if(i<7)                 //一个扫描循环结束(8位数码管,8ms)
    {
     
        i++;                
    }
    else 
    i = 0;                 //重新开始下一次循环
}

void InterruptTimer0()interrupt 1
{
     
    TH0 = T0RH;             //重新加载重载值
    TL0 = T0RL;             
    LedScan();              //数码管扫描显示
}

void T1_UART_Init(u16 baud) //串口配置函数,baud为通信波特率
{
     
    AUXR = 0x00;
    SCON = 0x50;                       //0101 0000配置串口工作在模式1
    TMOD = (TMOD & 0x0F) | 0x20;       //配置T1工作在模式2
    TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值
    TL1 = TH1;                         //初值等于重载值
    ET1 = 0;                           //T1用作波特率发生器,禁止T1中断
    ES = 1;                            //使能串口中断
    TR1 = 1;                           //启动T1         
}

void InterruptUART()interrupt 4
{
     
    if(RI)                       //接收到字节
    {
     
        RI = 0;                  //手动清零接收中断标志位
        RxdByte = SBUF;          //接收到的数据保存到接收字节变量中
        SBUF = RxdByte;          //接收到的数据再直接发回,提示输入信息是否正确接收
    }
    if(TI)                       //字节发送完毕
    {
     
        TI = 0;                  //手动清零发送中断标志位
    }
}

用到了定时器T0(方式1,16位,用于数码管的扫描),T1(方式2,8位自动重载,用作波特率发生器),T0的中断,UART串口的中断。

串口助手的配置:
【蓝桥杯】单片机学习(7)——UART串口通信_第4张图片实现现象:
【蓝桥杯】单片机学习(7)——UART串口通信_第5张图片【蓝桥杯】单片机学习(7)——UART串口通信_第6张图片注意文本模式和HEX模式的区别。

附录:ASCII字符表
【蓝桥杯】单片机学习(7)——UART串口通信_第7张图片

你可能感兴趣的:(单片机学习(蓝桥),单片机)