呵呵,先来一个程序(摘自书上的,实现的是在上位机(pc机)上用串口调试助手发送一个字符X,单片机收到字符后返回给上位机I get X串口波特率设为9600bps。代码如下:)
#include
#define uchar unsigned char
#define uint unsigned int
unsigned char flag,a,i;
uchar code table[]="I get ";
/*--------初始化操作---------------*/
void init()
{
TMOD=0x20; //T1定时器工作方式2
TH1=0xfd; //装初值
TL1=0xfd; //装初值
TR1=1; //启动定时器1
//***********************************
SM0=0; //设定串口工作方式1
SM1=1; //同上
REN=1; //允许串口接收
//***********************************
EA=1; //开总中断
ES=1; //开串口中断
//因为定时器2是自动重装初值的因此不需要开定时器中断
}
/*---------------------------------*/
/*-------------主函数--------------*/
void main()
{
init();
while(1)
{
if(flag==1)
{
ES=0;
for(i=0;i<6;i++) //发送数据
{
SBUF=table[i];
while(!ti);
TI=0;
}
SBUF=a;
while(!TI);
TI=0;
ES=1;
flag=0;
}
}
}
/*-----------------------------------*/
/*--------------串口中断---------------*/
void ser() interrupt 4
{
RI=0;
a=SBUF;
flag=1;
}
/*------------------------------------*/
主程序的工作过程:当我们用串口调试助手发数据给单片机时,发送完后单片机接收到数据后会触发接收中断然后程序就会进入到接收中断中进行必要的处理,RI由软件清零为下一次中断做准备,然后把SBUF寄存器(接收到的)数据给变量a,最后置flag=1.然后回到主程序中检测到flag=1,再将前面定义的字符I get和串口发送的字符发送给pc机。while(!TI);是等待是否发送完毕的作用,当发送完毕后触发发送串口中断这时TI会自动置1,假设这时候已经发送完了我们就把TI由1置为0,再开串口中断,flag置零。又进行下一次了接收了。。。
溢出率的计算
单片机有四种串口方式,方式0和方式2的波特率是固定的,而方式1和3的波特率是可变的,具体设置多少由定时器T1的溢出率决定,溢出的频率越高波特率也越高,通信的速度也就越快。当然还与别的因素有关,具体波特率的计算有专门的公式。方式1的波特率计算公式(2^SMOD/32)x(T1溢出率)而方式0的波特率为fosc/12是固定的其中 fosc是单片机的晶振频率,通常为12MHZ和11.0592MHZ,公式中的SMOD是PCON(电源管理寄存器)的最高位,当设置SMOD的最高位为0时,串口方式1的波特率没有加倍,如果设置为1显然其他条件不变的情况下波特率会加倍,PCON的其他位跟这个程序就没多大的关系了呵呵,直接无视 ,要用到的时候再研究^-^。由于这个程序用到的是串口方式1,波特率是可以设置的,假如要设置波特率为9600bps的话,已知单片机的晶振为11.0592MHZ。因为溢出率就是溢出的频率即定时器每计多少个数产生一次溢出。这里采用定时器1来计数,因为定时器1有这样的特点即每发生一次溢出它会自动重装初值,不需要人为的去设定,显然这个特点可以提高溢出的精度,因此采用了定时器T1.来实现精确溢出。现在就是要求出定时器T1中的TH1和TL1装的初值是多少了,我们假设TH1和TL1装的初值都是X,因为TH1和TL1都是八位的所以最多能计数256个,其计数原理是:因为假设的是TH1和TL1都装的是X,那么每发生一次溢出后单片机会自动把TL1中的值重装入TH1中,开始进行第二次溢出了,就这样重复着进行下去。。。设所求的数为X,由前面分析可知定时器每计256-X个就溢出一次,而每记一个数的时间是一个机器周期,因为一个机器周期是12个时钟周期所以计一个数的时间为12/11.0592s,那么定时器溢出一次的时间为(256-x)x 12/11.0592s 那么溢出率就是时间的倒数为11.0592/(256-x)x12,这里SMOD取的是0,则波特率为 1/32 x【11.0592/(256-X)x12】=9600 这样就可以计算出X的值也就是TH1和TL1的值。而通常波特率都是固定的就是这个原因,因为这样计算出的X才会是整数。
串行口控制寄存器SCON
SM0,SM1是工作方式选择位 该程序中SM0=0,SM1=1初始化串口工作方式为1.REN是允许串行口接收位REN等于1时就允许了,该程序中初始化为1 最后是TI和RI 其中TI是发送中断位,在方式1下串行发送停止位的开始时,系统自动置1,然后申请中断。RI是接收中断位串行接收停止位时系统自动置1,申请中断,SCON 的其他的位与该程序无关,直接无视。等用到的时候再研究^_^编程前首先要进行串行口1工作的初始化操作主要是设置产生波特率的定时器1、串行口控制和中断控制。具体步骤如下:
1确定T1的工作方式(编程TMOD寄存器);
2计算T1的初值,装载TH1、TL1
3启动T1(编程TCON中的TR1位);
4确定串行口控制(编程SCON寄存器); |
7