上一篇 Blog 主要记录了一些简单的外部中断和定时器的使用,在那个时候我们还只会让指定的数码管显示同一个数字,在这篇博文中,我们就记录一下几种让不同数码管显示不同数字(也叫做动态显示)的办法。
文章目录
一、动态显示思路的萌芽
我们试想:因为现在我们不是只会一次只能显示某一个数字嘛,那么,如果我们实现这样的效果:(以下描述规定在某一时刻只能亮一个数码管)第一秒第一个数码管亮“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,继续贴在着就有点长了。
好啦,这就是本次 Blog 的全部内容啦!我们学习了数码管的动态操作,对定时器的使用进一步深化,希望能够大家带来帮助!