微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > STC89C52通过串口控制流水灯亮灭

STC89C52通过串口控制流水灯亮灭

时间:11-20 来源:互联网 点击:
本次笔记包含两个方面:

1.只是控制LED的亮灭,不返回数值

2.控制LED的亮灭,并返回数值

看了几讲的视频,都是在讲串口的方式1。其他的还没接触,这里也只用串口的方式1实现这两个功能。串口里面需要计算的地方是根据所要使用的波特率求定时器的初始值。定时器使用的是方式2,可以自动装初始值,避免赋值语句装初始值时出现误差。

以9800bps,定时器使用方式2,串口使用方式1,晶振波特率为 11.0592MHZ,求TH1跟TL1的值。

方式1的波特率 = (2^SMOD/32)xT1溢出率。单片机复位后,电源管理寄存器PCON全部清零,SMOD作为其中一位自然也清零。

波特率已经知道了。这样就剩下T1溢出率了。

假设初值为X,则定时器每次计256-X个数溢出一次(定时器为8位,最大为255 。256时发生溢出)。每计一个数的时间为一个机器周期,机器周期 = T时钟周期 X 12 。于是溢出的时间为 = 个数X 每个时间 = ( 256 - X) * 12/Fosc . 那么基础率就是溢出时间的倒数。

于是结合公式“方式1的波特率 = (2^SMOD/32)xT1溢出率”,式子可以总结为:

9600 = 2^0 /32 * Fosc / (256 - X)*12 带入全部已知数据得到 9600 = 2^0 /32 * 11059200/ (256 - X)*12 =====》》》》 求得的X为: 253 .

在此基础上,如果把SMOD 设为1 ,则 求得波特率为 :

波特率 = (2^1/32) * 11059200 / (256 - 253 ) = 2 * [ 1/32 * 11059200 / (256 - 253)] = 2 * 9600 = 19200 。即变为原来的两倍。

如果把晶振换成12MHZ再求初值,求得的X为: 252.744792…… 无穷小数。这样就会产生误差。以前一直感觉整数的晶振挺好,现在才知道为什么会有11.0592MHZ这种晶振的存在了,。

这样计算得到了初值,下面贴代码。

只是控制LED的亮灭,不返回数值

实现这个又分为查询和中断两种方法。

A。先用查询。感觉叫判断更好些,因为是用if判断来实现的

#include void main(){  //设置参数TMOD = 0x20; //设定定时器1的工作方式为方式2TH1 = 0xfd;TL1 = 0xfd;	 //装载TH1、TL1TR1 = 1; //启动定时器1REN = 1; //允许串行接收位SM0 = 0;SM1 = 1; //设定串口工作方式为方式1/**    	       EA = 1; //全局中断允许位*		ES = 1; //串口中断允许位*		此处使用的是查询法判断接收中断标志位,所以即便不开启中断允许位,也可以**/while(1){	 	//查询法检测RIif(RI == 1)//RI为接收中断标志位。硬件置为1,必须软件清0{P1 = SBUF;RI = 0;} 		}}
B 中断法
#include  void main(){  //设置参数TMOD = 0x20; //设定定时器1的工作方式为方式2TH1 = 0xfd;TL1 = 0xfd;	 //装载TH1、TL1TR1 = 1; //启动定时器1REN = 1; //允许串行接收位SM0 = 0;SM1 = 1; //设定串口工作方式为方式1EA = 1; //全局中断允许位ES = 1; //串口中断允许位while(1) ;	//等待中断的发生}//中断检测RIvoid ser() interrupt 4{P1 = SBUF;RI = 0;}

这两个除了代码,感觉就是是否开启中断允许了。因为RI置为1是硬件自动执行的。即便是不开启中断允许位,照样可以用if进行判断。

上面这两个是单方向的,再来个双向的。

/**通过串口给下位机发送数据,并使之显示在P1口的流水灯上。*同时单片机返回接收到的数据,显示在串口助手上*/#include unsigned char flag;void main(){  //设置参数TMOD = 0x20; //设定定时器1的工作方式为方式2TH1 = 0xfd;TL1 = 0xfd;	 //装载TH1、TL1TR1 = 1; //启动定时器1SM0 = 0;SM1 = 1; //设定串口工作方式为方式1REN = 1; //允许串行接收位EA = 1; //全局中断允许位ES = 1; //串口中断允许位while(1){	/* 刚开始单片机缓冲寄存器为空,无数据可以显示* 先从串口接收数据,再返回该数据* 在中断中接收数据,同时将flag标志位置为1.说明接收到了数据* 若接收到数据(flag == 1),说明接收到了;否则说明未接收到数据,不显示。继续判断flag数值*/if(flag == 1) {						//发送数据ES = 0; //关闭串口中断,发送数据SBUF = P1; //数据写入SBUF寄存器while(!TI); //等待TI = 0;ES = 1; flag = 0;}		}}void ser() interrupt 4{//接收数据P1 = SBUF;flag = 1;RI = 0;}

主函数里面那个flag = 0 。 一定不能少了。否则只要一小会儿的功能,串口助手就卡了。。。。

这个例子里还有两条语句比较关键:

P1 = SBUF;//把SBUF寄存器中的数值赋给P1

SBUF = P1;//把P1的数值写入到SBUF

SBUF是这么写的:SBUF 串行数据缓冲寄存器,一个发送缓冲寄存器,一个接收缓冲寄存器。两个公用一个地址99H,但在物理上是两个独立的寄存器。那么如何区分是发送还是接收呢?就用语句来区

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top