【单片机技术】—— 数码管的动态显示方法与定时器

上一篇 BlogBlogBlog 主要记录了一些简单的外部中断和定时器的使用,在那个时候我们还只会让指定的数码管显示同一个数字,在这篇博文中,我们就记录一下几种让不同数码管显示不同数字(也叫做动态显示)的办法。

文章目录

一、动态显示思路的萌芽

我们试想:因为现在我们不是只会一次只能显示某一个数字嘛,那么,如果我们实现这样的效果:(以下描述规定在某一时刻只能亮一个数码管)第一秒第一个数码管亮“1”,第二秒第二个数码管亮 “2”、、、第六秒第六个数码管亮“6”,接着重复上面的循环。

如果间隔的时间不是1s,而是几毫秒甚至几微秒,那么人眼就会分辨不出来,看起来就像是同一时间6个数码管分别显示 “123456” 的效果。

我们可以如何实现上述思想呢?—— 通过定时器!我们可以让定时器计时,每到了规定时间,就往后移动一位。下面,我们看看代码部分:

1.1 代码和实验部分

代码如下:

#include<reg52.h>
#define uchar unsigned char   //宏定义
#define uint unsigned int

sbit WELA = P2^7;   //定义位选
sbit DULA = P2^6;   //定义段选

uchar number,position,t;
//number表示需要显示什么数,position表示数字显示的位置,t 表示定时器计时时间

uchar code table_DUAN[] = {0x06,0x5b,0x4f,
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,
                           0x39,0x5e,0x79,0x71};  //定义段选信号编码表(从1开始)

uchar code table_WEI[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; //定义位选信号编码表

void init();   //初始化函数,完成诸如启动定时器、赋初值等一系列操作

void main()
{
	init();
	while(1)
	{
  		if(t == 1)      
 		{
   			t = 0;
   			if(number == 6)     //因为我们最多显示到6
   			{
    				number = 0;
   			}
   			if(position == 6)  
   			{
    				position = 0;
   			}

   			DULA = 1;
   			P0 = table_DUAN[number];
  			DULA = 0;
   			number++;
 
   			P0 = 0xff;   //为了防止前面的段选信号在一瞬间会对下面的位选信号产生影响
 
   			WELA = 1;
   			P0 = table_WEI[position];
   			WELA = 0;
   			position++;
  	       }
 	}
}

void init()
{
	t = 0;
 	number = position = 0;

	TH0 = (65536-1000)/256;
	TL0 = (65536-1000)%256;

	TMOD = 0x01;

	EA = 1;
	ET0 = 1;

	TR0 = 1;
}

void timer0() interrupt 1
{
 	TH0 = (65536-1000)/256;
 	TL0 = (65536-1000)%256;
 	t++;
}

二、用delay()函数实现任意数字的显示

不过,大家注意到了吗:用上面的代码,如果想显示任意给定的数字,那么似乎有些麻烦,下面我们介绍一种通用方法:

如果给定了一个数字(假设是两位数),那么,我们可以直接把它的每一位(比如个位、十位、、、)分离出来,然后在一个while(1) 大循环里面显示了十位、延迟一小段时间,又去显示个位,再延迟一段时间。在这样的无限循环中,我们肉眼看到的就是“静止”的两位数了。

注意:如果想显示的是三位数,那么uchar类型就不再适用了,因为 uchar最大就是256,需要使用int

2.1 代码和实验部分

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit WELA = P2^7;
sbit DULA = P2^6;

uchar t,temp,shi,ge;

uchar code table_DUAN[] = {0x06,0x5b,0x4f,
            0x66,0x6d,0x7d,0x07,
            0x7f,0x6f,0x77,0x7c,
            0x39,0x5e,0x79,0x71}; 

void delay(uint);

void main()
{
	temp = 45;
 	shi = temp/10;
 	ge = temp%10;

	while(1)
	{
		DULA = 1;
  		P0 = table_DUAN[shi-1];
		DULA = 0;
		
		P0 = 0xff;

		WELA = 1;
  		P0 = 0xfe;
  		WELA = 0;

		delay(5);

		DULA = 1;
  		P0 = table_DUAN[ge-1];
  		DULA = 0;

		P0 = 0xff;

		WELA = 1;
  		P0 = 0xfd;
  		WELA = 0;

		delay(5);
	}
}

void delay(uint z)
{
 	uint x,y;
 	for(x=z;x>0;x--)
  		for(y=100;y>0;y--);
}

三、进阶部分

如果你觉得只是单纯显示一个数不够过瘾,那么我们现在看一个有趣的例子:我们给定一个数字,让这个数字每隔一秒减少一次,当减到100的时候,我们就让数码管保持在100这个数

那么,这个题目我们就可以通过第二节讲到的利用 delay() 显示任何数,以及定时器定时1s控制递减

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit WELA = P2^7;
sbit DULA = P2^6;

uchar t,bai,shi,ge;
uint temp;

uchar code table_DUAN[] = {0x3f,0x06,0x5b,0x4f,
            		   0x66,0x6d,0x7d,0x07,
            		   0x7f,0x6f,0x77,0x7c,
            		   0x39,0x5e,0x79,0x71}; 

void init();
void delay(uint);
void display(uint temp);

void main()
{
 	init();
 	temp = 145;
 	while(1)
 	{
  		if(t == 20)     //每经过1s,数字就递减一次
  		{
   			t = 0;
   			temp--;
   			if(temp == 100)    
   			{
    				TR0 = 0;   //当减小到100时,我们把计数器关了,他自然就不会递减
   			}
  		}
  		display(temp);   //普通的动态显示,和第二节类似,只不过我们现在把它封装在了函数里面   
 	}
}

void init()
{
 	WELA = 0;
 	DULA = 0;
 	
 	t = 0;
 	TH0 = (65536-50000)/256;
 	TL0 = (65536-50000)%256;
 	
 	TMOD = 0x01;
 	
 	EA = 1;
 	ET0 = 1;
 	
 	TR0 = 1;
}

void delay(uint z)
{
 	uint x,y;
 	for(x=z;x>0;x--)
  		for(y=100;y>0;y--);
}

void display(uint temp)
{
 	bai = temp/100;
 	shi = (temp-100*bai)/10;
 	ge = temp%10;

 	DULA = 1;
 	P0 = table_DUAN[bai];
 	DULA = 0;

	P0 = 0xff;

	WELA = 1;
	P0 = 0xfe;
	WELA = 0;

	delay(1);

 	DULA = 1;
 	P0 = table_DUAN[shi];
 	DULA = 0;

	P0 = 0xff;

 	WELA = 1;
 	P0 = 0xfd;
 	WELA = 0;

	delay(1);

	DULA = 1;
 	P0 = table_DUAN[ge];
	DULA = 0;

	P0 = 0xff;

	WELA = 1;
 	P0 = 0xfb;
 	WELA = 0;
 	
	dealy(1);

void timer0() interrupt 1
{
 	TH0 = (65536-50000)/256;
 	TL0 = (65536-50000)%256;
 	t++;
}

【补充二】:我们现在想实现这样的功能:数码管一开始显示765410,用定时器 T0 控制,每隔1s递减1次,同时,T0控制LED 以每隔0.5s的速度控制流水灯。当 765410递减到 765398 的时候让数码管保持现在的值,同时流水灯停止,并且全部闪烁,当闪烁持续3s之后,数码管显示 “HELLO”

这个题目的代码我晚点会上传到github,继续贴在着就有点长了。

好啦,这就是本次 BlogBlogBlog 的全部内容啦!我们学习了数码管的动态操作,对定时器的使用进一步深化,希望能够大家带来帮助!

上一篇:外部IC寄存器的位定义


下一篇:C# 委托 的语法 之一