共阳数码管

数码管就是由LED组成的。capture_20240229204119212

每个数码管的代号如图所示,按abcd顺时针走一圈即可。我们让P0=0x00就能点亮所有数码管(per)。

如果我们要让数码管成为一个2,那么就是

dp g f e d c b a
1 0 1 0 0 1 0 0

换算为十六进制就是(从右向左!!!!)

1
P0=0xa4;

同理,0的话就是

dp g f e d c b a
1 1 0 0 0 0 0 0

即:

1
P0=0xc0;

不过听说比赛的时候赛点资源包里面是有数码管数字的十六进制的…..

接下来我们看原理图。

capture_20240229205434728

控制数码管,我们是由com公共端控制的,capture_20240229205434728

abcd口由U7控制。端口连接情况如图所示,依然存在锁存器,依然存在或非门

com连接情况也是显而易见。由U8控制。

不过需要注意的是,我们一共有8个数码管,每个阴极a和a,b和b都是接在一起的,如果我们需要显示0,那所有数码管都会只显示0。

因此,需要的线不是72个,而是16根线。具体如何操作我们后面再说。

静态数码管

下面我们开始写代码:

1
2
3
4
5
6
7
#include <reg52.h>
#define uint unsigned int
#define uchar unsignded char
sbit LSA =P2^5;
sbit LSB =P2^6;
sbit LSC=P2^7;
code uchaar segment[10] = (0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90);//把十个数码管的数字十六进制放进一个叫 segment的数组里去。code 意思就是我们以后不会再更改它了。

capture_20240302100404991

当我们编译成功时,会看到下面状态栏里的内容capture_20240302100821624

date是程序变量大小,xdate是外部存储器,code是存放了我们刚才的数组。

我们上一次学习了LED,蜂鸣器和继电器,每次我们都要重新定义573锁存器的输出,所以,我们写一个新的函数,用来调用我们需要的功能。

函数定义如下:

1
2
3
4
5
6
7
8
9
10
void hc573(unchar channel)
{
switch(channel)
{
case 4:LSC = 1;LSB = 0; LEA = 0;break;
case 5:LSC = 1;LSB = 0; LEA = 1;break;//LED
case 6:LSC = 1;LSB = 1; LEA = 0;break;//数码管
case 7:LSC = 1;LSB = 0; LEA = 1;break;
}
}

函数初始化

1
2
3
4
5
6
7
void init ()
{
hc573(5);
P0 =Ox00;//控制第几个数码管量
hc573(4);
P0 = 0xff;//数码管显示8
}

定义数码管函数:

1
2
3
4
5
6
7
void SMG(uchar seg)
{
hc573(6);
P0 = 0xff;
hc573(7);
P0 = segment[seg];
}

主函数:

1
2
3
4
5
6
7
8
void main()
{
init();
while(1)
{
SMG[7];
}
}

然后,我们的数码管就会全部显示数字7了。

动态数码管

首先,我们的数码管是没法同时显示不同数字的。

那我们该怎么样才能让数码管同时显示不同数字呢?

我们没法改变数码管,但能用数码管欺骗我们的眼睛。

我们可以让第一个数码管显示1,然后熄灭其他数码管,再过1ms.让第二个数码管显示2,同时熄灭第一个和其他数码管,如此循环往复,就能欺骗我们的眼睛了。

这个效果叫做,余晖效应

我们开始改代码:

1
2
3
4
5
6
7
8
void SMG(uchar pos,seg)
{
hc573(6);
P0 = 0x01<< (pos-1);//(数码管位选)让一个数码管亮,pos是1,第二个pos为2.
hc573(7);//数码管段选
P0 = segment[seg];
delay_ms(1);//记得在前面定义一个延时函数嗷
}

定义显示数字:20240302

1
2
3
4
5
6
7
8
9
10
11
void display()
{
SMG(1,2);//第一位是位选,第二位是段选,这一行的意思是第一个数码管显示2
SMG(2,0);
SMG(3,2);
SMG(4,4);
SMG(5,0);
SMG(6,3);
SMG(7,0);
SMG(8,2);
}

主函数

1
2
3
4
5
6
7
8
void main()
{
init();
while(1)
{
display();
}
}

然后就完成了。

不过,我们会发现,没有亮的地方有残影。

这里,我们就需要进行数码管消隐

数码管消隐

出现的原因就是先进行位选,再进行段选,进行第二次循环的时候,上一次段选的状态会延续到我下一次位选。这样就会出现残影。

解决方法就是直接在每一次循环的时候,在位选前面加一次段选,令P0 = 0xff;

于是,我们进行消隐处理后的代码就是:

1
2
3
4
5
6
7
8
9
10
void SMG(uchar pos,seg)
{
hc573(7); //消隐
P0 = 0xff;
hc573(6); //数码管位选
P0 = 0x01<< (pos-1);
hc573(7); //数码管段选
P0 = segment[seg];
delay_ms(1);
}

数码管特殊字符

字母

字母的话我们和数字方法一样,这里不过多赘述。

当我们需要调用的时候,记得在我们放入字母的segment数组中进行调用。

我们的数码管显示函数是这样的:

1
2
3
4
5
6
7
8
9
10
11
void display()
{
SMG(1,2);
SMG(2,0);
SMG(3,2);
SMG(4,4);
SMG(5,0);
SMG(6,11);//后三个数码管就会显示我们已经编辑好的字符。
SMG(7,12);
SMG(8,13);
}

小数点

如果是显示小数点的话,那我们让dp输出为0就好了,这样的话我的数字要全部重新写。当然我们还有更加便捷的方法。

我们先举个狸子

如果是显示数字1

11111001

变为

01111001

这里改变的只有最后一位,所以我们的思路就是保留前七位,更改最后一位。

这里我们使用&运算符。

&和1效果为保留,&0效果就是清除。

所以,我们搞出来一个

01111111就可以把最后一位的dp位置清除为0.

所以,我们的代码更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void SMG(uchar pos,seg)
{
hc573(7);
P0 = 0xff;
hc573(6);
P0 = 0x01 << (pos-1);
hc573(7);
P0 = segment[seg];
delay_ms(1);
}

void SMG1(uchar pos,seg)//让每一数字显示小数点
{
hc573(7);
P0 = 0xff;
hc573(6);
P0 = 0x01 << (pos-1);
hc573(7);
P0 = segment[seg]&0x7f;//清除最后一位
delay_ms(1);
}

显示函数更改为:

1
2
3
4
5
6
7
8
9
10
11
void display()
{
SMG(1,2);
SMG(2,0);
SMG(3,2);
SMG(4,4);
SMG(5,0);
SMG1(6,11);//这样就好了。
SMG1(7,12);
SMG1(8,13);
}