一. 题目概述
-
目的
通过按键控制时钟和闹钟的操作; -
元器件
由数码管显示、单片机最小系统、按键输入和电机控制保护电路组成。 -
具体操作
二. 对问题的解读
- 问题的难点仍在单列按键上,还是老难点,如何根据设计要求做出相应的的效果。这届题目难在逻辑思路的复杂,如何抽丝剥茧理出正确的思路。还要注意一些细节,注意数据的边界属性。两个状态来回转换,如何不导致混乱。
- 如何让数码管闪烁?用定时还是时钟。
- 如何让灯1闪烁在规定的时间,还只能闪5秒
- 其他部分由模板写成即可
三. 问题的难点
a) 最难的还是单列按键,如何在不同模式下进行切换,并做普通的计算;
b) 数码管闪烁如何闪才是最好的。
c) 在定时中,实现双重的时间定时
d) 怎样定位数据的边界属性
四. 问题的解决 - 单列按键的处理:需要用到很多的标志位,模式的切换其实很简单,在前几届题中出现过,可以直接套用。只是这里比较特殊,需要再多写一层,为的是不导致混乱。例如if(shi==0) {alarm=0;shi=5;} 在未被按下之前,需要将闹钟的部分关闭,然后打开时钟的区域。剩下的和这个是一样的操作。实现加减时,比较反复复杂,需要区分时钟和闹钟两种状态,在特定的状态下,进行加或减。还要注意,加上时间获得的函数。
子函数部分:
void keyscan()
{
if(P300)
{
delayms(5);
if(P300)
{
if(LED_shan0)
{
if(shi0) {alarm=0;shi=5;}
else if(shi5) shi=1;
else if(shi1) shi=2;
else if(shi2) shi=3;
else if(shi3) shi=5;
}
else if(LED_shan==1)
{
LED_shan=0;
P2=0x80;P0=0xff;
}
}
while(!P30);
}
else if(P31==0)
{
delayms(5);
if(P31==0)
{
if(LED_shan==0)
{
if(alarm==0) {shi=0;alarm=5;}
else if(alarm==5) alarm=1;
else if(alarm==1) alarm=2;
else if(alarm==2) alarm=3;
else if(alarm==3) alarm=5;//不让显示了
}
else if(LED_shan==1)
{
LED_shan=0;
P2=0x80;P0=0xff;
}
}
while(!P31);
}
else if(P32==0)
{
delayms(5);
if(P32==0)
{
if(LED_shan==0)
{
if(shi==1) {if(shijian[2]==23) shijian[2]=0;else shijian[2]++;DS_init();}
else if(shi==2) {if(shijian[1]==59) shijian[1]=0;else shijian[1]++;jian=1;DS_init();}
else if(shi==3) {if(shijian[1]==59) shijian[1]=0;else shijian[0]++;jian=1;DS_init();}
else if(alarm==1) {if(shijian[1]==59) shijian[1]=0;else nao[2]++;}
else if(alarm==2) {if(shijian[1]==59) shijian[1]=0;else nao[1]++;}
else if(alarm==3) {if(shijian[1]==59) shijian[1]=0;else nao[0]++;}
}
else if(LED_shan==1)
{
LED_shan=0;
P2=0x80;P0=0xff;
}
}
while(!P32);
}
else if(P33==0)
{
delayms(5);
if(P33==0)
{
if(LED_shan==0)
{
s4==1;//按键被按下了
if(shi==5) {wendu=1;}
}
else if(LED_shan==1)
{
LED_shan=0;
P2=0x80;P0=0xff;
}
}
if((s4==1)&&(P33==1))//P33=1是松手时的检测
{
s4=0;wendu=0;
if(shi==1) {shijian[2]--;jian=1;DS_init();}
else if(shi==2) {shijian[1]--;jian=1;DS_init();}
else if(shi==3) {shijian[0]--;jian=1;DS_init();}
else if(alarm==1) {nao[2]--;}
else if(alarm==2) {nao[1]--;}
else if(alarm==3) {nao[0]--;}
}
}
}
主函数部分:
void main()
{
allinit();
DS_init();
Timer0Init();
yi=0;er=8;san=10;si=3;wu=0;liu=10;qi=0;ba=0;
while(1)
{
DS_get();
if(wendu==0)
{
if(shi==5)
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
else if(shi==1)
{
if(shijian[0]%2==1)
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
else
{
yi=11;er=11;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
}
else if(shi==2)
{
if(shijian[1]%2==1)
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
else
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=11;wu=11;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
}
else if(shi==3)
{
if(shijian[2]%2==1)
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
else
{
yi=shijian[2]/10;er=shijian[2]/10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=11;ba=11;
}
}
if(alarm==5)
{
yi=nao[2]/10;er=nao[2]%10;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
else if(alarm==1)
{
if(nao[0]%2==1)
{
yi=nao[2]/10;er=nao[2]%10;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
else
{
yi=11;er=11;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
}
else if(alarm==2)
{
if(nao[1]%2==1)
{
yi=nao[2]/10;er=nao[2]%10;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
else
{
yi=nao[2]/10;er=nao[2]%10;san=10;
si=11;wu=11;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
}
else if(alarm==3)
{
if(nao[2]%2==1)
{
yi=nao[2]/10;er=nao[2]%10;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=nao[0]/10;ba=nao[0]%10;
}
else
{
yi=nao[2]/10;er=nao[2]/10;san=10;
si=nao[1]/10;wu=nao[1]%10;liu=10;
qi=11;ba=11;
}
}
}
else if(wendu==1)
{
yi=11;er=11;san=11;si=11;wu=11;liu=Tempget()/10;qi=Tempget()%10;ba=12;
}
if((shijian[0]==nao[0])&&(shijian[1]==nao[1])&&(shijian[2]==nao[2]))
{
LED_shan=1;tt=0;miao=0;
}
-
数码管的闪烁,当时写题时,误以为要写定时器函数才能实现。其实并不是,直接在调用时间时,加上一个if的判断,也就是奇数秒亮,偶数秒的老套路,加以实现。
if(shijian[2]%2==1)
{
yi=shijian[2]/10;er=shijian[2]%10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=shijian[0]/10;ba=shijian[0]%10;
}
else
{
yi=shijian[2]/10;er=shijian[2]/10;san=10;
si=shijian[1]/10;wu=shijian[1]%10;liu=10;
qi=11;ba=11;
} -
实现双重定时,还是用到标志位。只不过需要多个标志位加以区分。
void time0() interrupt 1
{
tt++;miao++;if((tt==40)&&(LED_shan==1)) { tt=0; if(fla==0) {fla=1;P2=0x80;P0=0xfe;} else if(fla==1) {fla=0;P2=0x80;P0=0xff;} } if(miao==1000) { miao=0; LED_shan=0; P2=0x80;P0=0xff; }
}
-
定义数据的边界,仍然用到标志位。
if(LED_shan0)
{
if(alarm0) {shi=0;alarm=5;}
else if(alarm5) alarm=1;
else if(alarm1) alarm=2;
else if(alarm2) alarm=3;
else if(alarm3) alarm=5;//不让显示了
}
else if(LED_shan==1)
{
LED_shan=0;
P2=0x80;P0=0xff;
}
五.经验总结
这套题整体上比较难,难在实现比较繁杂,需要一点点的实现,不厌其烦的改程序,还要注意很多的细节问题。多个模式的切换必然会导致数据的跑串,这是就需要再以前的套路上进行变化。以此套题为例,3个数字不够,就多加一个加以区分。开这一模式时,就要将另一个关闭。并且还要多写一个数字,作为中间变量进行判断。
需要注意的是,以前的一些小技巧可以直接移植过来,如果没有太多的变化的话。做这道题时,就有一种熟悉感,而且不是一处两处出现过。
本届题目注重诸多的细节:在 “时钟显示”状态下,按下 S4 按键,显示温度数据,松开按键,返回“时钟显示”界面。这样的要求是对按键的深入考察,就要对按键的原理摸透。实现起来也不难,将松手检测部分进行替换,用if语句进行判别松手,实现灯的亮灭。
自己的几点要求:驱动这三大部分已经基本定型,平时需反复进行理解并辅以记忆,便可容易将底层驱动写好。每日除了将模板反复练习外,更为重要的是:将历届做过的真题,亲自打一遍,同样需要反复练习。