|
发表于 2012-11-4 10:00:52
|
显示全部楼层
用按键和数码管以及单片机定时器实现一个简易的可以调整的时钟,要求如下:
8位数码管显示,显示格式如下
时-分-秒
XX-XX-XX
要求:系统有三个按键,功能分别是调整,加,减。在第一次按下调整键时候,停止走时,显示秒的两位数码管以1 Hz 频率闪烁;如果第二次按下调整键,则分开始闪烁,秒恢复正常显示;如果第三次按下调整键,则时开始闪烁,分恢复正常显示;如果第四次按下调整键,时恢复正常显示,开始走时。在数码管闪烁的时候,按下加或者减键可以调整相应的显示内容。
/*****************************
作者:liyang
日期:2012年10月27日
目标MCU:STC89C51 晶振:11.0592M
******************************/
#include<reg51.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
uint8 LedBitCnt; //LedBitCnt控制数码管的位选
uint8 flagm=0,flagf=0,flags=0;//时分秒闪烁的控制标志位
uint8 ms2_flag; //2ms数码管动态扫描时标消息
uint ms10_flag,ms500_flag;
uint8 ms2_cnt,ms10_cnt,count,s1num;
uint8 dis_buff[8]={0};
uint8 shi=12,fen=23,miao=56;
uint8 code SegTab[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x40,0x00};
sbit ADDR0 = P2^0;//74hc138的输入控制端A
sbit ADDR1 = P2^1;//74hc138的输入控制端B
sbit ADDR2 = P2^2;//74hc138的输入控制端C
sbit adjust=P3^2;
sbit add=P3^3;
sbit sub=P3^4;
void delayms(uint8 z)
{
uint8 i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
void disp()
{
P0=SegTab[dis_buff[LedBitCnt]];
switch(LedBitCnt)
{
case 0:
ADDR0=0;ADDR1=0;ADDR2=0;
break;
case 1:
ADDR0=1;ADDR1=0;ADDR2=0;
break;
case 2:
ADDR0=0;ADDR1=1;ADDR2=0;
break;
case 3:
ADDR0=1;ADDR1=1;ADDR2=0;
break;
case 4:
ADDR0=0;ADDR1=0;ADDR2=1;
break;
case 5:
ADDR0=1;ADDR1=0;ADDR2=1;
break;
case 6:
ADDR0=0;ADDR1=1;ADDR2=1;
break;
case 7:
ADDR0=1;ADDR1=1;ADDR2=1;
break;
}
}
void time_to_disbuff(void)
{
if(flagm&(!ms500_flag))
{
dis_buff[7]=11;
dis_buff[6]=11;
}
else
{
dis_buff[7]=miao%10;
dis_buff[6]=miao/10;
}
dis_buff[5]=10;
if(flagf&(!ms500_flag))
{
dis_buff[4]=11;
dis_buff[3]=11;
}
else
{
dis_buff[4]=fen%10;
dis_buff[3]=fen/10;
}
dis_buff[2]=10;
if(flags&(!ms500_flag))
{
dis_buff[1]=11;
dis_buff[0]=11;
}
else
{
dis_buff[1]=shi%10;
dis_buff[0]=shi/10;
}
}
void init()
{
TMOD=0x11;
TH1=0xf8;
TL1=0xcd;
TH0=0x4c;
TL0=0x00;
TR0=1;
ET0=1;
TR1=1;
ET1=1;
}
void keyscan()
{
if(adjust==0)
{
delayms(10);
if(adjust==0)
{
s1num++;
while(!adjust);
if(s1num==1)
{
flagm=1;
TR0=0;
}
}
}
if(s1num==2)
{
flagm=0;
flagf=1;
}
if(s1num==3)
{
flagm=0;
flagf=0;
flags=1;
}
if(s1num==4)
{
TR0=1;
flags=0;
s1num=0;
}
if(adjust!=0)
{
if(add==0)
{
delayms(10);
if(add==0)
{
while(!add);
if(s1num==1)
{
miao++;
if(miao==60)
miao=0;
}
if(s1num==2)
{
fen++;
if(fen==60)
fen=0;
}
if(s1num==3)
{
shi++;
if(shi==24)
shi=0;
}
}
}
if(sub==0)
{
delayms(10);
if(sub==0)
{
while(!sub);
if(s1num==1)
{
miao--;
if(miao==-1)
miao=59;
}
if(s1num==2)
{
fen--;
if(fen==-1)
fen=59;
}
if(s1num==3)
{
shi--;
if(shi==-1)
shi=23;
}
}
}
}
}
void main()
{
init();
EA=1;
time_to_disbuff();
P0=0x00;
while(1)
{
keyscan();
if(ms2_flag)
{
ms2_flag=0;
LedBitCnt++;
if(LedBitCnt>7)
{
LedBitCnt=0;
}
time_to_disbuff();
disp();
}
if(ms10_flag)
{
ms10_flag=0;
}
}
}
void timer0() interrupt 1
{
TH0=0x4c;
TL0=0x00;
count++;
if(count==20)
{
count=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
}
}
}
}
}
void timer1() interrupt 3 //定时1ms
{
TH1=0xf8;
TL1=0xcd;
ms2_flag=1; //用于数码管显示
ms2_cnt++;
if(ms2_cnt>=5)
{
ms2_cnt=0;
ms10_flag=1;//用于键扫描
if(++ms10_cnt>=50)
{
ms10_cnt=0;
ms500_flag=~ms500_flag;
}
}
}
总结:1 先开辟一个数码管显示的缓冲区,动态扫描函数函数负责从这个缓冲区中取出数据,并扫描显示。而其他函数则可以修改该缓冲区,从而改变显示的内容。
2 要学会标志位的灵活应用
3 按键程序存在不足,使用了延时函数delayms(10),让控制器在这白白等待了10ms的时间,啥也没干。这是不可取的。其次while(!adjust);更是程序设计的大忌(极少的特殊情况例外)。原本是等待按键释放,结果CPU就一直死死的盯住该按键,其他事情都不管了。
4 要处理好按键程序不足,就得学习按键状态机
5 继续学习,完善我的电子时钟,谢谢楼主的分享
|
|