历史上的今天
今天是:2025年08月20日(星期三)
2019年08月20日 | 51单片机之串口通讯应用实例(逻辑分析仪调试)
2019-08-20 来源:eefocus
硬件:STC89C52RC
开发工具:Keil uVision4
前言:8051是一款很经典的、历史悠久的单片机,作为一款入门级的单片机8051受到很多初学者的欢迎。89c52是8051系列的成员之一,拥有8K字节程序存储空间,512字节随机数据存储空间;I/O口控制端口、中断功能、定时器及串行接口。下面详细讲述串行接口功能的使用。
不管你用的芯片是不是STC89C52RC,只要你看完这篇文章,就能自行运用到不同的芯片上;因为一种串口通信协议的传输原理在任何芯片上都是统一的;所以它可以作为不同芯片一起协作的通信媒介。
目前普遍的单片机都有串行通信的接口,因为它依赖的硬件比较简单,一条串行数据输出线(TX)、一条串行数据接收线(RX)、一条用于电压参考的共地线。由此看出,芯片可以同时接受和发送数据,也实现了所说的全双工;而且,数据的传输时异步进行的,也就是说当芯片发送数据的时候,不需要对方应答,甚至不接目标器件也能成功发送;与之相反的同步通讯,就是需要对方应答或者通过时钟线控制传输的过程。
波特率:每秒钟可以传送几位的数据成为波特率,单位是BPS(Bit Per Second)。典型的波特率有9600bps、115200bps,以9600bps为例,使用8个数据位,没有检验位,1个停止位,起始位一直会存在。那么发送一个字节共需要发送10位,9600/10=960字节,也就是说一秒最多能发960字节的数据,波特率越高,传送的时间越短。我们所说的4M宽带的4M指的也是波特率,是一秒可以发4M位,而不是一秒可以发4M字节。
串行异步通信时的数据格式:

⑴ 起始位:起始位必须是持续一个比特时间的逻辑“0”电平,标志传送一个字符的开始。
⑵ 数据位:数据位为5-8位,它紧跟在起始位之后,是被传送字符的有效数据位。传送时先传送字符的低位,后传送字符的高位。数据位究竟是几位,可由硬件或软件来设定。
⑶ 奇偶位:奇偶检验为仅占一位,用于进行奇校验或偶校验,也可以不设奇偶位。
⑷ 停止位:停止位为1位、1.5位或2位,可有软件设定。它一定是逻辑“1”电平,标志着传送一个字符的结束。
⑸ 空闲位:空闲位表示线路处于空闲状态,此时线路上为逻辑“1”电平。空闲位可以没有,此时异步传送的效率为最高。
下面是利用逻辑分析仪抓取信号得到的波形图,对照着上面所说的数据格式去解读:

图的上方是信号的波形图,下方是描述该串口信号的信息,只有告诉逻辑分析仪这些信息,才能让它从该信号中正确地读取数据,所以在应用的时候以上所显示的信息需要通信双方配置为一样。我们截取了一帧的数据,可以看到正在发送的值是0b10101010,也就是0xaa;首先,上面每一个点对应数据的一个bit位的值,总共8个点;可以看到第一个数据前有一个起始位,最后一个数据后面有一个停止位“1”,当然发完了之后是空闲状态也是处于逻辑“1”状态。数据位的低bit位先发,对于0b10101010来说就是先发0,所以起始位后面紧接着发0。
下面介绍如何使用单片机的串行通信,首先是相关寄存器介绍:
SCON特殊功能寄存器
下图是SCON寄存器的每一位,每一个位均可位寻址,可分别设定或清除。

SM0、SM1
SM0=0&SM1=0:模式0,移位寄存器控制I/O,波特率固定为工作频率/12。
SM0=0&SM1=1:模式1,8位串行数据传送,波特率由计时器1来控制。
SM0=1&SM1=0:模式2,9位串行数据传送,波特率可分为2种,工作频率/32或工作频率/64。
SM0=1&SM1=1:模式3,9位串行数据传送,波特率可用计时器1控制。
SM2: 在串行传输工作模式2或模式3时,用于多处理机控制功能。
REN:串行接口接收位,当REN=1时表示允许接收。
TB8:在模式2或模式3时,所送出的第9个数据位,可以由软件指令来做控制设定或清除。
RB8:在模式2或模式3时,所接收的第9位数据位,存放在此位上。
TI:串行传输数据发送中断产生标志,最后一个数据发送出去后,TI会被设置为1,此位必需由软件清除。
RI :串行传输数据接收中断产生标志,当接收到最后一个数据时,RI会被设置为1,此位必需由软件清除。
从上面可知,这款单片机并没有配置停止位和校验方法的,默认是一个停止位和无校验方法。所以它可以做到:
波特率:在合适范围内自行配置
数据位:8位或9位
校验位:不可选,默认没有校验位
停止位:不可选,默认1个停止位
其实我们可以做到有校验位的,就是将就第9个数据为作为校验位,当然该位的值需要软件计算出来。下面说一下各模式下波特率的计算:
模式0的波特率设定:
该模式下波特率固定的,为工作频率的1/12。如果使用12M的晶振,工作频率即为12M,波特率为12M/12=1Mbps。
模式2的波特率设定:
当SMOD=1时,波特率=(工作频率)/32
当SMOD=0时,波特率=(工作频率)/64
模式1和模式3的波特率设定:
模式1和模式3下的波特率有内部计数器1来控制,计数器的工作模式也有很多种,但必须要使用模式2,自动重新载入计时模式。如果对定时器不是很了解可参考链接。设定波特率的关键是计算出计数器TH1(自动载入计时值)的值,计算公式为:

由上面的公式,只要把波特率定下来,就可以算出TH1的值了,整理得:

假如单片机使用的晶振频率为11.0592MHz,各串行通信的波特率定为9600bps,SMOD设为0,则可求得TH1如下:

由上面公式,我们可以计算常用的波特率所对应的计时器自动载入值(写入TH1中),如下:

下面是一个例子,实现电脑端给单片机发送字符时,单片机将字符返回给电脑,波特率位9600bps,8个数据位,无校验位,1个停止位,单片机使用的晶振是11.0592MHz。
#include void InitUART (void) //初始化串口通信 { #if 1 //方法一 SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收 TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit 重装 TH1 = 0xFD; // TH1: 重装值 9600 波特率 晶振 11.0592MHz TR1 = 1; // TR1: timer 1 打开 EA = 1; //打开总中断 ES = 1; //打开串口中断 #else //方法二 TMOD=0x20; //设置定时器1工作模式:模式二 TH1=0xfd; //设定定时器重载值 TL1=0xfd; //初值 TR1=1; //打开定时器 REN=1; //使能串口接收数据 SM0=0; //串行通讯模式1 SM1=1; //串行通讯模式1 EA=1; //打开总中断 ES=1; //打开串口中断 #endif } void SendString(unsigned char *s) //发送字符串的函数 { while(*s!='




