51单片机串口通信

📅 2026/7/21 23:02:03 👁️ 阅读次数 📝 编程学习
51单片机串口通信

串口发送功能的实现:

一、配置SCON串行口控制寄存器

1.REN:允许/禁止串口接收控制位

2.SM0=0、SM1=1:选择通讯方式一

3.TI=0、RI=0:发送接收中断标志位,每次发送后必须手动清零

二、配置PCON电源控制寄存器

SMOD:波特率选择位,SMOD=1使方式一二三波特率加倍,默认为0

(波特率越低 = 越稳定、越抗干扰、越不容易出错,但速度越慢)

三、配置定时器

串口发送时中断不需要配置,只需要配置定时器1并选择波特率

串口需要八位自动重装,不再是十六位(65535),因为十六位要每次赋初值会占用时间导致误差,串口通信要双八位更精准,计数值变为0-255(256次计数,255后还要加一位才溢出)

1.在这里我们先对特殊功能寄存器TMOD高四位清零,低四位置默认:TMOD&=0x0F

再设置高四位GATE=0;C/~T=0;M1、M0=1,0(八位重装模式):TMOD|=0x20

2.然后再设置定时器初值和是否倍速波特率,这里选倍速也就是PCON |= 0x80,然后我们这里是八位自动重装模式,不需要每次溢出重新赋初值,只需要把高低位都设置成我们的初值就好:TL1=0xF4;TH1=0xF4;

波特率计算:我们这里初值为0xF4,换算为十进制就是244,256-244=12,也就是每次溢出经过12次计数,12个1.085us,每次溢出时间=12*1.085069444=13.020833328

溢出率=1/每次溢出时间=0.07680000003145728MHZ

注意,我们这里是波特率倍速,所以不用除2,直接除16就好

波特率=溢出率/16=4800.00000196608HZ≈4800HZ,是不是几乎没有误差?如果是12MHZ晶振就会算出是4807.69MHZ,而且波特率越高误差就会越大

3.ET1=0;禁止定时器中断,这里不需要

4.TR1=1:启动定时器1

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

当然也可以使用STC-ISP的波特率计算器自动生成初始化代码,连配置都省了:

四、串口发送函数

我们直接将数据写入SBUF即可,在写入后加上whlie判断检测发送是否完成,防止一直发送卡住,在发送后手动将发送标志位TI清零

//串口发送一个字节数据范围0-255 void UART_SendByte(unsigned char Byte) { SBUF=Byte; //写入SBUF实现数据发送 while(TI==0); //发送结束检测,防卡死 TI=0; //发送检测位清零 }

五、主函数调用

当我们需要连续发送信息时,在while循环中调用的时候要每次发送后延时,否则会由于发送过快发送错误信息,比如从66变为99,要想控制信息发送速度也可以通过延时函数粗略控制

void main() { Uartl Init (); //初始化 while(1) { UART_SendByte (0x66); //串口发送函数 Delay(100); //延时防止连续发送过快产生发送乱码 } }

程序编译烧录后打开串口,选择HEX模式,可以看到

如果我们选择文本模式,那么显示的就会是数字编码后,也就是字符原本的样子

六、串口发送模块化

串口发送可以模块化为.c.h文件方便以后调用(记得养成注释的好习惯),但是接下来讲的接收中断依赖于串口中断,和主函数耦合性较强,就没法模块化了

串口接收功能的实现:

一、串口初始化

其他都和发送一样,只需要改动几个点:

1.确保串口接收使能位为打开状态:SCON的第四位置1,也就是让SCON=0x50

(其实我们在发送时也是打开的,这里就不用改了)

2.打开串口中断:EA=1(启动中断总开关),ES=1(打开串口中断)

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

二、中断函数

我们在技术手册查询到中断号小尾巴为interrupt 4,那中断函数我们命名为void UART_Routine()interrupt 4(函数名可以随便起,只要带上空格+中断号小尾巴就是中断函数啦),主函数空循环即可,这样我们就实现了电脑命令控制LED了

void UART_Routine() interrupt 4 //中断函数头 { if(RI==1) //发送完成进入后续 { P2=SBUF; //使用串口写入SBUF的数据控制LED(发送需要手动写入SBUF,接收时电脑会直接写入,不需要我们操作) UART_SendByte(SBUF); //在中断里将串口收到的数据发出 RI=0; //将接收检测位手动置零(发送位我们在函数中置零就好啦) } }