数码管介绍
LED数码管:数码管是一种廉价,简单的显示器,是由多个发光二极管封装在一起组成的“8”字形的器件,在生活中也很常见,比如红绿灯的显示秒数的显示等。动态数码管版块与74H138译码器相连以达到以更少的接口控制更多的数码管,他们的开发板设计图分别如下所示:
现在了解了数码管的工作原理之后,我们就可以开始完成今天的任务了!
今日任务一:静态数码管的显示
由简到难,作为“点灯大师”,必须得先将点亮一个数码管并显示出一个数字吧,MCU的P2_4,P2_3,P2_2分别控制的是CBA(因为C是高位,所以是反着来的),P0端口直接就控制的是8个LED数码管,但是请注意第一个灯是LED8哦,其CBA端口对应的111,假设要点亮的值为2,不难得P0的的值为0x5B。所以最基础的代码如下:
#include <REGX52.H>
void main()
{
P2_4=1;
P2_3=1;
P2_2=1;
P0=0x5B;
while(1)
{
}
}
实验现象数码管LED8,也就是第一个数码管LED被点亮为2,现象如下:
但是目前稍加思索,就会发现如果要点亮其他灯,其他数字每次都要来给程序一个一个改值,还是很麻烦的,所以就用一个全局数组来存储P0的取值,额外定义一个函数,在函数里面用switch或者if判断来确定CBA的取值。代码如下:
#include <REGX52.H>
#include <intrins.h>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;
}
}
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};
void Nixie(unsigned char Location,Number)
{
switch(Location)//Location用来确定想要打开第几个灯,下面是对CBA的赋值
{
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];//P0可以直接被数组中的值来确定
}
void main()
{
while(1)
{
Nixie(1,2);//第一个LED数码管点亮为2
// Nixie(1,1);
// Delay(500);
// Nixie(2,2);
// Delay(500);
// Nixie(3,3);
// Delay(500);
// Nixie(4,4);
// Delay(500);
// Nixie(5,5);
// Delay(500);
// Nixie(6,6);
// Delay(500);
// Nixie(7,7);
// Delay(500);
// Nixie(8,8);
// Delay(500);
// Nixie(1,9);
// Delay(500);
// Nixie(1,10);
// Delay(500);
// Nixie(1,11);
// Delay(500);
// Nixie(1,12);
// Delay(500);
// Nixie(1,13);
// Delay(500);
// Nixie(1,14);
// Delay(500);
// Nixie(1,15);
// Delay(500);
}
}
初始来看,好像代码变得更加复杂了,但是实际上不是的,如果对晶体管LED的使用比较多这样函数的使用会简化了好多代码,而且也更直观,被注释的代码是测试值的正误,可以自己写代码之后用被注释的代码可以测试。
今日任务二:动态数码管的显示
由LED数码管的设计问题,每一次只能点亮一个LED数码管显示一个值,所以可以通过连续的高频度的暗亮来骗过眼睛以达到显示多个数字,这就是动态数码管的显示。有一个问题,假如我们需要显示连续的123,但是不能够直接单纯地在main函数里面写Nixie(1,1);Nixie(2,2) ; Nixie(3,3);这样会发生位置错乱的现象如下图所示:(降低曝光更清晰)
会发现第四个灯也点亮了,这是因为没有给数码消影,在LED数码管被点亮的时候,是先由位选选择,也就是CBA三个接口,再由段选去决定显示的数字,但是单片机的速度太快了,假如没有消影的行为,在选择下一个阶段的时候,上一个阶段的数据就会传到下一个阶段去,导致显示的问题,解决思路就是在段选之后将P0清零就可以解决了,只需要在Nixie()函数里面添加消影的操作就可以了,代码如下所示:
#include <REGX52.H>
#include <intrins.h>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;
}
}
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};
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);//这两行代码就是消影
P0=0x00;
}
void main()
{
while(1)
{
Nixie(1,1);
Nixie(2,2);
Nixie(3,3);
}
}
现象如下:
这次对LED数码管还算比较顺利,没有遇到什么问题 ,等会儿利用这个看能不能搞点有趣的玩意出来。
总结
LED数码管的学习主要是掌握了其设计图就能够点亮,不算特别难,但是要学会将几个数码管的表示用函数包装,这样会简便很多代码,完成点灯只需要掌握P0和P2那三个接口就可以了。
后续
在上完课之后,我做了一个能够运算最大四位数的加一减一以及加十减十运算,按照我的思路如果做八位可能会嵌套非常多,绝对不是因为我懒,也不是不会,只是四位更加有性价比。功能比较简单,程序设计得简单,所以大概只花了一个多小时便实现了该功能。下面是演示视频:
(如果没有看到视频就说明我录的视频还没有通过审核)
利用独立按键控制LED数码管实现加一减一加十减十
以下是代码:
#include <REGX52.H>
#include <intrins.h>
int ge=0;
int shi=0;
int bai=0;
int qian=0;
unsigned char LEDNumber=8;
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;
}
}
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};
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);
P0=0x00;
}
void show()
{
if(shi==0&&bai==0&&qian==0)
{
Nixie(LEDNumber,ge);
}
else if(bai==0&&qian==0)
{
Nixie(LEDNumber,ge);
Nixie(LEDNumber-1,shi);
}
else if(qian==0)
{
Nixie(LEDNumber,ge);
Nixie(LEDNumber-1,shi);
Nixie(LEDNumber-2,bai);
}
else if(qian!=0)
{
Nixie(LEDNumber,ge);
Nixie(LEDNumber-1,shi);
Nixie(LEDNumber-2,bai);
Nixie(LEDNumber-3,qian);
}
}
void AddandSubOne()
{
if (P3_1 == 0)
{
while (P3_1 == 0)
{
show();
}
Delay(10);
ge++;
if (ge > 9)
{
ge = 0;
shi++;
if (shi > 9)
{
shi = 0;
bai++;
if (bai > 9)
{
bai = 0;
qian++;
if (qian > 9)
{
ge = 0;
shi = 0;
bai = 0;
qian = 0;
}
}
}
}
}
else if (P3_0 == 0)
{
while (P3_0 == 0)
{
show();
}
Delay(10);
if(qian>0&&bai==0&&shi==0&&ge==0)
{
qian--;
bai=9;
shi=9;
ge=9;
}
else if(bai>0&&shi==0&&ge==0)
{
bai--;
shi=9;
ge=9;
}
else if(shi>0&&ge==0)
{
shi--;
ge=9;
}
else if(ge>0)
{
ge--;
if(ge<0)
{
ge=0;
}
}
}
}
void AddandSubTen()
{
if (P3_2 == 0)
{
while (P3_2 == 0)
{
show();
}
Delay(10);
shi++;
if (shi > 9)
{
shi = 0;
bai++;
if (bai > 9)
{
bai = 0;
qian++;
if (qian > 9)
{
ge = 0;
shi = 0;
bai = 0;
qian = 0;
}
}
}
}
else if (P3_3 == 0)
{
while (P3_3 == 0)
{
show();
}
Delay(10);
if(qian>0&&bai==0&&shi==0)
{
qian--;
bai=9;
shi=9;
}
else if(bai>0&&shi==0)
{
bai--;
shi=9;
}
else if(shi>0)
{
shi--;
if(shi<0)
{
shi=0;
}
}
}
}
void main()//K1加一,K2减一,K3加十,K4减十
{
while(1)
{
show();
AddandSubOne();
AddandSubTen();
}
}
总结:今天做的这个还是比较简单的,功能也达到了预期的效果,但是代码比较冗杂,一直在用if嵌套,我等以后我有其他思路了再来优化这个代码,而且还有几个问题,从视频中可以看出,在不涉及数字变化的LED数码管也会因为闪烁,影响观感,为了解决这个问题我放弃了一半解决按键的机械跳动问题,但是这样有带来了另外的问题,假如在按下按键之后松开得不果断就会出现那个按键又被按下的效果,导致加了多次效果,这个问题我写了一个实验代码,单独测试这个按键问题,我发现这个问题大概率是板子自带的问题,按键不灵敏,如果了解了按键的工作原理,就能够理解,你认为你没有松手,但是板子移位你松手了又按了下去。如果学到后面的知识能够解决这些问题,我会回来修改的。
都看到这里来了,点个赞吧!!!