单片机学习系列(5):串口通信原理与应用

单片机学习系列(5):串口通信原理与应用

一、串口通信概述

  • 定义与作用:串口通信是一种常用的数据传输方式,它通过串行的方式在单片机与外部设备之间逐位地传输数据,具有连线简单、成本低等优点。在很多应用场景中都起着关键作用,比如单片机与电脑进行数据交互,将采集到的传感器数据发送给电脑端进行分析和显示;或者多个单片机之间相互通信,协同完成更复杂的任务等。

二、串口通信基本原理

  • 数据传输方式:串口通信采用异步传输模式,即发送端和接收端不需要使用同一时钟信号来同步数据传输。它通过起始位、数据位、奇偶校验位(可选)和停止位来构成一帧数据进行传输。发送端先发送一个起始位(通常为低电平)来告知接收端数据即将开始传输,接着依次发送规定数量的数据位(常见的有 5 位、6 位、7 位、8 位等),然后可根据需要添加奇偶校验位用于数据校验,最后发送一个或多个停止位(通常为高电平)表示一帧数据传输结束。
  • 波特率:波特率是指单位时间内传输的二进制位数,它决定了数据传输的速度。例如波特率为 9600bps,表示每秒传输 9600 位数据,发送端和接收端需要设置相同的波特率才能正确地进行数据通信,否则会出现数据接收错误或者丢失的情况。

三、串口通信相关寄存器(以 51 单片机为例)

串口控制寄存器(SCON)

  • 功能描述:主要用于控制串口的工作方式、接收和发送的状态等。例如,它可以设置串口是工作在方式 0、方式 1、方式 2 还是方式 3,不同的工作方式有着不同的数据格式和波特率计算方式;同时还能通过其相关位来判断数据是否接收完成、是否可以发送数据等情况。
  • 重要位说明:比如 RI 位(接收中断标志位),当接收完一帧数据时,该位会被硬件自动置 1,需要软件将其清零;TI 位(发送中断标志位),在发送完一帧数据后,此位会被置 1,同样需要软件清零来准备下一次发送操作。

波特率发生器相关寄存器

  • 定时器 1(在方式 2 时常用作波特率发生器):在 51 单片机中,串口波特率通常与定时器 1 的设置相关。通过对定时器 1 的计数初值进行设置,可以改变其溢出频率,进而确定串口的波特率。例如,要设置波特率为 9600bps(晶振频率为 12MHz 时),就需要按照相应的计算公式来给定时器 1 的 TH1 和 TL1 寄存器赋合适的初值。

四、串口通信工作方式(以 51 单片机为例)

方式 0

  • 特点:这是一种同步移位寄存器方式,常用于扩展 I/O 口或者外接一些简单的并行设备实现数据传输。数据通过 RXD 引脚进行输入输出,TXD 引脚输出同步移位脉冲,传输的数据为 8 位,低位在前,高位在后,且波特率固定为晶振频率的 1/12。
  • 应用场景:比如连接一些简单的数码管显示模块,通过串口方式 0 来传输要显示的数据,实现数码管显示内容的控制。

方式 1

  • 特点:这是最常用的一种异步通信方式,数据格式为 1 个起始位、8 个数据位、1 个停止位,没有奇偶校验位,波特率可变,由定时器 1 或定时器 2(部分 51 单片机支持)的溢出率和相关的波特率计算公式来确定。
  • 应用场景:广泛应用于单片机与电脑、单片机与其他带有串口通信功能的设备之间的数据传输,如将单片机采集到的温度、湿度等传感器数据发送给电脑进行记录和分析。

方式 2

  • 特点:这种方式的数据格式为 1 个起始位、9 个数据位、1 个停止位,其中第 9 个数据位可以用作奇偶校验位或者多机通信中的地址/数据标识位,波特率固定为晶振频率的 1/64 或 1/32(取决于 SMOD 位的设置)。
  • 应用场景:在多机通信系统中,利用第 9 位来区分地址帧和数据帧,便于主机与多个从机之间进行准确的数据交互和通信管理。

方式 3

  • 特点:与方式 2 类似,数据格式也是 1 个起始位、9 个数据位、1 个停止位,但波特率可变,同样由定时器 1 或定时器 2 的溢出率等来确定,这使得它在需要灵活设置波特率且又要利用第 9 位功能的多机通信等场景中比较适用。
  • 应用场景:例如在一个较为复杂的分布式单片机控制系统中,多个从机通过不同的波特率与主机进行通信,方式 3 就能满足这种既要可变波特率又要进行多机通信标识的需求。

五、串口通信代码示例(以 51 单片机方式 1 为例,实现向电脑发送字符数据)

电路连接

将 51 单片机的 RXD 引脚和 TXD 引脚通过 USB 转串口模块(如 CH340 等)连接到电脑的 USB 接口,以便实现与电脑之间的通信。

C语言代码示例

#include <reg52.h>

// 定义波特率,这里设置为 9600bps(晶振 12MHz 时)
#define BAUDRATE 9600
#define FOSC 12000000
#define TIMER1_RELOAD_VALUE (65536 - (FOSC / 12 / 32 / BAUDRATE))

// 初始化串口函数
void Uart_Init()
{
    TMOD |= 0x20;  // 设置定时器 1 为方式 2(自动重装载的 8 位定时器)
    TH1 = TIMER1_RELOAD_VALUE;  // 装入定时器 1 计数初值
    TL1 = TIMER1_RELOAD_VALUE;
    TR1 = 1;  // 启动定时器 1
    SCON = 0x50;  // 设置串口为方式 1,允许接收
    EA = 1;  // 开启总中断
    ES = 1;  // 开启串口中断
}

// 发送一个字符的函数
void Uart_SendChar(char ch)
{
    SBUF = ch;  // 将字符放入发送缓冲区
    while(TI == 0);  // 等待发送完成,TI 为发送中断标志位
    TI = 0;  // 发送完成后清零标志位,准备下一次发送
}

// 主函数
void main()
{
    Uart_Init();
    while(1)
    {
        Uart_SendChar('A');  // 循环发送字符 'A'
        Delay(1000);  // 简单延时函数,假设已经定义,用于控制发送间隔
    }
}

// 串口中断服务函数
void Uart_ISR() interrupt 4
{
    if(RI == 1)  // 如果是接收中断
    {
        char receivedChar = SBUF;  // 读取接收到的字符
        RI = 0;  // 清零接收中断标志位
        // 这里可以添加对接收到字符的处理代码,比如判断、显示等操作
    }
    if(TI == 1)  // 如果是发送中断
    {
        TI = 0;  // 清零发送中断标志位
    }
}

六、常见问题及解决办法

  • 数据接收错误问题:首先检查波特率设置是否一致,发送端和接收端的波特率哪怕有微小差异都可能导致数据接收出错。其次,查看串口的工作方式是否匹配,包括数据位、停止位、奇偶校验位等设置都要相符。另外,还要留意硬件连接是否良好,比如串口线是否松动、转接口是否正常工作等。
  • 数据丢失问题:可能是由于接收缓冲区满了但没有及时处理数据导致后续数据丢失。可以适当增大接收缓冲区(如果支持)或者优化接收处理程序,加快数据处理速度,确保及时从缓冲区读取数据。同时,也要检查发送端的发送频率是否过快,超出了接收端的处理能力,可适当调整发送间隔。

七、下期预告

在“单片机学习系列(6)”中,将会深入讲解单片机的模数转换(ADC)与数模转换(DAC)相关知识,包括它们的工作原理、如何在单片机中进行配置与应用以及在实际项目中利用 ADC 和 DAC 实现对模拟信号的采集与输出控制等内容,欢迎大家继续关注哦。

希望大家通过学习串口通信知识,能顺利实现单片机与外部设备之间的可靠通信,有疑问可随时在评论区交流呀!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值