1.利用定时器中断实现时钟功能,格式:时-分-秒。
2.实现时钟显示和闹钟设置两个功能的切换。
3.闹钟设置,且限定字符格式(如时针不得超过24等)。
4.时钟到达预设值时,闹铃正常响起,且用按键关闭。
**
头文件
#ifndef colock_h
#define colock_h
#include
#define LedD P0 //段选
#define LedC P2 //位选
unsigned char s=57,m=59,h=23; //时、分、秒初始值
unsigned char j=0; //闪烁位的延时参数
unsigned char flag=0; //闪烁位
unsigned char key1=0,key2=0,key3=0; //三个中断按键
unsigned char f1=0,f2=1,f3=0; //f1:时钟到达闹钟预设值 标志位
//f2:闹钟关闭按键 标志位
//f3:闹钟状态 标志位
unsigned int i=0; //计数器延时参数
sbit cl=P3^0; //闹钟功能切换提示
sbit bz=P1^0; //闹铃输出口
//共阴极数码管
unsigned char num1[] = {
1,0,10,0,0,10,0,0}; /* 时钟待显示字符对应key值*/
unsigned char num2[] = {
0,0,10,0,0,10,1,0}; /* 闹钟待显示字符对应key值*/
code unsigned char wx[] = {
0xfe,0xfd,0xfb,0xf7, /* 位选编码 字符对应value值 */
0xef,0xdf,0xbf,0x7f};
code unsigned char dx[] = {
0x3f,0x06,0x5b,0x4f,0x66, /* 0-9数字,-的编码 */
0x6d,0x7d,0x07,0x7f,0x6f,0x40};
void init(); //初始化
void delay(unsigned char); //延时
void display(); //时针显示
void count(); //时针计数(计时)
void transform(); //将时分秒的个位十位分离
void twinkle(unsigned char); //闹钟显示界面 控制某一位闪烁
void int0(); //外部中断0
void int1(); //外部中断1
void it0(); //定时器0
void compare(); //闹钟预设值与时钟值比较
void ring(); //闹铃
#endif
c文件
#include "colock.h"
void main(void)
{
init();
while(1)
{
compare();
if(key1==1)
{
cl=1;
twinkle(flag); //已切换到闹钟功能 提示
}
else //切换到时钟显示
{
cl=0;
display();
}
}
}
void init(void) /*初始化*/
{
LedD = 0x00; /* 段码置0 */
LedC = 0xff; /* 位选置1 */
EA=1; //总中断
ET1=1; //开启定时器中断1
ET0=1; //定时器0
TR1=1; //开启定时器1
TMOD=0x20; //定时器1,工作方式2,八位自动重装载
TH1=156;
TL1=156; //0.1ms
IT0=1; //下降沿有效
IT1=1;
EX0=1; //外部中断0、1
EX1=1;
ET0=1; //开启定时器中断
TMOD=0x06; //八位自动重装载计数器0 扩展为中断
TR0=1; //开启定时器0
TH0=0xff;
TL0=0xff;
bz=0; //闹铃关闭
}
void display() //字符显示
{
unsigned char i;
for(i=0; i<8; i++)
{
LedC = wx[i]; /* 选通某一位,例如i=0,即选通第0位 */
LedD = dx[num1[i]]; /* 通过码表数组将第i位要显示的数字转换成数码管能识别的编码 */
delay(20); /* 微量延时,用于显示保持 */
LedD=0x00; //消隐
}
}
void delay(unsigned char t) //延时
{
unsigned char i,j;
for(i=0; i<20; i++)
for(j=0; j<t; j++);
}
void transform() //数位转换
{
h%=24;
num1[0]=h/10; //十位
num1[1]=h%10; //个位
num1[3]=m/10;
num1[4]=m%10;
num1[6]=s/10;
num1[7]=s%10;
}
void count() interrupt 3 //计时
{
i++;
if(i==100)
{
s++;
if(s==60)
{
s=0;
m++;
}
if(m==60)
{
m=0;
h++;
}
transform();
i%=100;
if(f1&&f2) //启动闹铃
ring();
else
bz=0;
}
}
//闹钟界面相关程序
void twinkle(unsigned char t) //某一位闪烁
{
unsigned char i;
j%=50;
for(i=0;i<8;i++)
{
if((i==t)&&(j<25))
continue;
else
{
delay(20);
P2=wx[i];
P0=dx[num2[i]];
}
}
j++;
}
void int0() interrupt 0 //进入闹钟界面
{
key1++;
key1%=2;
}
void int1() interrupt 2 //移动调整位(闪烁位) 关闭闹铃
{
flag++;
if(flag==2||flag==5) //跳过分隔符
flag++;
flag%=8;
if(f1) //关闭闹铃标志符f2的赋值
{
f2=0;
f1=0;
}
else
f2=1;
}
void it0() interrupt 1 //闪烁位数字加一
{
if(flag==0&&num2[flag]==2) //限制 时针高位不得破2
{
num2[flag]=0;
return;
}
else if(flag==1&&num2[flag]==3&&num2[0]==2) //限制 时针为2时,低位不得破4
{
num2[flag]=0;
return;
}
else if((flag==3||flag==6)&&num2[flag]==5) //分针、秒针高位不得破6
{
num2[flag]=0;
return;
}
num2[flag]++;
num2[flag]%=10; //防止任意数字破9
}
void compare() //闹钟,比较是否到达预定时间
{
unsigned char i;
for(i=0;i<8;i++)
{
if(num1[i]==num2[i])
f1=1;
else
{
if(f3)
return;
else
{
f1=0;
return;
}
}
}
f3=1;
}
void ring() //闹铃
{
bz=~bz;
}
部分说明:
num1[] 储存时钟数值
num2[] 储存闹钟数值
关闭闹铃的按键与更换闪烁位复用了
闹铃的闪烁与时钟的定时器复用了
(待后续补充)
1.时钟显示
**
1.闹铃的蜂鸣器我使用了led灯代替,便于显示
2.proteus里的延时似乎是受电脑性能影响,故代码中的延时参数 i 等全局变量并非理论值,应个性化调整
3.待后续补充…
ps:欢迎评论区咨询讨论
电路图与代码
2020.8.6:
事实上,当初因时间限制,程序(判断闹钟是否到时)这部分算法有些臃肿复杂,存在很大的优化空间(我用了f1,f2,f3三个flag变量,实则并无必要),个人建议可以将闹钟判断响应部分的代码推翻重写
目前闹钟存在只能响应一次的问题,bug也是出在对f1,f2,f3三个状态量的if判断语句上