/********************************************************************
* 描述* * 電子時鐘,LED數(shù)碼管顯示,晶振使用12MHz *
* K1---時調(diào)整 *
K2---分調(diào)整 * K3---秒調(diào)整 K4---時間暫停 K5---12小時制和24小時制切換
* 上電時初始化顯示:12-00-00 *
*********************************************************************#include<reg51.h>
#include<intrins.h>
unsignedchar data dis_digit;
unsignedchar key_s, key_v;
unsignedchar code dis_code[11]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00
};//0,1,2,3 4, 5, 6, 7, 8, 9, off //共陰數(shù)碼管
unsignedchar data dis_buf[8];
unsignedchar data dis_index;
unsignedchar hour,min,sec;
unsignedchar sec100;
unsignedchar flag,flag1,flag2; //falg用于時間停止和啟動標志,falg1為12小時和24小時的切換標志,falg2為12小時的上午和下午的切換標志
sbitK1 = P1^0; //用于時的調(diào)整
sbitK2 = P1^1; //用于分的調(diào)整
sbitK3 = P1^2; //用于秒的調(diào)整
sbitK4 = P1^3; //用于時間調(diào)整的開關(guān),按下一次暫停時間,再按一次時則開始計時
sbitK5 = P1^4; //用于24小時制和12小時制的切換
bitscan_key();
voidproc_key();
voidinc_sec();
voidinc_min();
voidinc_hour();
voidinc_hour1();
voiddelayms(unsigned char ms);
voidmain(void)
{
P0 = 0xff;
P2 = 0xff;
TMOD = 0x11; // 定時器0, 1工作模式1, 16位定時方式
TH1 = 0xd8; //使用12MHz的晶振,定時時間為:10ms
TL1 = 0xf0;
TH0 = 0xf8; //定時時間為2ms,用于數(shù)碼管的動態(tài)掃描
TL0 = 0x30;
hour = 12;
min = 00;
sec = 00;
sec100 = 0;
flag = 0;
flag1 = 0;
dis_buf[0] = dis_code[hour / 10]; // 時十位
dis_buf[1] = dis_code[hour % 10]; // 時個位
dis_buf[2] = dis_code[min / 10]; // 分十位
dis_buf[3] = dis_code[min % 10]; // 分個位
dis_buf[4] = dis_code[sec / 10]; // 秒十位
dis_buf[5] = dis_code[sec % 10]; // 秒個位
dis_buf[6] = 0x00; // 關(guān)閉該位數(shù)碼管
dis_buf[7] = 0x7f; // 顯示 B 表示下午
dis_digit = 0xfe;
dis_index = 0;
TCON = 0x01; //T1:TF1TR1 T0:TF0 TR0 定時中斷:IE1 IT1 IE0 IT0 //外部中斷0的觸發(fā)方式為下降沿觸發(fā)
IE = 0x8a; // 使能timer0,1 中斷,控制IE寄存器的格式:EA - -ES ET1 EX1 ET0 EX0
// 1 0 0 0 1 0 1 0
TR0 = 1; //開定時器0
TR1 = 1; //開定時器1
key_v = 0x1f; //定義為K1,K2,K3,K4,K5相應(yīng)的按鍵,當沒有按下時則為,K1,K2,K3,K4,K5,都為高電平,0x1f
while(1)
{
if(scan_key()) //先掃描一次是否有按鍵按下
{
delayms(10); //延時
if(scan_key()) //再次掃描一次是否有按鍵 按下
{
key_v = key_s; //將key_s的值傳給key_v
proc_key();
}
}
}
}
bitscan_key()
{
key_s = 0x00; //設(shè)置key_s先為0
key_s |=K5;
key_s <<= 1;
key_s |= K4;
key_s <<= 1;
key_s |= K3;
key_s <<= 1;
key_s |= K2; //K2 -> P1.1,若K2按下則為0,當K2按下時key_s與K2或的結(jié)果會使得key_s為0x00,未按下時K2則為1,key_s與K2或的結(jié)果會使得key_s為0x01
key_s <<= 1; //將key_s左移一位,
key_s |= K1; //K1-> P1.0,若K1按下則為0,當K1按下時key_s與K1或的結(jié)果會使得key_s為0x00或是0x02,沒有按下時則得到的結(jié)果為0x01或是0x03
return(key_s ^ key_v); //進行邏輯異或運算,相同為0,不同為1. 已經(jīng)定義了變量:key_v = 0x1f; 如果兩個按鍵都沒有按下則是得到0x03,異或的結(jié)果是為0
}
voidproc_key()
{
if(K4==0) //K4是否按下
{
flag++; //關(guān)閉定時器
TR1=0; //關(guān)閉定時器1
dis_buf[6] = 0x76; // 顯示 H,用于表示設(shè)定時間的標志
}
if(K5==0)
{
flag1++; //flag1的初始值是0,falg1為12小時和24小時的切換標志
if(flag1==1) //24小時制
{
if(dis_buf[7]==0x7f) //判斷是不是下午
{
hour=hour+12;
dis_buf[7]=0x00;
}
dis_buf[7] = 0x00; // 關(guān)閉顯示
if(hour >23)
{
hour = 0;
}
if(hour > 9)
dis_buf[0] = dis_code[hour / 10]; // 時十位
else
dis_buf[0] = 0x00; // 當小時的十位為0時不顯示
dis_buf[1] = dis_code[hour % 10]; // 時個位
}
if(flag1==2) //12小時制
{
flag1=0;
if(hour>12||hour==0) //判斷是不是下午,并用于處理24小時制的大于13和等于0的處理
{
if(hour>12)
hour=hour-12;
if(hour==0)
hour=12;
dis_buf[7]=0x7f; //顯示下午 B
}
else
dis_buf[7] = 0x77; // 顯示 A 表示上午
if(hour > 9)
dis_buf[0] = dis_code[hour / 10]; // 時十位
else
dis_buf[0] = 0x00; // 當小時的十位為0時不顯示
dis_buf[1] = dis_code[hour % 10]; // 時個位
}
}
if((key_v & 0x01) == 0) // K1,當只有K1按下時,則key_s為0x02,沒有按下時key_s則為0x03
{
if(flag1==0)
inc_hour();
if(flag1==1)
inc_hour1();
}
elseif((key_v & 0x02) == 0) // K2, 當只有K2按下時,則key_s為0x01,沒有按下時key_s則為0x03
{
min++;
if(min > 59)
{
min= 0;
}
dis_buf[2] = dis_code[min / 10]; // 分十位
dis_buf[3] = dis_code[min % 10]; // 分個位
}
else if((key_v & 0x04) == 0) // K3是否按下
{
sec++;
if(sec > 59)
{
sec= 0;
}
dis_buf[4] = dis_code[sec / 10]; // 秒十位
dis_buf[5] = dis_code[sec % 10]; // 秒個位
}
if(flag==2)
{
flag=0;
TR1=1;
dis_buf[6] = 0x00;
if(flag1==0)
{
if(flag2)
dis_buf[7] = 0x77; // 顯示 A 表示上午
else
dis_buf[7] = 0x7f; // 顯示 B 表示下午
}
}
}
voidtimer0() interrupt 1
// 定時器0中斷服務(wù)程序, 用于數(shù)碼管的動態(tài)掃描
//dis_index --- 顯示索引, 用于標識當前顯示的數(shù)碼管和緩沖區(qū)的偏移量
//dis_digit --- 位選通值, 傳送到P0口用于選通當前數(shù)碼管的數(shù)值,如等于0xfe時,
// 選通P2.0口數(shù)碼管
//dis_buf --- 顯于緩沖區(qū)基地址
{
TH0 = 0xf8; //定時時間為2ms
TL0 = 0x30;
P2 = 0xff; // 先關(guān)閉所有數(shù)碼管
P0 = dis_buf[dis_index]; // 顯示代碼傳送到P0口
P2 = dis_digit; //
dis_digit = _crol_(dis_digit,1); // 位選通值左移, 下次中斷時選通下一位數(shù)碼管
dis_index++; //
dis_index &= 0x07; // 8個數(shù)碼管全部掃描完一遍之后,再回到第一個開始下一次掃描 ,限定了只掃描8位,當為超過8位時則開始清零.
} //0x07=0000 0111 dis_index在一個個加一時,則為加到8次。
//定時器1的定時時間為10ms
voidtimer1() interrupt 3
{
TH1 = 0xd8;
TL1 = 0xf0;
sec100++;
if(sec100 >= 100) //定時1秒的時間
{
sec100 = 0;
inc_sec();
}
}
voidinc_sec()
{
sec++;
if(sec > 59)
{
sec = 0;
inc_min();
}
dis_buf[4] = dis_code[sec / 10]; // 秒十位
dis_buf[5] = dis_code[sec % 10]; // 秒個位
}
voidinc_min()
{
min++;
if(min > 59)
{
min = 0;
if(flag1==0)
inc_hour();
if(flag1==1)
inc_hour1();
}
dis_buf[2] = dis_code[min / 10]; // 分十位
dis_buf[3] = dis_code[min % 10]; // 分個位
}
voidinc_hour() //12小時制
{
hour++;
if(hour > 12)
{
flag2=~flag2;
hour= 1;
}
if(hour> 9)
dis_buf[0] = dis_code[hour / 10]; // 時十位
else
dis_buf[0] = 0x00; // 當小時的十位為0時不顯示
dis_buf[1] = dis_code[hour % 10]; // 時個位
if(flag2)
dis_buf[7] = 0x77; //顯示 A 表示上午
else
dis_buf[7] = 0x7f; // 顯示 B 表示下午
}
voidinc_hour1() //24小時制時間
{
hour++;
if(hour >23)
{
hour = 0;
}
if(hour > 9)
dis_buf[0] = dis_code[hour / 10]; // 時十位
else
dis_buf[0] = 0x00; // 當小時的十位為0時不顯示
dis_buf[1] = dis_code[hour % 10]; // 時個位
}
voiddelayms(unsigned char ms)
// 延時子程序
{
unsigned char i;
while(ms--)
{
for(i = 0; i < 120; i++);
}
}