1.简介
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。
51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。
STC89C52有一个UART,对应有四种工作模式:
模式0:同步移位寄存器
模式1:8位UART,波特率可变(常用)
模式2:9位UART,波特率固定
模式3:9位UART,波特率可变
串口的模式图如下图所示:
串口通信/1-1.png)
其中,由于串口需要=控制数据传输的速度,因此需要使用定时器。与上一章中使用的定时器0不同,UART默认使用定时器1。SBUF为串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,并申请TI(发射中断);读操作时,读出的是接收寄存器,并申请RI(接收中断)。
2.串口初始化函数编写
首先介绍一些串行口相关的寄存器:
串口通信/2-1.png)
在串口初始化的过程中,我们需要配置SCON,PCON的高二位,以及与定时器1有关的寄存器(TMOD,TH1,TL1,TR1,ET1)。如果需要用到串口中断,则需要将EA(中断总开关),ES(串口中断开关)置1。
UART的定时器默认只能使用定时器1,且使用模式2:8位自动重装模式。不使用模式1:16位定时器的原因在于16位定时器每次进入中断都需要把计数器记录初值,会占用一定的时间,但在串口中由于传输速率较快,因此需要更加精准的操作。
8位自动重装模式会把TH与TL分开,TH负责设定初值,TL用于接收脉冲计时计数。当TL溢出(>255)时,会自动将TH的值重新装入TL自己。从而完成自动重装的过程,无需额外在中断中设定初值大小。
需要注意的是,由于定时器0在UART中的作用仅为控制数据传输速度,并不涉及到定时结束后需要做的事情,真正需要做的事应该在串口中断中完成,因此无需开启定时器1的中断,也就不需要配置ET1,EA,PT1等寄存器。
首先需要配置的是SCON,每一位的解释如下:
串口通信/2-2.png)
串口通信/2-3.png)
SM0与SM1共同决定串口的模式,我们使用模式1时,这两位需要分别置01。
SM2在多机通信中使用,暂时不用管它,均置0。
REN代表是否允许接收数据,允许置1。
TB8,RB8都与模式1无关,均置0
TI是在数据发送完毕后置1,然后向主机请求中断的,在相应中断后必须在代码中手动将T1置0。
RI是在数据接收完毕后置1,然后向主机请求中断的,在相应中断后必须在代码中手动将R1置0。
综上:SCON=0b 0101 0000(0x50)。
PCON的高二位解释分别如下:
串口通信/2-4.png)
SMOD用于控制波特率是否加倍,在系统晶振频率非11.0592MHz的整数倍时,较高的波特率会导致一定的误差。因此在实际操作时选择较低的波特率然后启动波特率倍速(SMOD置1),就能有效的减少误差。
SMOD0在帧校验时会使用到,本实验用不到,因此无需处理。
PCON其余位与电源相关,无需处理。
综上:PCON=0b 1000 0000(0x80)。为了避免对其他位操作,我们使用PCON|=0x80。
接下来配置定时器1,由于UART默认使用8位自动重装模式,因此TMOD的高四位应该为0010,为了避免对其他位操作,我们先将高四位清零:TMOD &= 0x0F,再设定高四位的具体数值:TMOD|=0x20。
TL和TH的初值均设为一样,需要根据波特率得出,计算方法在稍后讲解。
由于我们不需要触发定时器1的中断,因此ET1置1。
启动定时器1,TR1置1。
当我们需要用到串口中断时,需要将EA(中断总开关),ES(串口中断开关)置1。
这样,一个串口初始化函数就写好了:
1 | void UART_Init(void) //4800bps@11.0592MHz |
3.串口发送函数编写
先给出函数的写法:
1 | void UART_SendByte(unsigned char Byte) |
SBUF为串行通信特殊功能寄存器,用于缓存串口接收或者发送的数据。首先将要发送的数据写入SBUF中,此时SBUF中的数据就被依次发送出去了,然后等待直到TI为1(串口中的数据全部发送完成),最后将TI重置为0完成整个流程。
4.串口中断函数编写
先给出函数的写法:
1 | void UART_Routine() interrupt 4 |
首先确认该终端是由接收数据产生的即:if(RI==1)。在处理完数据以后,需要将RI重置为0完成整个流程。
5.波特率的计算
波特率计算需要结合这张图片讲解:
串口通信/1-1.png)
假设我们在系统晶振频率为11.0592MHz,定时器时钟为12分频,不使用波特率倍速的情况下,初值设定为0xF4(244),则需要等待256-244=12个脉冲周期后进入中断。11.0592MHZ的晶振频率,12分以后为0.9216MHZ,约1.08μs晶振一次,经过12个脉冲周期,也就是12*1.08μs=13.0208333333μs后溢出,因此溢出率为其倒数,即:1/13.0208333333=0.0768MHz。溢出率的公式可以总结为:SYSclk/12/(256-TH1)
由于使用波特率倍速,因此直接将溢出率除以16,无需额外除以2,得到结果为0.0048MHz,即得到4800Hz的波特率。
由此,我们得到了初值设定为0xF4时,波特率倍速得到的波特率为4800。我们也可以推断出在使用同样初值的情况下,如果不使用波特率倍速, 得到的波特率应为2400。
其他波特率也可以仿照此过程计算得出。