#include <reg51.h>
#define false 0
#define true 1
#define uchar unsigned char //0——255
#define uint unsigned int //0——65535
#define ulong unsigned long //0——4294967295
sbit start_key = P3^0; //啟動按鈕
sbit pause_key = P3^1; //暫停按鈕
sbit reset_key = P3^2; //重置按鈕
sbit beep_key = P3^3; //聲音按鈕
sbit start_led = P3^4; //啟動指示燈
sbit pause_led = P3^5; //暫停指示燈
sbit beep_led = P3^6; //喇叭指示燈
sbit beep = P3^7; //喇叭
uchar disCode[10] = {0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09}; //數碼管段碼 0~9
uchar locCode[8] = {0x01,0x02,0x04,0x08,0x10,0x20}; //位碼
void displayTime(void); //刷新時間顯示
void disPlay(uchar num, uchar loc); //數碼管、led顯示函數
void Delay1ms(unsigned int n); //延時1ms
uchar state; //狀態:0-停止,1-啟動,2-暫停
ulong ms = 0; //存儲毫秒值
uchar fen = 0; //分鐘數
uchar miao; //秒數
uchar ms2; //毫秒數的10位
bit isBeep = false; //是否開啟蜂鳴器
/*******************************************************************************
* 函 數 名 : T0_INT
* 函數功能 : T0定時器中斷函數10ms
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void T0_INT(void) interrupt 1
{
//這里不是減去10000是因為在C51單片機中,每執行一條語句需要花費 1ms 時間。減去的是誤差值。
//經過測試,大概每一分鐘還是會有 0.8 s的誤差……
//實際的秒表還是得專業的時鐘芯片
TL0= (65536-9000)/256;
TH0= (65536-9000)%256;
ms ++;
}
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void main(void)
{
TMOD=0x61; //0110 0001 //方式一
TL0= (65536-10000)/256; // 10ms
TH0= (65536-10000)%256;
TR0=1; //開啟T0
//ET0=1; //T0中斷允許(要在點擊了啟動按鈕在開啟,所以這里不需要開啟)
EA=1; //總中斷開啟
//以下指示燈一開始都應該是滅的
start_led = 0; //啟動指示燈
pause_led = 0; //暫停指示燈
beep_led = 0; //喇叭指示燈
while(1)
{
displayTime(); //刷新時間顯示
//檢測啟動、停止按鈕
if(start_key == 0) //按下了啟動、停止按鈕
{
Delay1ms(10); //延時消抖
if(start_key == 0)
{
if(state == 0)//之前是未啟動,按了按鈕要變成已啟動
{
state = 1; //更新狀態為已啟動
ms = 0; //毫秒數歸零
fen = 0; //分鐘數歸零
ET0 = 1; //T0中斷允許打開,開始計時
start_led = 1; //啟動led指示燈亮
}else{
state = 0; //更新狀態為未啟動
ET0 = 0; //關閉T0中斷,停止計時
start_led = 0; //啟動led指示燈滅
pause_led = 0; //暫停指示燈滅
}
while(start_key == 0) displayTime(); //防止按鍵重復檢測
}
}
//檢測暫停按鈕
if(state != 0 && pause_key == 0) //已啟動計時,并且暫停按鈕按下
{
Delay1ms(10); //延時消抖
if(pause_key == 0)
{
if(state == 2) //之前是暫停,現在要啟動
{
state = 1; //更新狀態為已啟動
pause_led = 0; //暫停指示燈滅
ET0 = 1; //打開T0中斷允許,恢復計時
}else{
state = 2;
pause_led = 1; //暫停指示燈亮起
ET0 = 0; //關閉T0定時器,暫停計時
}
while(pause_key == 0) displayTime(); //防止按鍵重復檢測
}
}
//檢測歸零按鈕
if(state == 0 && reset_key == 0) //已停止計時,并且歸零按鈕按下
{
Delay1ms(10); //延時消抖
if(reset_key == 0)
{
ms = 0; //毫秒數歸零
fen = 0; //分鐘數歸零
while(reset_key == 0) displayTime(); //防止按鍵重復檢測
}
}
//檢測聲音按鈕
if(beep_key == 0) //歸零按鈕按下
{
Delay1ms(10); //延時消抖
if(beep_key == 0)
{
isBeep = ~isBeep; //取反,原來是開啟的,變為關閉。原來是關閉的則變為開啟
beep_led = isBeep; //更新聲音指示燈
while(beep_key == 0) displayTime(); //防止按鍵重復檢測
}
}
}
}
void displayTime(void) //刷新時間顯示
{
miao = ms/100 - fen*60; //秒數
ms2 = ms/10%10; //毫秒數的10位
//已啟動計時,并且開啟了聲音 并且處于一秒剛開始的0.1秒內(即新的一秒剛剛開始)
if(state == 1 && isBeep == true && ms2 < 1)
{
beep = 0; //蜂鳴器發出響聲
}else{
beep = 1; //關閉蜂鳴器
}
if(miao >= 60) //秒數大于60
{
miao = 0;
fen++; //分鐘數加一
}
disPlay(fen/10, 0); //顯示分鐘數的十位
disPlay(fen%10, 1); //顯示分鐘數的個位
disPlay(miao/10, 2); //顯示秒數的十位
disPlay(miao%10, 3); //顯示秒數的個位
disPlay(ms2, 4); //0.1s
disPlay(ms%10, 5); //0.01s
}
void disPlay(uchar num, uchar loc) //數碼管、led顯示函數
{
P0 = 0xff; //消除重影
P2 = locCode[loc]; //位碼輸出
P0 = disCode[num]; //段碼輸出
Delay1ms(1); //增加顯示時間,防止顯示過暗
}
/*******************************************************************************
* 函 數 名 : Delay1ms (多個)
* 函數功能 : 延時函數,延時n*1ms
* 輸 入 : n-延時次數
* 輸 出 : 無
*******************************************************************************/
void Delay1ms(unsigned int n)
{
unsigned char i, j;
for (; n>0; n--)
for(i=0;i<10;i++)
for(j=0;j<33;j++);
}
|