51单片机串口通信基础教程:从代码出发理解通信原理
一、引言
想象我们生活在一个由各种小机器人组成的世界里,每个小机器人都有自己的任务和功能。为了让这些小机器人之间能够交流信息,我们需要一种通信方式。在51单片机的世界里,串口通信就像是小机器人之间的“电话线路”,通过它,单片机可以和其他设备(比如电脑)进行信息的传递。今天,我们就来详细解读一段51单片机串口通信的代码,看看这个“电话线路”是如何搭建和工作的。
二、代码整体功能概述
这段代码的主要功能是让51单片机通过串口与其他设备进行通信。单片机初始化串口后,先发送两个字节的数据 0x5a
,之后进入一个无限循环,等待接收其他设备发送的数据。一旦接收到数据,就将数据加1后再发送回去。
三、代码详细解读
1. 头文件和特殊寄存器定义
#include "reg52.h"
sfr AUXR=0x8e;
#include "reg52.h"
:这就像是我们打开了一个工具箱,reg52.h
这个头文件里包含了很多51单片机常用的工具(寄存器定义),我们在代码里可以直接使用这些工具。sfr AUXR=0x8e
:AUXR
是一个特殊的寄存器,就好比是工具箱里一个比较特殊的工具。我们通过sfr
关键字给它指定了地址0x8e
,这样我们就可以使用这个特殊工具来完成一些特定的任务。
2. 变量定义
unsigned char urdat;
urdat
就像是一个小盒子,用来存放从串口接收到的数据。unsigned char
表示这个盒子只能存放无符号的单字节数据。
3. 数据发送函数 SendByte
void SendByte(unsigned char dat)
{
SBUF = dat;
while(TI==0);
TI=0;
}
SBUF = dat;
:SBUF
是串口的数据缓冲区,就像是一个快递包裹箱。我们把要发送的数据dat
放到这个包裹箱里,准备寄出去。while(TI==0);
:TI
是发送中断标志位,就像是快递的发货通知。当TI
为0时,说明包裹还没发出去,我们就一直等着,直到包裹发出去(TI
变为1)。TI=0;
:包裹发出去后,我们把发货通知清零,为下一次发货做准备。
4. 延时函数 Delay10ms
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
这个延时函数就像是一个倒计时器。在单片机的世界里,有时候我们需要等一段时间再做下一步操作。这里通过嵌套的循环,让单片机空转一段时间,大约是10毫秒。i
和 j
的值是根据单片机的晶振频率 11.0592MHz
计算出来的,就像是倒计时器的刻度。
5. 串口初始化函数 UartInit
void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES=1;
EA=1;
}
这个函数就像是在搭建“电话线路”。
SCON = 0x50;
:SCON
是串口控制寄存器,就像是电话的拨号盘。我们把它设置为0x50
,表示使用8位数据、可变波特率的通信模式。AUXR |= 0x40;
和AUXR &= 0xFE;
:AUXR
就像是电话线路的总开关,这里我们通过设置它来选择定时器1作为时钟源和波特率发生器。TMOD &= 0x0F;
:TMOD
是定时器模式寄存器,就像是定时器的模式选择按钮。我们把它设置为让定时器1工作在16位自动重装模式。TL1 = 0xE0;
和TH1 = 0xFE;
:TL1
和TH1
是定时器1的初值寄存器,就像是定时器的初始刻度。我们给它们赋初值,是为了得到我们想要的波特率(这里是9600bps)。ET1 = 0;
:禁止定时器1中断,就像是把定时器的闹钟关掉,我们不需要它发出中断信号。TR1 = 1;
:启动定时器1,就像是按下定时器的启动按钮。ES=1;
和EA=1;
:ES
是串口中断允许位,EA
是全局中断允许位。我们把它们都设置为1,就像是打开了电话的铃声开关,允许串口接收到数据时发出中断信号。
6. 串口中断服务函数 ServiceUart
void ServiceUart() interrupt 4
{
if(RI==1)
{
RI=0;
urdat=SBUF;
SendByte(urdat+1);
}
}
这个函数就像是当电话铃声响起(串口接收到数据)时,我们要做的事情。
if(RI==1)
:RI
是接收中断标志位,就像是电话的来电指示灯。当RI
为1时,说明有电话打进来(接收到数据)。RI=0;
:把来电指示灯熄灭,为下一次来电做准备。urdat=SBUF;
:把接收到的数据从数据缓冲区SBUF
里取出来,放到我们之前准备好的小盒子urdat
里。SendByte(urdat+1);
:把小盒子里的数据加1,然后通过SendByte
函数再发送回去,就像是接电话后回复对方一个修改后的信息。
7. 主函数 main
void main()
{
UartInit();
Delay10ms();//用来延迟使得方便用串口工具显示出0x5a
SendByte(0x5a);
SendByte(0x5a);
while(1);
}
主函数就像是整个程序的指挥官。
UartInit();
:调用串口初始化函数,搭建好“电话线路”。Delay10ms();
:延时10毫秒,就像是给对方一点准备时间,方便对方的串口工具显示我们要发送的数据。SendByte(0x5a);
和SendByte(0x5a);
:发送两个字节的数据0x5a
,就像是给对方打个招呼。while(1);
:进入无限循环,就像是指挥官一直在等待新的任务(等待串口接收到新的数据)。
四、逻辑图
这个逻辑图清晰地展示了程序的执行流程。从开始初始化串口,到发送数据,再到进入无限循环等待接收数据,一旦接收到数据就进行处理并回复,形成了一个完整的串口通信流程。
通过以上的解读和逻辑图,相信你对51单片机的串口通信有了更深入的理解。现在你可以试着修改代码,实现更多有趣的功能,比如发送不同的数据、处理更复杂的信息等。