2024年八月六号,编写
这一节老师教了两个实验:4-1 静态数码管显示
4-2 动态数码管显示
如图4-1所示,数码管其实就一个显示器。LED就是发光二极管;LED数码管也就是由多个发光二极管封装在一起的显示器。
图4-1
1、单个数码管引脚定义
数码管的接法,有共阳和共阴之分。我们使用的51单片机的数码管接法为共阴接法,如图4-2所示,图片的8个LED(发光二极管)都接在了引脚3和8上面。其中上面是发光二极管的负极接在了引脚3和8上面,这种数码管接法就属于共阴接法;下面是发光二极管的正极接在了引脚3和8上面,这种数码管接法就属于共阳接法。
共阴接法,如果给引脚3和8高电平,则LED则永远不亮;共阳接法,如果给引脚3和8低电平,则LED则永远不亮;
图4-2
如图4-3左图所示,数码管为共阴接法时(表示数码管里面的发光二极管的接法),位选(决定那数码管亮)处给低电平(位寄存器给0),段选(一个数码管有8个LED,有8段)处给高电平(位寄存器给1),这一段的LED才会亮。数码管为共阳极接法,如图4-3右图,原理一样。
图4-3
段选,如图4-4所示,一个数码管有8个LED灯,分别是:A、B、C、D、E、F、G、DP,这8个(也叫8段)LED,段选是为了控制这些段LED亮或者灭,让这些段形成想要的数字。
图4-4
2、开发板四位一体的数码管引脚定义
前面说的是一个数码管,这里讲的是4个数码管连在一起。那么就会有4个共阴或者共阳引脚点。4个数码管的每一段都是对应的接在同一个引脚,比如4个数码管的A段LED接在一起、B段LED接在一起等,如图4-4所示。这样就会导致,不同的数码管会显示相同的数字,所以得用延时函数,通过在while循环中快速的换数字(也就是说,数字停留的时间小于人眼观察的时间,这样我们就会观察不到数字波动)。
如图4-4所示,以共阴接法为例,通过给引脚12、9、8、6高电平或者低电平(位寄存器1/0),就可以选择哪个数码管亮,比如如果想让引脚8对应的数码管亮,其他的数码管暗,我们可以让引脚8的位寄存器值为0,其他的共阴引脚为1。
图4-4
3、原理图
先尝试自己分析下原理图4-5和4-6,然后再去看下面的解答。
图4-5
图4-6
在单片机数码管项目过程中,一般都是如图4-7所示,通过控制8个数码管,来实现哪些数码管亮并且显示哪个数字。我们用的51单片机,数码管采用共阴接法,所以要想让数码管亮,则位寄存器为0,低电平。
图4-7
如图4-8所示,位选。位选:也就是选择哪一个数码管亮。从图中,我们可以看到用三个接口(P2_1、P2_2、P2_3)来控制8个LED灯(并没有按照一一对应的那种控制),这样可以节约接口,二进制(111)刚好可以控制8个灯。一定要注意高位对高位,数据的高位对应二极管的高位,比如:P2_4(C)对应位寄存器的值位1、P2_3(B)对应位寄存器的值位0、P2_4(A)对应位寄存器的值位0,则二进制为100,相当于数字4,则点亮LED5。
注意,二进制000,点亮的是LED1。
图中的G1、G2A、G2B,这块板子的开发人员已经为我们接好对应的高电平和低电平了,单片机通电就会自动工作,承担使能的作用。
图4-8
如图4-9所示,段选。段选:也就是让数码管显示具体的数字。从图中我们可以看到通过P0接口对LCD进行一一对应的控制。单片机中:一定要注意高位对高位,也就是数据的高位对应二极管的高位。正如图中所示,想让数码管显示数字6,也就是让B段LED和DP段LED不亮,其他段都亮。我们可以让B段LED和DP段LED处的位寄存器值位0,因为最下面是P0_7,所以数据的最高位是P0_7所对应位寄存器的值,二进制应该是0111 1101,对应十六进制应该是0x7D。
图4-9
如图4-10所示,使用注意:数码管接法为共阴接法的数码管断码表,比如:想让数字0显示在数码管上面,直接使用十六进制0x3F(令P0=0x3F)。也就是说,上面为想显示的数字或者字母,下面则是P0等于十六进制的程序就行了,属于程序就会显示。
图4-10
5、函数与数组
图4-11
图4-12
如下图:子函数,无参数,无返回值
图4-13
如下图:子函数,有参数x,无返回值。如果主函数中给x=8,则子函数中输出8,在主函数中也会输出8。
图4-14
如下图:子函数,有参数x,有返回值。a=子函数的整个函数值(整个函数体),也就是返回值6,所以a=6。
图4-15
4-1 静态数码管显示
如图4-9所示,数码管位置从左到右依次是:LED8、LED7、LED6...LED1。
所以,想要让第一个数码管显示数字,实际上是让LED8亮,所以代码中P2_4=1,P2_3=1,P2_2=1。
#include <REGX52.H>
unsigned char NiXieTube[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
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=NiXieTube[Number];
}
void main()
{
NiXie(6,6);
while(1)
{
}
}
4-2 动态数码管显示
需要循环扫描,while()循环中编写;
需要加入延时函数;
#include <REGX52.H>
unsigned char NiXieTube[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
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=NiXieTube[Number];
}
void main()
{
while(1)
{
NiXie(1,1);
NiXie(2,2);
NiXie(3,3);
}
}
上面代码数码管的数字跑到其他的数码管上面,数字重叠,也就是说会有篡位;所以数码管需要消除影子(消影)
图4-16
解决方法如下所示:
图4-17
图4-18
#include <REGX52.H>
void Delay(unsigned char xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
unsigned char NiXieTube[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
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=NiXieTube[Number];
Delay(1);//延迟1毫秒,让数字显示更稳定,不然数字亮度会暗
P0=0x00;//清零
}
void main()
{
while(1)
{
NiXie(1,1);
NiXie(2,2);
NiXie(3,3);
}
}
本文用的就是单片机直接扫描:会耗费大量的单片机CPU时间,会遇到闪烁、不显示的问题
专用驱动芯片(比如:TM1640)