我手里用的是9针D型串口,它的引脚分布为2:RXD、3:TXD和5:逻辑地。如下图所示,
MCS-51的串行发送和串行接收利用了P3口的第二功能,P3.0作为串行数据的接收线RXD,P3.1作为串行数据线的发送线TXD。串行通信的控制寄存器占据了26个SFR中的3个,其中,PCON和SCON用于设置串行口工作方式以及确定数据的发送和接收波特率,SBUF实际上由两个8位寄存器组成,一个用于存放将要发送的数据,另一个用于存放接收到的数据,起着数据的缓冲作用。
MCS-51的串行接口如下图:
记得还是大二暑假的时候开始接触RS232通讯,当时对这3个SFR的概念非常模糊,那个时候的数字电路是自学的,基础不扎实,现在回头好好理解一下,发现这种通讯操作起来还是比较简单的,关键是要把这3个SFR的Functional Block Diagram理解清楚,这涉及到一些数字电路方面的知识,一点体会就是电路基础一定要过硬,否则控制程序将无从写起。
串行口通讯有4种工作方式可供选择,我这次调试的是方式1,即10位异步收发方式,这种方式比较常用。波特率的设置这里就不多说了,有专门的表可以直接查询,可以按照自己的需求选择其中一种就OK了。需要注意的是,这里数据的传送有两种途径可供选择,分别为:
(1)查询式:CPU通过查询通讯端口TXD和RXD的状态进行数据的传送,它的优点是硬件连线和查询程序十分简单,但是CPU在查询等待过程中会降低效率。
(2)中断法:中断传送是利用CPU本身的中断功能来实现对终端的数据传送,这种方式可以提高CPU的工作效率。
下面是我修改好的程序,我尽量把它写的清楚、简单、易懂、格式标准:
(1)查询法:
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
uchar temp;
//************************************************
void send_back() //数据返回子程序
{
SBUF="P1";
while(!TI); //等待数据发送完毕
TI="0"; //将发送标志位清零
}
//************************************************
void main()
{
TMOD="0x20"; //定时器1,工作方式2
TH1=0xFD;
TL1=0xFD; //给定时器1装初值,设定波特率为9600bps
PCON="0x00"; //波特率不进行加倍
SM0=0;
SM1=1; //串行工作方式1
REN="1"; //允许接收数据
TR1=1; //启动定时器1
while(1)
{
if(RI==1) //接收到数据时该位自动置为1。
{
RI="0"; //将接收标志位清零,否则上位机会一直不停地发送数据
temp="SBUF";
P1=temp;
send_back(); //把接收到的数据返回PC机
}
}
}
(2)中断法:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
//************************************************
void send_back() //数据返回子程序
{
SBUF="P1";
while(!TI); //等待数据发送完毕
TI=0; //将发送标志位清零
}
//************************************************
void main()
{
TMOD="0x20"; //定时器1,工作方式2
TH1 =0xfd;
TL1 =0xfd; //给定时器1装初值,设定波特率为9600bps
PCON="0x00"; //波特率不进行加倍
SM0 =0;
SM1 =1; //串行工作方式1
REN =1; //允许接收数据
ES =1; //打开串口中断4
TR1 =1; //启动定时器1
EA =1; //打开总中断
while(1);
}
//************************************************
void UART() interrupt 4
{
if(RI==1) //接收到数据时该位自动置为1。
{
RI="0"; //将接收标志位清零,否则上位机会一直不停地发送数据
P1=SBUF;
send_back();//把接收到的数据返回PC机
}
}
调试这个通讯程序时,发现使用串口调试发送数据时必须使用16进制模式发送,否则单片机收不到数据,以后得记住这一点,如图: