4.3 51单片机-串口通信

简介: 4.3 51单片机-串口通信

4.3 串口通信

4.3.1 通信的概念


通信一词按照传统的理解就是信息的传输与交换。


对于单片机来说,通信则与传感器、存储芯片、外围控制芯片等技术紧密结合,成为整个单片机系统的“神经中枢”;没有通信,单片机所实现的功能仅仅局限于单片机本身,就无法通过其它设备获得有用信息,也无法将自己产生的信息告诉其它设备。如果单片机通信没处理好的话,它和外围器件的合作程度就受到限制,最终整个系统也无法完成强大的功能,由此可见单片机通信技术的重要性。


UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。


4.3.2 串口通信介绍


串口通信是按照位(bit)发送和接收,串口可以在使用一根线发送数据的同时用另一根线接收数据;这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。


串口是计算机上一种非常通用的设备通信协议,大多数计算机(不包括笔记本电脑,主要是台式主机)包含两个基于RS-232的串口。串口同时也是仪器仪表设备通用的通信协议。


image.png

上面图中的串行接口叫做 RS232 接口,由于现在笔记本电脑都不带这种 9 针串口了,所以和单片机通信越来越趋向于使用USB协议虚拟的串口(就是使用USB转串口协议芯片,实现串口与USB协议互转,比如:CH340)。 标准的RS232接口里,2号引脚是接收数据口RXD,3号引脚是发送数据TXD,对于 RS232 标准来说,它的TXD 和 RXD 的电压, -3V~-15V 电压代表是 1, +3~+15V 电压代表是 0。 因此电脑的 9 针 RS232串口是不能和单片机直接连接的,需要用一个电平转换芯片 MAX232 来完成,单片机上的电压是TTL标准,TTL电平信号规定,+5V等价于逻辑“1”,0V等价于逻辑“0”。


STC90C51RC/RD+系列单片机串口通信对应的专用管脚是P3.0/RxD和P3.1/TxD,由它们组成的通信接口就叫做串行接口,简称串口。


image.png

图中, GND 表示单片机系统电源的参考地, TXD 是串行发送引脚, RXD 是串行接收引脚。两个单片机之间要通信,首先电源基准得一样,所以要把两个单片机的 GND 相互连接起来,然后单片机1的TXD引脚接到单片机2 的 RXD 引脚上,即此路为单片机 1 发送而单片机 2 接收的通道,单片机 1 的 RXD 引脚接到单片机 2 的 TXD 引脚上,即此路为单片机 2 发送而单片机 1 接收的通道。这个示意图就体现了两个单片机相互收发信息的过程。


当单片机 1 想给单片机 2 发送数据时,比如发送一个 0xE4 这个数据,用二进制形式表示就是 0b11100100,在 UART 通信过程中,是低位先发,高位后发的原则,那么就让 TXD首先拉低电平,持续一段时间,发送一位 0,然后继续拉低,再持续一段时间,又发送了一位 0,然后拉高电平,持续一段时间,发了一位 1……一直到把 8 位二进制数字 0b11100100全部发送完毕。


这里就涉及到了一个问题,就是持续的这“一段时间”到底是多久?由此便引入了通信中的一个重要概念——波特率,也叫做比特率。


波特率就是发送二进制数据位的速率,习惯上用 baud 表示,即发送一位二进制数据的持续时间=1/baud。在通信之前,单片机 1 和单片机 2 首先都要明确的约定好它们之间的通信波特率,必须保持一致,收发双方才能正常实现通信。


约定好速度后,还要考虑第二个问题,数据什么时候是起始,什么时候是结束?不管是提前接收还是延迟接收,数据都会接收错误。在 UART 通信的时候,一个字节是 8 位,规定当没有通信信号发生时,通信线路保持高电平,当要发送数据之前,先发一位 0 表示起始位,然后发送 8 位数据位,数据位是先低后高的顺序,数据位发完后再发一位 1 表示停止位。这样本来要发送一个字节的 8 位数据,而实际上一共发送了 10 位,多出来的两位其中一位起始位,一位停止位。而接收方,原本一直保持的高电平,一旦检测到了一位低平,那就知道了要开始准备接收数据了,接收到 8 位数据位后,然后检测到停止位,再准备下一个数据的接收。


下面图片展示了一个完整的串口数据发送接收过程:

image.png

4.3.3 51单片机的串口寄存器介绍


STC90C51RC/RD+系列单片机内部集成有一个功能很强的全双工串行通信口(P3.0/RxD和P3.1/TxD),与传统8051单片机的串口完全兼容。设有2个互相独立的接收、发送缓冲器,可以同时发送和接收数据。


串行通信设有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,波特率由内部定时器/计数器产生。


4种工作模式,可通过软件编程对SCON中的SM0、 SM1的设置进行选择。其中模式1、模式2和模式3为异步通信,每个发送和接收的字符都带有1个起始位和1个停止位。


发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入,因而两个缓冲器可以共用一个地址码(99H)。两个缓冲器统称串行通信特殊功能寄存器SBUF。


串口相关的配置寄存器如下:

image.png

完成基本串口通信主要使用的寄存器有4个:


SCON: 串行控制寄存器 (可位寻址)


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


IE : 中断允许寄存器 (可位寻址)


SBUF: 发送/接收缓冲区(双向的)


4.3.3 串行控制寄存器SCON


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

image.png

TI: 数据发送完成中断请求标志位,由内部硬件自动置位(TI=1),必须用软件复位(TI=0)。


RI: 数据接收完成中断请求志位,由内部硬件置位,即RI=1,必须由软件复位,即RI=0。


SCON的所有位在复位之后全部为"0"。


REN:允许/禁止串行接收控制位。 由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。


SM0/FE:当PCON寄存器中的SMOD0/PCON.6位为0时,该位和SM1一起指定串行通信的工作方式,如下表所示。

image.png

SCON寄存器主要配置串口的工作方式,启动串口的接收功能,常用的工作模式是方式1(8位UART)。

串口工作在方式1时,波特率是可变的,可变的波特由定时器/计数器1或独立波特率发生器产生

示例:

SCON=0x50;          //设置为工作方式1,允许串口接收

4.3.3 电源控制寄存器PCON

电源控制寄存器PCON格式如下:

image.png

SMOD: 波特率选择位。当SMOD=1,则使串行通信方式1、 2、 3的波特率加倍;复位时SMOD=0。

SMOD0: 帧错误检测有效控制位,当SMOD0=0时,与SCON寄存器中的SM0/FE位一起指定串行口的工作方式。复位时SMOD0=0。

配置示例:

PCON=0x80;          //波特率加倍

4.3.4 串行口数据缓冲寄存器SBUF


STC90C51RC/RD+系列单片机的串行口缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。


示例:

u8 Rx_Byte;
Rx_Byte = SBUF;  //接收到的数据保存到变量中
SBUF = Rx_Byte; //将变量保存的数据发送出去

4.3.5 波特率设置

image.png

image.png

image.png

4.3.6 配置串口实现数据收发示例(波特率不加倍)


下面代码配置串口的波特率为9600,波特率不加倍,当前运行代码的单片机晶振是: 11.059200MHZ。


单片机工作在12T模式下(在12T架构下一个机器周期是12个时钟周期,也就是 12/11059200 秒)


主函数里1秒钟向串口发送一个字符串,串口开启了接收中断,如果收到数据就原样将数据再发送出去。


波特率的配置方法,在STC芯片参考手册的串口章节有示例代码(P199),可以参考修改。


(硬件平台说明:CPU是STC90C516RD 、晶振频率12MHZ 、工作在12T模式下、一个机器周期为1us时间)


示例代码:

#include <reg51.h>
/*串口初始化函数*/
void UART_Init(void)
{
    PCON=0x00;    //波特率不加倍
    SCON=0x50;    //配置串口工作在模式1(8位数据模式)
    EA=1;         //打开总中断
    ES=1;         //打开接收中断
    TMOD&=0x0F;   //清零T1的控制位
    TMOD|=0x20;   //配置T1为模式2 (8位自动重装载)
    TL1=TH1=256-(11059200/12/32/9600); //计算 T1 重载值 28800
    //TH1= TL1=256-(FOSC/12/32/BAUD);  //计算公式  FOSC表示晶振频率  BAUD表示波特率
    TR1=1;        //启动 T1
}
/*串口接收中断*/
void UART_IRQHandler(void) interrupt 4
{
    u8 Rx_Byte;
    if(RI)  //接收到字节
    {
        RI=0;//手动清零接收中断标志位
        Rx_Byte=SBUF;  //接收到的数据保存到变量中
        UART_SendOneByte(Rx_Byte); //再发回给电脑端
    }
}
/*发送一个字符*/
void UART_SendOneByte(u8 c)
{
    SBUF = c;
    while(TI==0){}
    TI = 0;
}
/*发送字符串*/
void UART_SendString(u8 *p)
{
    while(*p++!='\0')
    {
        UART_SendOneByte(*p);
    }
}
int main()
{
    UART_Init();
    while(1)
    {
        UART_SendString("12345欢迎学习51单片机开发.\r\n");
        DelayMs(1000);
    }
}

4.3.7 配置51单片机的串口支持printf函数


下面代码中重写了putchar函数支持了标准的printf函数,因为printf函数底层会调用putchar函数进行字节发送。Keil软件上不需要做任何其他设置。putchar函数原型在stdio.h文件中有原型声明。


如果要支持scanf函数,重写getchar函数即可。


(硬件平台说明:CPU是STC90C516RD 、晶振频率12MHZ 、工作在12T模式下、一个机器周期为1us时间)


示例代码:

#include <reg51.h>
/*串口初始化函数*/
void UART_Init(void)
{
    PCON=0x00;    //波特率不加倍
    SCON=0x50;    //配置串口工作在模式1(8位数据模式)
    //EA=1;       //打开总中断
    //ES=1;       //打开接收中断
    TMOD&=0x0F;   //清零T1的控制位
    TMOD|=0x20;   //配置T1为模式2 (8位自动重装载)
    TL1=TH1=256-(11059200/12/32/9600); //计算 T1 重载值  11956000
    //TH1= TL1=256-(FOSC/12/32/BAUD);  //计算公式  FOSC表示晶振频率  BAUD表示波特率
    TR1=1;        //启动 T1
}
/*发送一个字符*/
void UART_SendOneByte(u8 c)
{
    SBUF = c;
    while(TI==0){}
    TI = 0;
}
/*重写putchar函数为了支持printf函数*/
char putchar(char c)
{
    UART_SendOneByte(c);
    return c;
}
int main()
{
    u8 str[]="我是字符串";
    u32 data1=123456;
    float data2=123.356;
    int data3=0x12345;
    UART_Init();
    while(1)
    {
        printf("字符串:%s\r\n",str);
        printf("data1:%ld\r\n",data1); //这里的u32是typedef unsigned long u32;
        printf("data2:%f\r\n",data2);
        printf("十六进制:%#x\r\n",(int)data3);
        DelayMs(1000);
    }
}

4.3.8 配置串口实现数据收发(12M晶振、波特率加倍)

下面代码配置串口的波特率为4800,单片机晶振的频率为12MHZ。

(硬件平台说明:CPU是STC90C516RD 、晶振频率12MHZ 、工作在12T模式下、一个机器周期为1us时间)

示例代码:

#include <reg51.h>
int main()
{
    u8 key;
    UART_Init();
    while(1)
    {
        key=Array_Scan();
        if(key)
        {
            UART_SendString("12345欢迎学习51单片机开发.\r\n");
        }
    }
}
/*
串口初始化函数
单片机采用了12M的晶振
*/
void UART_Init(void)
{
    PCON=0x80;    //波特率加倍
    SCON=0x50;    //配置串口工作在模式1(8位数据模式)
    EA=1;         //打开总中断
    ES=1;         //打开接收中断
    TMOD&=0x0F;   //清零T1的控制位
    TMOD|=0x20;   //配置T1为模式2 (8位自动重装载)
    TL1=TH1=0xF3;
    //TH1=TL1=256-(FOSC/12/32/BAUD);  //计算公式  FOSC表示晶振频率  BAUD表示波特率
    TR1=1;        //启动 T1
}
/*
串口接收中断
*/
void UART_IRQHandler(void) interrupt 4
{
    u8 Rx_Byte;
    if(RI)  //接收到字节
    {
        RI=0;//手动清零接收中断标志位
        Rx_Byte=SBUF;  //接收到的数据保存到变量中
        UART_SendOneByte(Rx_Byte); //再发回给电脑端
    }
}
/*
发送一个字符
*/
void UART_SendOneByte(u8 c)
{
    SBUF = c;
    while(TI==0){}
    TI = 0;
}
/*
发送字符串
*/
void UART_SendString(u8 *p)
{
    while(*p++!='\0')
    {
        UART_SendOneByte(*p);
    }
}
/*
重写putchar函数为了支持printf函数
*/
char putchar(char c)
{
    UART_SendOneByte(c);
    return c;
}
目录
相关文章
|
9月前
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
83 0
|
9月前
【单片机期中测试】12.串口通信的应用(1)——两台单片机之间的通信
【单片机期中测试】12.串口通信的应用(1)——两台单片机之间的通信
92 0
|
11月前
|
C语言 芯片
51单片机学习--定时器--中断--串口通信
51单片机学习--定时器--中断--串口通信
197 0
蓝桥杯之单片机学习(十二)——串口通信进阶应用案例解析
蓝桥杯之单片机学习(十二)——串口通信进阶应用案例解析
216 0
蓝桥杯之单片机学习(十二)——串口通信进阶应用案例解析
|
缓存
蓝桥杯之单片机学习(十一)——串口通信的基本原理与应用
蓝桥杯之单片机学习(十一)——串口通信的基本原理与应用
298 0
蓝桥杯之单片机学习(十一)——串口通信的基本原理与应用
复习单片机:串口通信(内含:1.代码部分+2.串口内部结构+3.串口控制寄存器 SCON+4.电源控制寄存器 PCON+5. 串口的使用方法+6.硬件设计+7.实验现象)
复习单片机:串口通信(内含:1.代码部分+2.串口内部结构+3.串口控制寄存器 SCON+4.电源控制寄存器 PCON+5. 串口的使用方法+6.硬件设计+7.实验现象)
297 1
复习单片机:串口通信(内含:1.代码部分+2.串口内部结构+3.串口控制寄存器 SCON+4.电源控制寄存器 PCON+5. 串口的使用方法+6.硬件设计+7.实验现象)
|
缓存 开发工具 芯片
单片机:串口通信(内含硬件解析+软件编程)
单片机:串口通信(内含硬件解析+软件编程)
132 0
单片机:串口通信(内含硬件解析+软件编程)