串口通信在单片机开发中是一种很常见的通信方式,一般所说的串口是对应rs232标准,对应有gnd,vcc,rx,tx四根数据线。其中rx,tx分别是接收、发送端口,而在实际接线中,我们需要注意,rx接另一端tx,tx接另一端的rx。在51单片机中,rx对应P3.0端口,tx对应P3.1端口。
串口终端在proteus中,是在Virtual Instruments Mode的VIRTUAL TERMINAL。
要仿真串口通信,我们需要了解串口内部结构,这里给出单片机手册中关于串口内部逻辑使用到的寄存器列表:
我们要重点关注的是如下四个寄存器:
SCON:串口控制寄存器
PCON:电源控制寄存器
SBUF:缓存数据寄存器
IE:串口中断寄存器
一般,串口工作模式有如下四种方式:
0)同步移位寄存器
1)8位UART,波特率可变
2)9位UART,波特率固定
3)9位UART,波特率可变
在串口实验中,主要使用工作模式1)8位UART,波特率可变。这种工作模式具体内容如下所示:
我们的串口工作模式,主要由SCON这个寄存器变量来设置。 而SCON寄存器描述如下:
这里也引出了关于SCON值得的设置,和设置之后波特率的计算方法,这里波特率的计算关系到定时器1的溢出率,这个溢出率又和6T(SMOD=1)/12T(SMOD=0)的工作模式有关,我们看如下所示的串口工作内部结构:
综合以上描述,波特率的计算就是 baud_rate =
SYSclk是系统时钟,也就是晶振的频率,如果晶振是12M,这里就是。
这个晶振的频率和波特率的大小,以及TH1的初始值,关系到后面仿真的时候,在visual terminal中是否会乱码和不显示内容。因为如果存在误差,那么最后收到的数据就会错位,在显示的时候,就会乱码或者不显示。
一般,我们晶振大概是12M,但是实际上,可能会设置为11.0592M,这样,我们在设置了TH1初始值为0xFD=253之后,那么这个时候波特率根据上面的计算公式,可以得出,正好是9600。
如下所示的代码,是一个使用proteus仿真51单片机结合visual terminal串口终端显示单片机发送的字符串aaa并显示的程序。
#include
void uart_init(void);
void uart_send_byte(unsigned char c);
void delay(void);
void uart_send_string(unsigned char *str);
void main(void)
{
uart_init();
while(1)
{
uart_send_string("aaa\r\n");
delay();
}
}
void uart_init(void)
{
SCON=0x50;
PCON=0x00;
TMOD=0x20;
TH1=TL1=0xFD;
TR1=1;
ES=1;
EA=1;
}
void uart_send_data(unsigned char c)
{
SBUF=c;
while(!TI);
TI=0;
}
void uart_send_string(unsigned char *str)
{
while (*str)
{
uart_send_data(*str++);
}
}
void delay(void)
{
unsigned char a,b;
for(a=0;a<100;a++)
for(b=0;b<100;b++);
}
这段代码最麻烦的在于uart_init()串口初始化部分,这里的值,可以通过我们的单片机下载程序stc-isp工具来生成:
如上图所示,这里是根据波特率9600,系统时钟频率11.0592M,以及uart数据位 8位,波特率发生器 定时器1(8位自动重载)生成的代码,我们实际中没有使用PCON,所以代码里面设置的是0x00。
仿真效果如下所示:
在进行仿真的时候,可能不会出现terminal显示框, 可以在菜单栏debug->virtual terminal来让它显示:
如果visual terminal显示的是乱码,我们就需要根据实际情况修改单片机时钟频率,双击单片机,在弹出框中设置合适的频率,这个频率也不是随便设置的,而是根据代码中TH1以及波特率的值来设置,计算公式在前面已经给出过,如下所示:
其实整个串口通信代码很简单,但是需要理解初始化中的代码,我们需要了解它的内部结构,以及工作原理。 关于串口通信,在实际中,我们需要关注波特率。