1.利用8位数码管制作一个24小时制数字时钟,可以显示小时、分钟、秒,且中间有 ’ · ’ 或 ’ - '间隔。
2.小时、分钟可以通过按键进行调整。
3.每个整点蜂鸣器发出相应次数的声响,且每秒响1次,每次0.5秒。
1位变量 LSA、LSB、LSC接在3-8译码器上,分别对应8个七段数码管的“使能”
8位变量 P3 的低4位对应4个独立按键,按键按下时为低电平
8位变量 P0 对应七段数码管每一段的电平
用 Timer0中断 实现时钟
用 Timer1 控制蜂鸣器每秒响1次,每次0.5秒
用 Timer2 产生蜂鸣器的振荡频率
考虑中断资源不够,采用轮询的方式检测按键
/**
* 用这种方式轮询按键,在Display执行的时间检测不到按键。
* 而Display()里又有跟按键消抖时间相近的延时时间。
* 实测按键检测效果并不好。
* 于是直接以Display()函数作为按键消抖的延时。
* 把按键前后两次检测分别放在Display()的前和后。
* 实测效果好很多。
**/
void main()
{
Init();
while(1){
key_check();
Display();
}
}
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit beep=P1^5;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
u8 sec=0,min=0,hour=0,Rnd;
u8 flag;
u8 code smgduan[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
u8 time[8] = {0};
void delay(u16 i){
while(i--);
}
void Init()
{
P3=0x0F;
TMOD=0X11;
TH0=0XFC;
TL0=0X18;
TH1=0XFC;
TL1=0X18;
TH2=0XFC;
TL2=0X18;
ET0=1;
//ET1=1;
//ET2=1;
EA=1;
TR0=1;
TR1=1;
TR2=1;
}
void Display()
{
u8 i,num;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=1;LSB=1;LSC=1;num=hour/10; break;//显示第0位
case(1):
LSA=0;LSB=1;LSC=1;num=hour%10; break;//显示第1位
case(2):
LSA=1;LSB=0;LSC=1;num=10; break;//显示第2位
case(3):
LSA=0;LSB=0;LSC=1;num=min/10; break;//显示第3位
case(4):
LSA=1;LSB=1;LSC=0;num=min%10; break;//显示第4位
case(5):
LSA=0;LSB=1;LSC=0;num=10; break;//显示第5位
case(6):
LSA=1;LSB=0;LSC=0;num=sec/10; break;//显示第6位
case(7):
LSA=0;LSB=0;LSC=0;num=sec%10; break;//显示第7位
}
P0 = smgduan[num];
delay(100);
P0&=0x00;
}
}
void key_check(){
if(P3==0x0F) delay(1000);
else {
delay(1000);
return;
}
P3 &= 0x0F;
if(!(P3&0x01)){ //press k2
min += 1;
if(min>59) min=0;
}
else if(!(P3&0x02)){ //press k1
sec += 1;
if(sec>59) sec=0;
}
else if(!(P3&0x04)){ //press k3
hour += 1;
if(hour>23) hour=0;
}
else if(!(P3&0x08)){ //press k4 func: reset
sec = 0;
min = 0;
hour = 0;
}
return;
}
void main()
{
Init();
while(1){
//key_check();
flag=0;
if(k1 & k2 & k3 & k4) flag=1;
Display();
if(!sec && !min && hour) {
ET1=1;
Rnd=2*hour-2;
}
if(flag){
if(!k2){ //press k2
min += 1;
if(min>59) min=0;
}
else if(!k1){ //press k1
sec += 1;
if(sec>59) sec=0;
}
else if(!k3){ //press k3
hour += 1;
if(hour>23) hour=0;
}
else if(!k4){ //press k4 func: reset
sec = 0;
min = 0;
hour = 0;
}
}
}
}
void Timer0() interrupt 1 //need to adjust to 1 sec
{
static u16 x;
TH0=0XFC;
TL0=0X18;
x++;
if(x>=1000)
{
x=0;
sec++;
}
if(sec>59) {sec=0;min++;}
if(min>59) {min=0;hour++;}
if(hour>23) hour=0;
}
void Timer1() interrupt 3
{
static u16 y;
TH1=0XFC;
TL1=0X18;
y++;
if(y>=500)
{
y=0;
if(!Rnd) ET1=0;
Rnd--;
}
}
void Timer2() interrupt 5
{
TH2=0XFC;
TL2=0X18;
beep=~beep;
}
当蜂鸣器在报时的时候,会频繁产生中断,导致数码管刷新频率不够,出现肉眼可见的闪烁。
为了解决闪烁的问题,我们回看方案一。
方案一里有一大部分CPU时间开销在了delay()上面,所以考虑将delay()的时间利用上。
于是将 beep=~beep; 加在delay()等处来产生蜂鸣器的震荡。
于是有了下面的代码。
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit beep=P1^5;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
u8 sec=0,min=0,hour=0,Rnd; //Rnd -> Round 用于计量蜂鸣器响几次
u8 flag,EB=0; //EB -> Enable Beep
u8 code smgduan[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
u8 time[8] = {0};
void delay(u16 i){
while(i--);
if(EB) beep=~beep;
}
void Init()
{
P3=0x0F;
TMOD=0X11;
TH0=0XFC;
TL0=0X18;
TH1=0XFC;
TL1=0X18;
TH2=0XFC;
TL2=0X18;
ET0=1;
//ET1=1;
//ET2=1;
EA=1;
TR0=1;
TR1=1;
TR2=1;
}
void Display()
{
u8 i,num;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=1;LSB=1;LSC=1;num=hour/10; break;//显示第0位
case(1):
LSA=0;LSB=1;LSC=1;num=hour%10; break;//显示第1位
case(2):
LSA=1;LSB=0;LSC=1;num=10; break;//显示第2位
case(3):
LSA=0;LSB=0;LSC=1;num=min/10; break;//显示第3位
case(4):
LSA=1;LSB=1;LSC=0;num=min%10; break;//显示第4位
case(5):
LSA=0;LSB=1;LSC=0;num=10; break;//显示第5位
case(6):
LSA=1;LSB=0;LSC=0;num=sec/10; break;//显示第6位
case(7):
LSA=0;LSB=0;LSC=0;num=sec%10; break;//显示第7位
}
P0 = smgduan[num];
delay(50);
P0&=0x00;
}
}
void main()
{
Init();
while(1){
if(EB) beep=~beep;
flag=0;
if(k1 & k2 & k3 & k4) flag=1;
Display();
if(!sec && !min && hour) {
ET1=1;
Rnd=2*hour-2;
}
if(flag){
if(!k2){ //press k2
min += 1;
if(min>59) min=0;
}
else if(!k1){ //press k1
sec += 1;
if(sec>59) sec=0;
}
else if(!k3){ //press k3
hour += 1;
if(hour>23) hour=0;
}
else if(!k4){ //press k4 func: reset
sec = 0;
min = 0;
hour = 0;
}
}
}
}
void Timer0() interrupt 1 //need to adjust to 1 sec
{
static u16 x;
TH0=0XFC;
TL0=0X18;
x++;
if(x>=1000)
{
x=0;
sec++;
}
if(sec>59) {sec=0;min++;}
if(min>59) {min=0;hour++;}
if(hour>23) hour=0;
}
void Timer1() interrupt 3
{
static u16 y;
TH1=0XFC;
TL1=0X18;
y++;
if(y>=500)
{
y=0;
if(!Rnd) ET1=0;
EB=~EB;
Rnd--;
}
}
无法控制蜂鸣器震荡的频率,希望有人可以提供一个更好的思路。