上一节我们得出一个结论,多位一体的数码管不可能在同一时刻显示多个不同数字,即使有多位选中的话,那显示的数字也会是相同的。这是由于他们共用引脚导致的这个现象。当然这也是为了节省引脚的连接方式,方便操作。
那这样的连接方式怎样才能让数码管同时显示不同数字呢?
这就是我们要实现的第二功能:动态数码管显示。就是利用人眼视觉暂留和数码管显示的余晖这个原理来实现的。比如我们先让数码管的第一位显示“1”,然后很快地让第二位显示“2”,很快地让第三位显示“3”......然后不断地让它扫描,就是很快地扫描的“1”“2”“3”“1”“2”“3”“1”“2”“3”......这样就可以同时显示123了。
这一节我们就来看看动态数码管显示的代码怎么写
新创建工程,把上一节的代码复制过来
多复制几段这个
改成
然后再加个1ms延时函数
复制过来改造成这样:
然后每次显示后就延时个200ms
编译无错误后看一下效果
这时我们看到动态数码管的第一第二第三位分别显示1 2 3,而且一直在来回扫描闪烁,并且看起来还不能同时显示1 2 3。
这还不是我们想实现的效果
怎么才能让这些数字看起来是静止的1 2 3?
我们需要把延时的时间改短一点,改成20ms看看效果
这样我们基本能看到1 2 3三个数字同时显示了,但是还是肉眼可见地在闪烁,再把延时时间缩短成10ms
这样看起来效果好多了,把延时时间所得越短,效果就越好,肉眼就越看不出数字在闪烁,就好像1 2 3三个数字是静态同时显示的一样。这勉强是我们想要达到的效果,但还不是最佳效果。
如果我们把延时代码先注释掉会出现什么情况呢?
这时候我们发现显示数字的位置是错乱的,3显示在了第一位数码管,2显示在了第四位数码管上。
这就是为什么我们前面不是直接让它显示三个数字,还要加个Delay慢慢来看,就是因为这个原因。
这种现象是数码管常见的问题,叫做数码管的消影(它在其他位数码管上显示的影子),为什么会出现影子呢?
首先数码管显示会有一个位选和段选。它就是位选-段选-位选-段选-位选-段选等等如此循环,但是因为单片机的速度很快,就在前一个位选段选到下一个位选和段选中间,上一位的数据就会篡到下一个数据里面去,因为他们是挨在一起的,当选中下一位的时候,上一位的数据自然就会过来,因为下一位的数据还没有到。所以就会出现显示数字篡位的问题
如果避免这个问题呢?
我们可以在下一个位选之前先把上一个段选清零。
可以在子函数中的段选结束后,加一个Delay 1ms,让它稳定地显示,因为如果立马清零的话,数码管就比较暗。然后加上P0=0x00;
这里的Delay还是保持注释状态
这是编译看看效果:
这次的效果非常完美,没有出现篡位的现象,没有肉眼可见地闪烁。是完美地静止状态的三个数字同时显示。
完整的代码如下:
#include <REGX52.H>
//定义数组
unsigned char NixieTable[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void Nixie(unsigned char location, Number)
{
//位选
switch(location)
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
//段选
P0=NixieTable[Number];
Delay(1);//延时1ms
P0=0x00;//清零
}
void main()
{
while(1)
{
Nixie(1,1);
//Delay(10);
Nixie(2,2);
//Delay(10);
Nixie(3,3);
//Delay(10);
}
}
以上就是这节想要实现的动态数码管显示的效果。
接下来总结一下额外的知识:
数码管驱动方式:
- 单片机直接扫描:硬件设备简单,但会耗费大量的单片机CPU时间。(也就是本节讲的这种方式)
另外以下两种模块也是通过单片机直接扫描的方式实现的。它是通过三根数据线和两根电源线就可以控制8个数码管,但是它也需要单片机扫描。
- 专用驱动芯片(推荐):内部自带显存、扫描电路,单片机只需告诉它显示什么即可
第二种方式就是只需要两根通讯线(通讯协议之后会学),只需要按照这个协议告诉它显示什么,它就自己不断地扫描数码管,而且不会出现闪烁。上图中的芯片是TM1640,只需要两根线就可以控制16位数码管显示任意数字。