关键词:共阳数码管的动态显示;调试错误注意点;数码管段码表;Delay函数的不同设置;小蜜蜂
一、知识点
1、动态显示的原理:
2、静态显示和动态显示的区别:
左上:静态显示原理,几个COM端输入1,表示该数码管被点亮,能够显示数字(输入0,则表示不会显示数字),另一端P0输入数字对应的段码(因为是公共端,所以只能显示一个数字)
左下:多位数字用静态显示方法呈现,但占用较多IO口
右:动态显示,轮流点亮数码管(COM只有一个是1,其余都是0)
二、实验
实验目的:
实验步骤:
S1:定义数码管段码表数组
代码:
unsigned char code SMG_duanma[18]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,
0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF,0xFF};
//数码管0-9,A-F,-,空白(b,d用小写表示)
S2:复制静态数码管的信道选择函数代码
unsigned char SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:P2=(P2&0x1F)|0x80;break;//1001 1111 //100->8
case 5:P2=(P2&0x1F)|0xA0;break;//1011 1111 //101->A
case 6:P2=(P2&0x1F)|0xC0;break;//1101 1111 //110->C
case 7:P2=(P2&0x1F)|0xE0;break;//1111 1111 //高三位清零&,|将高三位置值
}
}
S3:编写数码管显示函数
原理:
Y6控制位置,Y7控制段码 (显示的数字)
代码:
void DisplaySMG(unsigned char value,pos)//value表示数值,pos表示显示的位置
{
SelectHC573(6);//打开控制位置显示的总闸
P0=0x01<<pos;//0x01左移pos位,表示COM(pos)位置1
SelectHC573(7);//打开控制数字显示的总闸
P0=value;
}
S4:编写数码管动态显示函数
1.初步:利用静态数码管显示单个位的值为小模块组合显示2018
void Display_Dynamic()
{
DisplaySMG_Bit(SMG_duanma[2],0);
DisplaySMG_Bit(SMG_duanma[0],1);
DisplaySMG_Bit(SMG_duanma[1],2);
DisplaySMG_Bit(SMG_duanma[8],3);//分别在四个位置显示2、0、1、8
}
2.改进:让一个数码管显示一会儿(即延迟),再显示下一个数码管(轮流显示)
void SMG_Delay(unsigned int t)
{
while(t--);
}
void Display_Dynamic()
{
DisplaySMG_Bit(SMG_duanma[2],0);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[0],1);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[1],2);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[8],3);//分别在四个位置显示2、0、1、8
SMG_Delay(500);
}
实验现象:运行提示错误
心路历程:
最开始我只是看到说P2重定义,有很多的提醒,但一直觉得没什么错,不知道怎么解决,直到我翻到最上面的提示,才发现是段码表数组处有语法错误,修改后根据提示再调试再修改,解决了问题(和P2重定义无关)
经验总结:
1.出现错误提示从最上面看起,边修改边调试
2.注意函数是否有返回值,第二次错误提示即是unsigned char SelectHC573(unsigned char channel),我没有写返回值,所以需将其改为void类型
实验现象:
前4个数码管稳定显示2018(最后一个数码管有红色阴影)——>有残影说明你没消影,加个P0=0XFF就行了(弹幕),或者修改延时,延时越久越闪(视觉暂留现象,故不能长时间延时),用延时来消影
完整动态显示2018代码:
#include <REGX52.H>
unsigned char code SMG_duanma[18]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF,0xFF};
//数码管0-9,A-F,-,空白(b,d用小写表示)
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:P2=(P2&0x1F)|0x80;break;//1001 1111 //100->8
case 5:P2=(P2&0x1F)|0xA0;break;//1011 1111 //101->A
case 6:P2=(P2&0x1F)|0xC0;break;//1101 1111 //110->C
case 7:P2=(P2&0x1F)|0xE0;break;//1111 1111 //高三位清零&,|将高三位置值
}
}
void DisplaySMG_Bit(unsigned char value,pos)//value表示数值,pos表示显示的位置
{
SelectHC573(6);//打开控制位置显示的总闸
P0=0x01<<pos;//0x01左移pos位,表示COM(pos)位置1
SelectHC573(7);//打开控制数字显示的总闸
P0=value;
}
void SMG_Delay(unsigned int t)
{
while(t--);
}
void Display_Dynamic()
{
DisplaySMG_Bit(SMG_duanma[2],0);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[0],1);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[1],2);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[8],3);//分别在四个位置显示2、0、1、8
SMG_Delay(500);
}
void main(void)
{
while(1)
{
Display_Dynamic();
}
}
S5:在void Display_Dynamic()中添加--分隔符以及最后两位显示月份(固定的)
代码:
unsigned char yue=1;
DisplaySMG_Bit(SMG_duanma[16],4);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[16],5);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[yue/10],6);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[yue%10],7);
SMG_Delay(500);
实验现象:数码管稳定显示2018--01
S6:让月份动起来,从1->2->...->12->1->...
思路:
1.在while循环里实现yue++,并设定月份循环限制(if语句或直接yue%=12)
2.为了让yue++没有那么快(数码管显示才会稳定可见),需要加延时函数,但这个延时和上面设置的不同,while并不是空循环,而是有Display_Dynamic();(这里写延时是让1到12变慢 并且延时同时还要刷新数码管)
添加代码如下:
void Delay(unsigned char t)
{
while(t--)
{
Display_Dynamic();
}
}
void main(void)
{
while(1)
{
Display_Dynamic();
yue++;
if(yue>12)
yue=1;//也可以直接yue=yue%12;,不用if语句
Delay(100);
}
}
备注:类似定时器中断效果,你如果单纯用延时函数,8个数码管都会暗下去,直到下一次循环重新显示,不符合要求,但后面学了中断,就不会用这个方法了,这个方法效率低(B站弹幕)
完整代码:
#include <REGX52.H>
unsigned char yue=1;
unsigned char code SMG_duanma[18]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF,0xFF};
//数码管0-9,A-F,-,空白(b,d用小写表示)
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:P2=(P2&0x1F)|0x80;break;//1001 1111 //100->8
case 5:P2=(P2&0x1F)|0xA0;break;//1011 1111 //101->A
case 6:P2=(P2&0x1F)|0xC0;break;//1101 1111 //110->C
case 7:P2=(P2&0x1F)|0xE0;break;//1111 1111 //高三位清零&,|将高三位置值
}
}
void DisplaySMG_Bit(unsigned char value,pos)//value表示数值,pos表示显示的位置
{
SelectHC573(6);//打开控制位置显示的总闸
P0=0x01<<pos;//0x01左移pos位,表示COM(pos)位置1
SelectHC573(7);//打开控制数字显示的总闸
P0=value;
}
void SMG_Delay(unsigned int t)
{
while(t--);
}
void Display_Dynamic()
{
DisplaySMG_Bit(SMG_duanma[2],0);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[0],1);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[1],2);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[8],3);//分别在四个位置显示2、0、1、8
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[16],4);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[16],5);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[yue/10],6);
SMG_Delay(500);
DisplaySMG_Bit(SMG_duanma[yue%10],7);
SMG_Delay(500);
}
void Delay(unsigned char t)
{
while(t--)
{
Display_Dynamic();
}
}
void main(void)
{
while(1)
{
Display_Dynamic();
yue++;
if(yue>12)
yue=1;//也可以直接yue=yue%12;,不用if语句
Delay(100);
}
}
经验+1:新添加的Delay函数需要在 Display_Dynamic();之后出现,否则会出现失去Display_Dynamic();的定义而报错的现象(先定义后使用)
感谢B站小蜜蜂老师的教程,本笔记资料及代码均来自教程,仅作为个人复习、整理和学习交流用。