通过K1~k4按键切换并实现四个不同功能
模式一:数码管静态显示
U1▢▢▢▢01
▢表示不显示数据
模式二:数码管动态显示
U2▢▢▢▢XX
(其中xx为00~10,每秒加一)
模式三:数码管动态显示
U3▢▢- - 03
(其中第5和第6位数码管显示的-以0.5s为间隔不断闪烁)
模式四:数码管静态显示
U4▢▢▢▢XX
(其中XX位00~99,每按一次显示的两个数字均加1)
按键响应时间<=20ms,并进行消抖处理
根据各个模式的要求可知,数码管的前两位都是显示当前模式,只要给相应位码和段码即可
模式1的主要要求就是最后两位显示01,同样也是给对应的位码和段码即可
模式2要求最后两位显示数字按1s的频率改变,那么这里我们需要写一个类似计时器的程序来计算一秒的时间,但是不能直接用延时函数,因为在延时函数执行的过程中我们是没有办法进行操作的,因此我们需要考虑其它的实现方法,这里我通过计算数码管的扫描此时来得到大致1s的时间。我们还需要加上每次进入模式二时、当数字满十时将数字归零的判断。
关于数码管扫描、分频和时间周期
时间周期:通常指一个时钟周期
机器周期:机器周期(Machine Cycle)是计算机中的一个基本时间单位,它指的是执行一条机器指令所需的时间。
(即机器周期≠时间周期,一个机器周期可以包含多个时间周期)
- 分频:在嵌入式系统设计中,我们有时需要将一个高频率的时钟信号分频得到一个较低的频率用于其他模块的工作。这种操作称为分频,常见的分频方式包括2分频、4分频、8分频、12分频等。分频的目的可以是为了减小系统的功耗、降低干扰、适配不同的模块工作频率等。
(分频的作用实际上是增长时钟周期(也可以降低功耗),绝大多数51单片机默认12分频,原因:老版51单片机使用复杂操作集,导致1个时钟周期内CPU根本无法完成一条指令,因此默认需要12个时钟周期)
STC89C52RC的晶振频率为11.0592MHz,即每秒震荡11.0592 * 1 000 000次(11.0592百万次)
12分频后得到每秒有921600个时间周期
每次扫描数码管大约需要1000个时间周期(来自前辈总结),每次需要扫描4个数码管,那么我们可以得到每秒的扫描次数(921600 / 1000 / 4 = 230.4次)
那么我们可以通过计算扫描次数来得到大致一秒的时间,用于任务2和任务3
模式3的要求类似于模式2,都是以一段时间为周期改变数码管的显示,同样通过计算扫描次数来计时
模式4的要求为每按一下K4,显示的数字加一,那么这里我们需要一段代码用于判断K4是不是被第一次按下(即K4被按下前是否处于模式4),当K4是第一次按下时,将计数器归零,否则计数器加1,最后在数字达到99时,加1则归零
具体实现代码如下
这样写最简单直接,还有精简的空间
#include
unsigned char NixieTable[12] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x3E, 0x40};
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, U, -对应的段码
void NixieTube_Display(unsigned char location, unsigned char num)
//分别传入显示位置、显示内容
{
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[num];
Delay(1);
//让数码管稳定显示,否则亮度会变低
//Delay写成了一个通用延时函数放在头文件了
//注意STC89C52RC的晶振频率为11.0592MHz,在创建延时函数时应注意选择
P0 = 0x00;
//清零
}
void main()
{
//用于标记当前运行模式
int mark = 0;
//用于标记模式三中,5、6号数码管是否显示
int mark2 = 0;
//用于标记模式四是第一次切换还是增加数字
int mark3 = 1;
//用于模式二的计时
int index1 = 0;
//用于模式三的计时
int index2 = 0;
int num1 = 0;
int num3 = 0;
int D_num1 = 0;
int D_num2 = 0;
while(1)
{
//这个地方如果把消抖和判断放在外面,由于每次扫描都要经过消抖的延时,扫描速度会变慢,所以写一个判断
//当有按键被按下时进入消抖和判断,如果没有,直接跳过这个过程,进行下一次扫描
if(P31 == 0 || P30 == 0 || P32 == 0 || P33 == 0)
//按键检测
{
Delay(10);
//消抖
if(P31 == 0)
{
mark = 1;
mark3 = 1;
//当进入其它模式时,将mark3置1,表示当切换到模式四时,应显示0
}
if(P30 == 0)
{
mark = 2;
num1 = 0;
//时间归零
index1 = 0;
//计时器归零
mark3 = 1;
}
if(P32 == 0)
{
mark = 3;
index2 = 0;
//计时器归零
mark2 = 0;
mark3 = 1;
}
if(P33 == 0)
{
mark = 4;
//num3++;
if(mark3 == 1)
{
num3 = 0;
mark3 = 0;
}
else
{
num3++;
}
}
while(P31 == 0 || P30 == 0 || P32 == 0 || P33 == 0);
Delay(10);
}
else
{
switch (mark)
{
case 1:
NixieTube_Display(1, 10);
NixieTube_Display(2, 1);
NixieTube_Display(7, 0);
NixieTube_Display(8, 1);
break;
case 2:
NixieTube_Display(1, 10);
NixieTube_Display(2, 2);
index1++;
if(index1 == 230)
//计算扫描次数
{
if(num1 == 10)
{
num1 = -1;
//当计时到10秒时,设为-1,加上1为0
}
num1++;
index1 = 0;
}
if(num1 <= 9)
{
NixieTube_Display(7, 0);
NixieTube_Display(8, num1);
}
if(num1 == 10)
{
NixieTube_Display(7, 1);
NixieTube_Display(8, 0);
}
break;
case 3:
NixieTube_Display(1, 10);
NixieTube_Display(2, 3);
NixieTube_Display(7, 0);
NixieTube_Display(8, 3);
index2++;
if(index2 == 100)
//每0.5秒切换一次
//这里的扫描更慢一点,所以设定的次数应该更低
{
mark2++;
index2 = 0;
}
if(mark2 % 2 == 0)
{
NixieTube_Display(5, 11);
NixieTube_Display(6, 11);
}
if(mark2 % 2 == 1)
{
;
}
break;
case 4:
NixieTube_Display(1, 10);
NixieTube_Display(2, 4);
// if(num3 <=9)
// {
// NixieTube_Display(7, 0);
// NixieTube_Display(8, num3);
// }
// else if(num3 > 9 && num3 <= 99)
// //两位数
// {
// D_num1 = num3 / 10;
// D_num2 = num3 % 10;
// NixieTube_Display(7, D_num1);
// NixieTube_Display(8, D_num2);
// D_num1 = 0;
// D_num2 = 0;
// }
// else
// //三位数归零
// {
// num3 = 0;
// }
if(num3 == 10)
{
num3 = 0;
}
NixieTube_Display(7, num3);
NixieTube_Display(8, num3);
break;
}
}
}
}