单片机学习系列(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 实现对模拟信号的采集与输出控制等内容,欢迎大家继续关注哦。
希望大家通过学习串口通信知识,能顺利实现单片机与外部设备之间的可靠通信,有疑问可随时在评论区交流呀!
:串口通信原理与应用&spm=1001.2101.3001.5002&articleId=146175571&d=1&t=3&u=b14a75c201b44966afc7437a2abc2d5a)
6960

被折叠的 条评论
为什么被折叠?



