51单片机使用定时器进行数码管动态扫描程序

数码管是51单片机学习中比较基础的一个模块,为简化电路连接,提高系统可靠性,降低制造成本,多位数码管广泛采用动态扫描的方式进行显示。如果程序编写不当,数码管动态扫描容易出现亮度不均匀、亮度过低、重影等现象。很多初学者会在主函数中使用while(1)循环,结合delay函数不断扫描,但这样得不断调用display扫描,如果单片机还要执行别的程序时,就会由于扫描不及时,导致各种问题。此外,在控制段选位选的先后顺序上,如果程序不当,则会造成显示重影等问题。在此给出一个稳定可靠的程序方案。


电路连接:P1口通过两个74HC573分别连接到八位数码管的段选和片选,段选、位选由P3.4和P3.5控制,低电平锁存

#include 
 
 #define DIGI_PORT P1 // 宏定义数码管端口,如果端口改变,只需修改这一句即可
 #define DIGI_NUM 8 // 宏定义数码管个数
 
 sbit DULA = P3^4;
 sbit WELA = P3^5;
 
 unsigned char digiBuf[DIGI_NUM]; //数码管缓冲区
 
 unsigned char code DigiTable[] = {
 	0x3F,/*0*/
 	0x06,/*1*/
 	0x5B,/*2*/
 	0x4F,/*3*/
 	0x66,/*4*/
 	0x6D,/*5*/
 	0x7D,/*6*/
 	0x07,/*7*/
 	0x7F,/*8*/
 	0x6F,/*9*/
 	0x00,/* */
 };
 
 /* 
 初始化定时器0,方式1,11.0592MHz晶振时,每5ms进一次中断,
 如果只有4位数码管,10ms即可,间隔长度根据实际情况调整,
 在保证不闪烁的情况下,尽可能加长间距以减小对CPU资源的消耗
 */
 void initDigi()
 {
     TMOD = 0x01;
     TH0 = 0xEE;
     TL0 = 0x00;
     EA = 1;
     ET0 = 1;
     TR0 = 1;
 }
 
 void main()
 {
 	digiBuf[0] = 10; // 为10则该位不显示
 	digiBuf[1] = 1;
 	digiBuf[2] = 2;
 	digiBuf[3] = 3;
 	digiBuf[4] = 4;
 	digiBuf[5] = 5;
 	digiBuf[6] = 6;
 	digiBuf[7] = 7;
 	initDigi();
 	while(1);
 }
 
 // 定时器0函数每隔一段时间运行一次
 void displayTimer0() interrupt 1
 {
 	static unsigned char digiPos = 0; // 当前需要显示的数码管,此处使用静态局部变量,或者全局变量,不可使用默认局部变量
     TH0 = 0xEE;
     TL0 = 0x00;
 	// 位选关闭所有数码管,否则可能出现重影(下面段选改变之后,位选改变之前,上一次已经位选打开的数码会显示错误的信息)
 	DIGI_PORT = 0xFF;	//这一句如果和下一句位置交换,可能产生重影,具体见http://blog.csdn.net/jzj1993/article/details/8563337
 	WELA = 1;
 	WELA = 0;
 	// 这里进行段选(此时所有数码管都已关闭,不会显示错误信息)
 	DIGI_PORT = DigiTable[digiBuf[digiPos]];
 	DULA = 1;
 	DULA = 0;
 	// 这里根据digiPos进行位选
 	switch(digiPos) {
 		case 0:	DIGI_PORT = ~(1 << 0); break; // 打开第0个数码管
 		case 1:	DIGI_PORT = ~(1 << 1); break; // 打开第1个数码管
 		case 2:	DIGI_PORT = ~(1 << 2); break; // 打开第2个数码管
 		case 3:	DIGI_PORT = ~(1 << 3); break; // 打开第3个数码管
 		case 4:	DIGI_PORT = ~(1 << 4); break; // 打开第4个数码管
 		case 5:	DIGI_PORT = ~(1 << 5); break; // 打开第5个数码管
 		case 6:	DIGI_PORT = ~(1 << 6); break; // 打开第6个数码管
 		case 7:	DIGI_PORT = ~(1 << 7); break; // 打开第7个数码管
 	}
 	WELA = 1;
 	WELA = 0;
 	// 改变digiPos值,为下一次进入此函数做准备
 	digiPos++;
 	if(digiPos == DIGI_NUM)
 		digiPos = 0;
 }

Proteus仿真通过



源码及Proteus仿真文件点此链接下载


你可能感兴趣的:(单片机相关)