在stc89c52单片机的sfr特殊功能寄存器里面,有一个SBUF区域,是一个发送数据和接收数据公用的数据缓存区。当你的单片机发送数据的时候会先将数据存在这个缓冲区里面,累计一定量后再发送出去。接收数据的时候也会将接收的数据先存在这个缓存区里面,再去读取。也就是说接收数据的时候我们就去读这个缓冲区,发送数据的时候我们就往里面写入数据。
还有sfr中的EA全局中断控制符,ES串口中断控制符,当我们要使用串口中断的时候这两个值都需要设置为1,以开启串口中断功能。
sfr中的SMOD用于配置波特率。公式是:(2SMOD/32)*(定时器1的频率)。SMOD设置为1的时候是0的时候的两倍。
sfr中的SM0和SM1来配置串口的工作模式。我们一般使用将SM0设置为0,SM1设置为1。这种方式它的博客率计算公式为(2SMOD/32)*(定时器1的频率)
sfr中REN用于配置是否允许串口接收,1为允许接收,0为禁止接收。
sfr中的TI为发送中断请求标志位。在发送完成后标志位变为1,需要我们再手动置为0。
sfr中的RI为接收中断请求标志位。在接收完成后标志位变为1,需要我们再手动置为0。
比较重要的是波特率的计算,首先它是根据定时器1的频率,和SMOD的值,和SM0和SM1两位设置的串口工作方式来决定的。这里我们将SM0设置为0,SM1设置为1后,波特率的计算公式就是(2SMOD/32)*(定时器1的频率),定时器1的频率就是1秒钟中断的次数。而定时器计数一次就是一个机器周期,这个周期和单片机型号和晶振型号又有关系,比如stc89c52是12T的也就是12次晶振周期为一个机器周期即计数一次,使用的晶振是11.0592MHz的也就是一秒11.0592*106次。那么一个机器周期就是1秒11.0592*106/12次。然后是设置定时器1多少次产生中断,这个值的设置在定时器那里有讲,也是就给定时器1的计数空间设置初始值。这里我们使用只用定时器1计数空间的一个8位并且中断后自动置为初始值的方式,也就是只能用一个8位来计数,最多也就256次计数,如果我们初值设位n,则计数256-n次后产生中断,所以定时器的频率变为11.0592*106/(12*(256-n))。波特率就变为(2SMOD/32)* (11.0592*106/(12*(256-n)))。
在下面的代码例子中我们将波特率设置位19200,也即是19200 = (21/32)* (11.0592*106/(12*(256-n))),SMOD设置为1。解出n为253,十六进制就是0xFD。
因为在串口通信的两端必须要将波特率设置为一致来能正常通信。波特率就是就是每秒钟传送的数据位数,bit/s(bps)。
下面的代码是使用19200波特率,接收数据,如果接收到的数据是1就点亮第1个led灯(两秒后熄灭),2就是点亮第2个led灯(两秒后熄灭),依次类推,当超过8后就点亮全部led灯然后两秒后熄灭。
#include <reg52.h>
sbit LED0 = P0^0;
sbit LED1 = P0^1;
sbit LED2 = P0^2;
sbit LED3 = P0^3;
sbit LED4 = P0^4;
sbit LED5 = P0^5;
sbit LED6 = P0^6;
sbit LED7 = P0^7;
char rData = 0;
char RFlag = 0;
void UartInit(void)
{
TMOD = 0x20; //T1 方式2
PCON = 0x80; //SMOD = 1
SCON = 0x50; //方式1 8个数据位
TH1=0xFD;
TL1=0xFD;
TR1 = 1; //启动定时器1
ES=1; //开串口中断
EA=1; //开总中断
}
void SerialInt() interrupt 4
{
RI = 0;
RFlag = 1;
rData = SBUF;
}
void DelayMs(unsigned int n)
{
unsigned int i,j;
for(i = n; i > 0; i--)
for(j = 114; j > 0; j--)
;
}
void LedOff(int i)
{
switch(i)
{
case 1:
LED0 = 1;
break;
case 2:
LED1 = 1;
break;
case 3:
LED2 = 1;
break;
case 4:
LED3 = 1;
break;
case 5:
LED4 = 1;
break;
case 6:
LED5 = 1;
break;
case 7:
LED6 = 1;
break;
case 8:
LED7 = 1;
break;
default:
P0 = 0xFF;
}
}
void LedOn(int i)
{
switch(i)
{
case 1:
LED0 = 0;
break;
case 2:
LED1 = 0;
break;
case 3:
LED2 = 0;
break;
case 4:
LED3 = 0;
break;
case 5:
LED4 = 0;
break;
case 6:
LED5 = 0;
break;
case 7:
LED6 = 0;
break;
case 8:
LED7 = 0;
break;
default:
P0 = 0;
}
DelayMs(2000);
LedOff(i);
}
void main()
{
UartInit();
while(1)
{
if(RFlag)
{
RFlag = 0;
LedOn(rData);
}
}
}
发送数据可以由另外的单片机来发送,需要外接线。由于单片机的usb数据线也带了转串口,所以可以在电脑上用usb连接单片机后使用软件模拟向单片机发送数据用来测试: