51 串口通信

51 串口通信


串口是一种应用广泛的通讯接口,成本低、易使用,可用于实现两个设备之间的互相通信

单片机可以用其带有的串口与另一单片机、计算机、其它硬件模块等通信

硬件电路

(图源:B站江协科技视频截图)

在这里插入图片描述

TXD(Transmit Exchange Data)

RXD(receive external data)

交叉连接是因为TXD->RXD,延长线不需要交叉

如果两个设备各自都有供电,可以不接VCC

电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

  1. TTL(Transistor-Transistor Logic晶体管晶体管逻辑电路,就是单片机使用的电平)电平:+5V表示1,0V表示0(单片机用的)

  2. RS232电平:-3-15V表示1,+3+15V表示0(一般用在电脑等高电压的传输)

  3. RS485电平:两线压差+2+6V表示1,-2-6V表示0(差分信号)

RS485的两线压差是指两根线之前的电压差,而不是对地(传输距离远,更稳定,不使用差分信号的在10m之后就容易产生错误)

常见通信接口

名称引脚定义通信方式特点常见用途
UARTTXD、RXD全双工、异步点对点通信51单片机所用通信方式
I²CSCL、SDA半双工、同步可挂载多个设备单片机开发板上的24C02用于存储数据,单片机通过I²C的通信接口实现读取和写入
SPISCLK、MOSI、MISO、CS全双工、同步可挂载多个设备DS1302等用到
1-WireDQ半双工、异步可挂载多个设备温度传感器等用到
CAN、USB等CAN常用于汽车等,连接多个传感器,使用差分信号

通信方式

方式特点
全双工通信双方可以在同一时刻互相传输数据(有两数据线相互连接)
半双工通信双方可以互相传输数据,但必须分时复用一根数据线(只有一根线)
单工通信只能由一方发送到另一方,不能反向传输
同步通信双方通信速率相同
异步通信双方各自约定通信速率

通信速率:相当于在读取高低电平时采样的速率,速率正确才能接收到正确数据

同步:通信双方靠一根时钟线(比如上面提到的SCL、SCLK)来约定通信速率(不会导致收发错误)

总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)

(eg:I²C总线、SPI总线、1-Wire总线(满足总线的特点))

UART

51单片机上的UART

STC89C52RC有1个UART

有四种工作模式:

​ 模式0:同步移位寄存器

​ 模式1:8位UART,波特率可变(常用)

​ 模式2:9位UART,波特率固定

​ 模式3:9位UART,波特率可变

(图源:普中科技开发手册)

在这里插入图片描述

在这里插入图片描述

串口通信的接口和P30P31复用,操作P3的寄存器时则为IO,操作串口寄存器即为串口,不用单独区分

(STC89C52RC开发板上的USB转TTL下载模块)

在这里插入图片描述

在这里插入图片描述

串口参数

波特率:串口通信的速率(发送和接收各数据位的间隔时间)

机器人与PC通信涉及一个专业词语—波特率。计算机在串口通信时的速率用波特率表示,它的定义为每秒传输二进制代码的位数,即1波特=1位/秒,单位为bps(位/秒)。如果串口通信波特率设置为9600 bps,则表示串口每秒传输9600位二进制代码

检验位:用于数据验证(9位数据格式的最后一位,可用于奇偶校验等)

停止位:用于数据帧间隔

(图源:B站江协科技视频截图)

在这里插入图片描述

串口模式

(图源:B站江协科技视频截图)

在这里插入图片描述

数据通过总线传输,波特率由定时器T1控制,即在使用串口时需要配置定时器(经过2分频加16分频或者直接16分频)

发送时,先把8位的数据写入缓存,然后再发出去

接收时,先将数据接收到移位寄存器,然后移到缓存中

TI和RI表示发送中断和接收中断

(图源:普中科技开发手册)

在这里插入图片描述

TI和RI用的是同一个中断通道,通过一个或门

串口相关寄存器

(图源:普中科技开发手册)

在这里插入图片描述

注:PCON中只有SMOD和SMOD0是控制串口的,其余都是控制电源的

(图源:普中科技开发手册)

在这里插入图片描述

在这里插入图片描述

串口用的计时器1是“8位自动重装”模式:把两个计数器分开,一个中断后另一个自动重装(即两个计数器的一个用于计数,另一个用于保存一个固定数据,每次重置即为将保存的数值复制到计数所用计数器),只能计0~255,不用手动复位,可以减少运行时间

串口配置

通过stc-isp自动配置

在这里插入图片描述

11.0592MHz的系统频率是没有误差的,可以选择较高的波特率,12MHZ的系统频率会有误差,波特率越高误差越大

12MHZ的波特率需要加倍,不加倍的话分频后时钟会变慢(时钟分频后可能无法得到准确的波特率)

波特率计算

在以下条件下:
@9600bps
TL1 = 0xFD;//253
TH1 = 0xFD; 

256-253=3(每次溢出需要的脉冲次数)

3*1.085(每个时间周期对应的时间(us)) = 3.255

T1溢出率(每秒溢出的次数)= 1s / 3.255us = 307,219.6620 = 0.3072196620MHz

0.3072196620MHz / 2 / 16 = 0.0096006144375MHz = 9600.61Hz

通过近似计算得到的结果并非整数,以下为通过计算器计算得出的结果

在这里插入图片描述

对波特率倍速降低误差率的分析

(不一定对)

当晶振为12MHz时,选择4800bps,在波特率倍速的情况下,其实际波特率为2400bps,计数器初始化为243,计数13为1次溢出

即每13ns溢出一次,溢出率为76,923.0769

在这里插入图片描述

4,807.6923076923076923076923076923

此时误差为0.16%


当不使用波特率倍速,计数器初始化为249,计数7次,溢出率为142,857.1428

在这里插入图片描述

4,464.285714285714

此时误差为6.99%


由此可知,当系统频率为12MHz时,1秒内的溢出次数(即溢出率)不为整数导致产生误差,而波特率倍速就是将溢出所需时间加长,从而降低每秒溢出的次数,即降低溢出率,通过这种方式可以使溢出率更加接近整数,从而降低误差。

#include <STC89C5xRC.H>
#include "Delay.h"

void UART_inti()//4800bps@11.0592MHz
//初始化寄存器
{
    SCON = 0x40;
    //0100 0000
    PCON = 0;
    //此处不需要配置中断

    //配置定时器1
    TMOD &= 0x0F;       //TMOD高四位置0
    TMOD |= 0x20;       //串口需要用“8位自动重装”模式
    TL1 = 0xFA;         //设置定时初始值
    TH1 = 0xFA;         //设置定时重载值
    ET1 = 0;            //禁止定时器中断
    TR1 = 1;            //定时器1开始计时
}

void UART_SendByte(unsigned int Byte)
//发送数据
{
    SBUF = Byte;
    //将数据写入SBUF
    while(TI == 0);
    //当发送未完成,保持在函数内

    TI = 0;
    //重置TI
}

unsigned char sec = 0;

void main()
{
    UART_inti();
    while(1)
    {
        UART_SendByte(sec);
        sec++;
        Delay(1000);
    }
}

通信工具配置

选择相应的波特率

HEX模式/十六进制模式/二进制模式:以原始数据的形式显示

文本模式/字符模式:以原始数据编码(ASCII美国信息交换标准代码)后的形式显示

在这里插入图片描述

当发送数据的函数直接放在while并且没有任何延时时,打开串口接收的数据可能有错误,复位单片机即可(或者加一个延时,但是这样获得的第一个数据还是错误的)

模块化串口配置

#include <STC89C5xRC.H>

void Uart1_Init(void)   //9600bps@11.0592MHz
{
    PCON &= 0x7F;       //波特率不倍速
    SCON = 0x50;        //8位数据,可变波特率
    AUXR &= 0xBF;       //定时器时钟12T模式
    AUXR &= 0xFE;       //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;       //设置定时器模式
    TMOD |= 0x20;       //设置定时器模式
    TL1 = 0xFD;         //设置定时初始值
    TH1 = 0xFD;         //设置定时重载值
    ET1 = 0;            //禁止定时器中断
    TR1 = 1;            //定时器1开始计时
}


void UART_SendByte(unsigned int Byte)
//发送数据
{
    SBUF = Byte;
    //将数据写入SBUF
    //这里SBUF不用特地判断,写入时为发送端SBUF,读取时为接收端SBUF
    while(TI == 0);
    //当发送未完成,保持在函数内

    TI = 0;
    //重置TI
}

实例:根据接收的数据以二进制形式点亮LED

//在初始化函数中添加
EA = 1;//启动所有中断
ES = 1;//启动串口中断
#include <STC89C5xRC.H>
#include "Delay.h"
#include "Uart.h"

unsigned char sec = 0;

void main()
{
    Uart_Init();
    while(1)
    {

    }
}


void Uart_Routine() interrupt 4
//出发接收中断后的操作
{
    if(RI == 1)
    //防止发送中断导致操作进行
    {
        P2 = SBUF;
        //读取数据
        Uart_SendByte(SBUF);
        //发送接收到的数据
        RI = 0;
        //清零
    }
}
  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值