1.设计内容
以单片机为核心,设计一个电子时钟,能分别显示“时-分-秒”1.显示范围从0小时0分0秒到23小时59分59秒,通过定时器实现定时1s,实现时分、秒的运行及显示。
2.可通过键盘设置小时、分钟和秒数的初值。
3.当调时按键按下后,进入调整时间模式,通过按键进行新一次时间调整。
4.当按下 24-12 进制切换按键后,时钟显示会在 24时制和 12时制之间切换。
2.简易原理图(Proteus仿真)
原理图仿真采用的共阳极数码管(7SEG-MPX8-CA-BLUE)
图1
图2
按键介绍
P3_0按键,在时间调整界面用于调整时、分、秒的加。
P3_1按键,在时间调整界面用于调整时、分、秒的减。
P3_2按键,当在时钟显示界面时(如图1),按键按下后,进入时间调整模式,被调整的时间会进入闪烁状态,通过按键不断进行依次调整时、分、秒。当在进制切换界面时(如图2),按键按下后,用于24时制和 12时制之间的切换。
P3_4按键,按下后会进入时钟的进制调整界面,时钟显示会在 24时制和 12时制之间切换,前两位显示此刻的小时显示,后两位显示此时的时钟进制。
参考代码
#include <REGX51.H>
/* 底层函数声明区域 */
void Seg_Disp(unsigned char wela,dula);
unsigned char Key_Read();
/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char seg_disp_mode;//0-时钟界面 1-切换界面
unsigned int TCount;//1s计时变量
unsigned char Time[4] = {18,59,51};//时钟存放数组
unsigned char Time_index;//数组指针
unsigned char Tab = 24;//用于12-24切换
bit star_flag;//闪烁标志位
/* 键盘处理函数 */
void Key_Proc()
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;//键盘减速程序
Key_Val = Key_Read();//实时读取键码值
Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿
Key_Old = Key_Val;//辅助扫描变量
switch(Key_Down)
{
case 4://+
if(Time_index != 0)
Time[Time_index-1]++;
break;
case 5://-
if(Time_index != 0)
Time[Time_index-1]--;
break;
case 6://调整
if(seg_disp_mode == 0)
{
if(++Time_index >= 4)
Time_index = 0;
}else{
if(Tab == 24)
{
Tab = 12;
if(Time[0] > 12)Time[0] -= 12;
else if(Time[0] ==0) Time[0] = 12;
}else if(Tab == 12)
{
Tab = 24;
if(Time[0] < 12 && Time[0] > 0)Time[0] += 12;
}
}
break;
case 7://切换
if(++seg_disp_mode == 2) {seg_disp_mode = 0;}
break;
}
}
/* 信息处理函数 */
void Seg_Proc()
{
unsigned char i;
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;//数码管减速程序
if(Time[2] >= 60){Time[2] = 0; Time[1]++;}
if(Time[1] >= 60){Time[1] = 0; Time[0]++;}
if(Tab == 24){if(Time[0] >= Tab) Time[0] = 0;}
else{if(Time[0] > Tab) Time[0] = 1;}
if(seg_disp_mode == 0)
{
Seg_Buf[2] = Seg_Buf[5] = 11;//-
for(i=0;i<3;i++)
{
Seg_Buf[3*i] = Time[i] / 10 % 10;
Seg_Buf[3*i+1] = Time[i] % 10;
}
if(Time_index != 0)
{
Seg_Buf[3*(Time_index-1)] = star_flag?10:Time[Time_index-1] / 10;
Seg_Buf[3*(Time_index-1)+1] = star_flag?10:Time[Time_index-1] % 10;
}
}else{
for(i=2;i<6;i++)
{
Seg_Buf[0] = Time[0] / 10;
Seg_Buf[1] = Time[0] % 10;
Seg_Buf[i] = 10;
Seg_Buf[6] = Tab / 10;
Seg_Buf[7] = Tab % 10;
}
}
//
}
/* 定时器0中断初始化函数 */
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD |= 0X01;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器中断0打开
EA = 1; //总中断打开
}
/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TCount++;
if(TCount>=1000)
{
TCount=0;
Time[2]++;
}
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
if(++Seg_Slow_Down == 350) {Seg_Slow_Down = 0;star_flag ^= 1;}//数码管减速专用
if(++Seg_Pos == 8) Seg_Pos = 0;//数码管显示专用
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
}
/* Main */
void main()
{
Timer0Init();
while (1)
{
Key_Proc();
Seg_Proc();
}
}
/* 底层函数 */
unsigned char seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
unsigned char seg_wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void Seg_Disp(unsigned char wela,dula)
{
P0 = 0xff;
P2 = seg_wela[wela];
P0 = seg_dula[dula];
}
unsigned char Key_Read()
{
unsigned char temp = 0;
if(P3_0 == 0) temp = 4;
if(P3_1 == 0) temp = 5;
if(P3_2 == 0) temp = 6;
if(P3_3 == 0) temp = 7;
return temp;
}