11. 静态数码管显示
- 11.1. 数码管的介绍-开发板上数码管原理图如下
-
11.2. LED数码管:数码管是一种简单、廉价的显示器,是由多个发光二极管封装在一起组成“8”字型的器件:
-
11.3. 一位数码管的引脚定义和介绍;共阴极连接,共阳极连接。
-
11.4. 对于单个数码管(以共阴极为例),公共端3,8接地称为位选,如果需要点亮相应的数码管显示具体数据,就需要相应的ADP输入端输入相应高电平1,称为断码,如需要数码管显示6,则ADP的段码为 1011 1110B;共阳极的数码管正好相反;
-
11.5. 四位数码管介绍;
-
11.6. 如果需要4位数码管(以共阴极数码管为例)的第3位(从左往右数)显示1,则数码管的位选码为1101B;段码为:0110 0000B
-
11.7. 考虑到数码管驱动端口数量的限制,利用人眼视觉暂留和数码管亮灭余晖延时,如果需要数码管多位同时显示不同数据,需要用数码管扫描显示的办法,即动态数码管显示;
-
11.8. 因为开发板上面2个4位数码管的共阴极由74HC138来进行驱动,即只占用3个单片机IO引脚控制8个数码管段位,以节省单片机引脚使用。
-
11.9. 单片机低电平驱动的原因是单片机高电平输出电流有限,驱动有限,故采用低电平驱动比较有效;
-
11.10. C51数组的概念
•数组:把相同类型的一系列数据统一编制到某一个组别中,可以通过数组名+索引号简单快捷的操作大量数据
int x[3]; //定义一组变量(3个)
int x[]={1,2,3}; //定义一组变量并初始化
x[0] //引用数组的第0个变量
x[1] //引用数组的第1个变量
x[2] //引用数组的第2个变量
引用x[3]时,数组越界,读出的数值不确定,应避免这种操作
- 11.11.C51子函数的概念
•子函数:将完成某一种功能的程序代码单独抽取出来形成一个模块,在其它函数中可随时调用此模块,以达到代码的复用和优化程序结构的目的
void Function(unsigned char x, y) //void 无返回值,如果Function前加int 有返回值,有返回值的 // 在程序中需要定义一个变量,把返回值赋值给这个变量;
{
}
返回值 函数名(形参)
{
函数体
}
- 11.11. 测试程序,数码管第四位显示6,数码管位选Y3=0;数码管段选B, DP=0,段码为0x7d;
位选码 | P2_3 | P2_2 | P2_1 | 数码管从左到右第几位 |
---|---|---|---|---|
Y0 | 0 | 0 | 0 | 1 |
Y1 | 0 | 0 | 1 | 2 |
Y2 | 0 | 1 | 0 | 3 |
Y3 | 0 | 1 | 1 | 4 |
Y4 | 1 | 0 | 0 | 5 |
Y5 | 1 | 0 | 1 | 6 |
Y6 | 1 | 1 | 0 | 7 |
Y7 | 1 | 1 | 1 | 8 |
#include <REGX52.H>
void main()
{
P2_1=1;
P2_2=1;
P2_3=0;
while(1)
{
P0=0x7d;//数码管第四位显示6
}
}
Proteus模拟没有问题:
- 11.12. 数码管显示子函数(什么位置显示什么数),测试程序第7位显示6:
#include <REGX52.H>
void NixieTube(unsigned char Location,Number)
{
switch(Location)
{
case 8:P2_3=1;P2_2=1;P2_1=1;break;
case 7:P2_3=1;P2_2=1;P2_1=0;break;
case 6:P2_3=1;P2_2=0;P2_1=1;break;
case 5:P2_3=1;P2_2=0;P2_1=0;break;
case 4:P2_3=0;P2_2=1;P2_1=1;break;
case 3:P2_3=0;P2_2=1;P2_1=0;break;
case 2:P2_3=0;P2_2=0;P2_1=1;break;
case 1:P2_3=0;P2_2=0;P2_1=0;break;
}
P0=0x7d;
}
void main()
{
NixieTube(7,2);
while(1)
{
}
}
Proteus测试模拟通过
- 11.13. 数码管段码表用数组的形式加入函数中
0 1 2 3 4 5 6 7 8 9 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
A B C D E F 空
0x77,0x7C,0x39,0x5E,0x79,0x71,0x00,
- 11.14. 完整数码管显示子函数,测试第5位显示9没问题;
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void NixieTube(unsigned char Location,Number)
{
switch(Location)
{
case 8:P2_3=1;P2_2=1;P2_1=1;break;
case 7:P2_3=1;P2_2=1;P2_1=0;break;
case 6:P2_3=1;P2_2=0;P2_1=1;break;
case 5:P2_3=1;P2_2=0;P2_1=0;break;
case 4:P2_3=0;P2_2=1;P2_1=1;break;
case 3:P2_3=0;P2_2=1;P2_1=0;break;
case 2:P2_3=0;P2_2=0;P2_1=1;break;
case 1:P2_3=0;P2_2=0;P2_1=0;break;
}
P0=NixieTable[Number];
}
void main()
{
NixieTube(5,9);
while(1)
{
}
}
Proteus中测试没有问题;
12. 动态数码管显示
- 12.1. 动态数码管显示采用:实际程序例子引出->发现问题->解决问题的思路来进行学习推进的;如下为程序引例,程序要实现的效果是数码管第1~3位显示123这3个数字,思路是沿用上节数码管显示函数,每显示一位数字延时一段时间(因为视觉暂留现象会同时看到123这3个数字的显示。
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void delayxms(unsigned int t);
void NixieTube(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];
}
void delayxms(unsigned int t) //@12.000MHz 延时函数
{
while(t--)
{
unsigned char data i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
while(1)
{
NixieTube(1,1);
delayxms(200);
NixieTube(2,2);
delayxms(200);
NixieTube(3,3);
delayxms(200);
}
}
- 12.2. 以上程序普中开发板运行效果是数码管显示的123数字像是幻灯片,尝试将delayxms(200)改为delayxms(2)后会发现有重叠阴影,有重叠阴影的原因是数码管运行原理是依据:位选-段选-位选-段选-位选-段选的顺序来运行,过快的运行速度导致数据会有“串位”的问题,解决的办法是每显示一位后延时1ms,同时数码管熄屏一次,据此在以上程序的基础上需要在数码管显示子函数中加上延时1ms和数码管清屏的语句:
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void delayxms(unsigned int t);
void NixieTube(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];//数码管消影,因为位选-段选-位选-段选,段选数据与位选穿位导致
delayxms(1); //数码管稳定显示1ms;
P0=0x00;//数码管清屏;
}
void delayxms(unsigned int t) //@12.000MHz 延时函数
{
while(t--)
{
unsigned char data i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
while(1)
{
NixieTube(1,1);
//delayxms(2);
NixieTube(2,2);
//delayxms(2);
NixieTube(3,3);
//delayxms(2);
}
}
proteus程序演示画面
- 12.3. 同时注意程序语句开头 // 注释行符号的用法,将不需要编译的程序行注释掉,如果下次需要该程序行参与编译,则将开头的 //删除,修改程序便捷一点