在春节期间,我有幸整理了电脑中的文件,偶然发现了一个以前完成的小项目,它是应一位初学者朋友的请求而制作的。该项目旨在控制一个8位的数码管,使其依次显示数字0到9。现在,我想与大家分享这个作品。
由于当时没有可用的开发板,我选择了使用Proteus软件进行电路的仿真实验。
以下是我在进行该项目时所使用的工作环境:
Keil uVision5
Proteus 8 Professional
使用的数码管
在开始之前,我们需要对数码管的相关知识有一个基本的了解。
数码管的基本构成单元是发光二极管。根据段数的不同,数码管可以分为七段和八段两种类型。八段数码管相比七段数码管多了一个用于显示小数点的发光二极管单元,这使得数码管能够更精确地展示所需显示的内容。此外,数码管还可以根据其能够显示的位数来分类,常见的有1位、2位、3位、4位、5位、6位、7位和8位等不同规格的数码管。
>数码管的内部工作原理
上图展示了一个数码管的内部结构示意图。一个完整的数码管显示部分由8个二极管组成,这与51单片机的8位结构相吻合。
根据内部发光二极管的公共连接端的不同,数码管可以分为共阳极接法和共阴极接法两种。在共阳极接法中,所有发光二极管的正极共同连接到电源VCC,通过控制每个发光二极管的负极是否接地来决定其是否发光。而在共阴极接法中,每个发光二极管的负极共同连接到地GND,通过控制每个发光二极管的正极是否接电源来决定其是否发光。
在图中,a到g的管脚分别控制着每个发光二极管的亮灭状态。因此,如果要显示数字1,只需要点亮b和c两段即可(通过单片机对应端口输出0x06信号);如果要显示数字5,则需要点亮a、f、g、c和d段,以形成数字5的形状(输出0x6d信号)。
>多位数码管的内部连接原理图
上图展示了4位数码管的内部连接方式。每位数码管的阳极(或阴极)都是相互连接的,而其他相同功能的引脚也相互连接。一个4位数码管共有12个控制引脚,而一个8位的数码管则有16个控制引脚,其中包括8个共阳(或共阴)端和8个用于控制a到g段显示内容的引脚。
74LS138译码器
从数码管的显示原理可以看出,为了使一个数码管能够显示不同的字符,需要对数码管中的每个二极管进行精确的控制。每个二极管都需要单片机的一个控制引脚来驱动,例如在实际应用中,一个8位的共阴极或共阳极数码管共有16个引脚,如果全部使用单片机引脚进行控制,将会非常浪费资源,因为单片机的引脚资源本身就是有限的。
为了解决这个问题,我们可以使用一个译码器作为数码管的位选择器,通过控制来决定哪一位数码管需要显示。
74LS138译码器的1到3脚是输入端,按从高到低的顺序分别为CBA;7到15脚是输出端,按从高到低的顺序分别为Y7到Y0。
工作原理如下:输入端输入三位二进制数,将其转换为十进制数,然后经过译码器后,输出端中对应于该十进制数的引脚(即Y引脚)会变为低电平,而其他引脚则保持高电平。例如:
当输入为000时,对应的十进制数为0,输出端的0号引脚会变为低电平,其余引脚保持高电平,即状态为1111 1110;
当输入为101时,对应的十进制数为5,输出端的5号引脚会变为低电平,其余引脚保持高电平,即状态为1101 1111。
三位二进制数可以表示0到7共8个数字,因此74LS138译码器可以控制8位数码管。
Proteus电路图
程序设计
#include <REGX51.H>
//延时函数
void delay(unsigned int ms){
int k,l;
for(k=0;k<ms;k++)
for(l=0;l<120;l++);
}
//一个数码管显示 0~f 十六进制数组
char numHex[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/**
选择数码管,并显示出对应的十进制数
index :数码管位下标
num :char numHex[] 数组对应十进制数的下标
*/
void setIndexNum(unsigned char index,unsigned char num){
switch(index){//数码管位选,74LS138译码器的输入
case 0:
P1_2=0;
P1_3=0;
P1_4=0;
break;
case 1:
P1_2=1;
P1_3=0;
P1_4=0;
break;
case 2:
P1_2=0;
P1_3=1;
P1_4=0;
break;
case 3:
P1_2=1;
P1_3=1;
P1_4=0;
break;
case 4:
P1_2=0;
P1_3=0;
P1_4=1;
break;
case 5:
P1_2=1;
P1_3=0;
P1_4=1;
break;
case 6:
P1_2=0;
P1_3=1;
P1_4=1;
break;
case 7:
P1_2=1;
P1_3=1;
P1_4=1;
break;
}
P3=numHex[num];//数码管显示字符
}
void main(){
//proteus 不用while即可循环,不明白
unsigned char i,j;
for(i = 0;i < 8;i++){
for(j = 0;j < 16;j++){
setIndexNum(i,j);
delay(300);
if(j >= 15) break;
}
if(i >= 7) break;
}
}