|
#include <reg52.h>
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
unsigned char code LedChar[] = { //數(shù)碼管顯示字符轉(zhuǎn)換表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //數(shù)碼管顯示緩沖區(qū)
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char KeySta[4] = { //按鍵當(dāng)前狀態(tài)
1, 1, 1, 1
};
bit StopwatchRunning = 0; //秒表運(yùn)行標(biāo)志
bit StopwatchRefresh = 1; //秒表計(jì)數(shù)刷新標(biāo)志
unsigned char DecimalPart = 0; //秒表的小數(shù)部分
unsigned int IntegerPart = 0; //秒表的整數(shù)部分
unsigned char T0RH = 0; //T0 重載值的高字節(jié)
unsigned char T0RL = 0; //T0 重載值的低字節(jié)
void ConfigTimer0(unsigned int ms);
void StopwatchDisplay();
void KeyDriver();
void main(){
EA = 1; //開總中斷
ENLED = 0; //使能選擇數(shù)碼管
ADDR3 = 1;
P2 = 0xFE; //P2.0 置 0,選擇第 4 行按鍵作為獨(dú)立按鍵
ConfigTimer0(2); //配置 T0 定時(shí) 2ms
while (1){
if (StopwatchRefresh){ //需要刷新秒表示數(shù)時(shí)調(diào)用顯示函數(shù)
StopwatchRefresh = 0;
StopwatchDisplay();
}
KeyDriver(); //調(diào)用按鍵驅(qū)動(dòng)函數(shù)
}
}
/* 配置并啟動(dòng) T0,ms-T0 定時(shí)時(shí)間 */
void ConfigTimer0(unsigned int ms){
unsigned long tmp; //臨時(shí)變量
tmp = 11059200 / 12; //定時(shí)器計(jì)數(shù)頻率
tmp = (tmp * ms) / 1000; //計(jì)算所需的計(jì)數(shù)值
tmp = 65536 - tmp; //計(jì)算定時(shí)器重載值
tmp = tmp + 18; //補(bǔ)償中斷響應(yīng)延時(shí)造成的誤差
T0RH = (unsigned char)(tmp>>8); //定時(shí)器重載值拆分為高低字節(jié)
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x01; //配置 T0 為模式 1
TH0 = T0RH; //加載 T0 重載值
TL0 = T0RL;
ET0 = 1; //使能 T0 中斷
TR0 = 1; //啟動(dòng) T0
}
/* 秒表計(jì)數(shù)顯示函數(shù) */
void StopwatchDisplay(){
signed char i;
unsigned char buf[4]; //數(shù)據(jù)轉(zhuǎn)換的緩沖區(qū)
//小數(shù)部分轉(zhuǎn)換到低 2 位
LedBuff[0] = LedChar[DecimalPart%10];
LedBuff[1] = LedChar[DecimalPart/10];
//整數(shù)部分轉(zhuǎn)換到高 4 位
buf[0] = IntegerPart%10;
buf[1] = (IntegerPart/10)%10;
buf[2] = (IntegerPart/100)%10;
buf[3] = (IntegerPart/1000)%10;
for (i=3; i>=1; i--){ //整數(shù)部分高位的 0 轉(zhuǎn)換為空字符
if (buf[i] == 0){
LedBuff[i+2] = 0xFF;
}else{
break;
}
}
for ( ; i>=0; i--){ //有效數(shù)字位轉(zhuǎn)換為顯示字符
LedBuff[i+2] = LedChar[buf[i]];
}
LedBuff[2] &= 0x7F; //點(diǎn)亮小數(shù)點(diǎn)
}
/* 秒表啟停函數(shù) */
void StopwatchAction(){
if (StopwatchRunning){ //已啟動(dòng)則停止
StopwatchRunning = 0;
}else{ //未啟動(dòng)則啟動(dòng)
StopwatchRunning = 1;
}
}
/* 秒表復(fù)位函數(shù) */
void StopwatchReset(){
StopwatchRunning = 0; //停止秒表
DecimalPart = 0; //清零計(jì)數(shù)值
IntegerPart = 0;
StopwatchRefresh = 1; //置刷新標(biāo)志
}
/* 按鍵驅(qū)動(dòng)函數(shù),檢測(cè)按鍵動(dòng)作,調(diào)度相應(yīng)動(dòng)作函數(shù),需在主循環(huán)中調(diào)用 */
void KeyDriver(){
unsigned char i;
static unsigned char backup[4] = {1,1,1,1};
for (i=0; i<4; i++){ //循環(huán)檢測(cè) 4 個(gè)按鍵
if (backup[i] != KeySta[i]){ //檢測(cè)按鍵動(dòng)作
if (backup[i] != 0){ //按鍵按下時(shí)執(zhí)行動(dòng)作
if (i == 1){ //Esc 鍵復(fù)位秒表
StopwatchReset();
}else if (i == 2){//回車鍵啟停秒表
StopwatchAction();
}
}
backup[i] = KeySta[i]; //刷新前一次的備份值
}
}
}
/* 按鍵掃描函數(shù),需在定時(shí)中斷中調(diào)用 */
void KeyScan(){
unsigned char i;
static unsigned char keybuf[4] = { //按鍵掃描緩沖區(qū)
0xFF, 0xFF, 0xFF, 0xFF
};
//按鍵值移入緩沖區(qū)
keybuf[0] = (keybuf[0] << 1) | KEY1;
keybuf[1] = (keybuf[1] << 1) | KEY2;
keybuf[2] = (keybuf[2] << 1) | KEY3;
keybuf[3] = (keybuf[3] << 1) | KEY4;
//消抖后更新按鍵狀態(tài)
for (i=0; i<4; i++){
if (keybuf[i] == 0x00){
//連續(xù) 8 次掃描值為 0,即 16ms 內(nèi)都是按下狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的按下
KeySta[i] = 0;
}else if (keybuf[i] == 0xFF){
//連續(xù) 8 次掃描值為 1,即 16ms 內(nèi)都是彈起狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的彈起
KeySta[i] = 1;
}
}
}
/* 數(shù)碼管動(dòng)態(tài)掃描刷新函數(shù),需在定時(shí)中斷中調(diào)用 */
void LedScan(){
static unsigned char i = 0; //動(dòng)態(tài)掃描索引
P0 = 0xFF; //關(guān)閉所有段選位,顯示消隱
P1 = (P1 & 0xF8) | i; //位選索引值賦值到 P1 口低 3 位
P0 = LedBuff[i]; //緩沖區(qū)中索引位置的數(shù)據(jù)送到 P0 口
if (i < 5){ //索引遞增循環(huán),遍歷整個(gè)緩沖區(qū)
i++;
}else{
i = 0;
}
}
/* 秒表計(jì)數(shù)函數(shù),每隔 10ms 調(diào)用一次進(jìn)行秒表計(jì)數(shù)累加 */
void StopwatchCount(){
if (StopwatchRunning){ //當(dāng)處于運(yùn)行狀態(tài)時(shí)遞增計(jì)數(shù)值
DecimalPart++; //小數(shù)部分+1
if (DecimalPart >= 100){ //小數(shù)部分計(jì)到 100 時(shí)進(jìn)位到整數(shù)部分
DecimalPart = 0;
IntegerPart++; //整數(shù)部分+1
if (IntegerPart >= 10000){ //整數(shù)部分計(jì)到 10000 時(shí)歸零
IntegerPart = 0;
}
}
StopwatchRefresh = 1; //設(shè)置秒表計(jì)數(shù)刷新標(biāo)志
}
}
/* T0 中斷服務(wù)函數(shù),完成數(shù)碼管、按鍵掃描與秒表計(jì)數(shù) */
void InterruptTimer0() interrupt 1{
static unsigned char tmr10ms = 0;
TH0 = T0RH; //重新加載重載值
TL0 = T0RL;
LedScan(); //數(shù)碼管掃描顯示
KeyScan(); //按鍵掃描
//定時(shí) 10ms 進(jìn)行一次秒表計(jì)數(shù)
tmr10ms++;
if (tmr10ms >= 5){
tmr10ms = 0;
StopwatchCount(); //調(diào)用秒表計(jì)數(shù)函數(shù)
}
} |
|