/**************************************************************************************************
模块名称:51单片机简易秒表
模块功能:实现精确到毫秒的简易秒表
编写人员:mengkun()
编写日期:/12/18
**************************************************************************************************/
#include
#definefalse0
#definetrue1
#defineucharunsignedchar//0——255
#defineuintunsignedint//0——65535
#defineulongunsignedlong//0——4294967295
sbitstart_key=P3^0;//启动按钮
sbitpause_key=P3^1;//暂停按钮
sbitreset_key=P3^2;//重置按钮
sbitbeep_key=P3^3;//声音按钮
sbitstart_led=P3^4;//启动指示灯
sbitpause_led=P3^5;//暂停指示灯
sbitbeep_led=P3^6;//喇叭指示灯
sbitbeep=P3^7;//喇叭
uchardisCode[10]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09};//数码管段码0~9
ucharlocCode[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码
voiddisplayTime(void);//刷新时间显示
voiddisPlay(ucharnum,ucharloc);//数码管、led显示函数
voidDelay1ms(unsignedintn);//延时1ms
ucharstate;//状态:0-停止,1-启动,2-暂停
ulongms=0;//存储毫秒值
ucharfen=0;//分钟数
ucharmiao;//秒数
ucharms2;//毫秒数的10位
bitisBeep=false;//是否开启蜂鸣器
/*******************************************************************************
*函数名:T0_INT
*函数功能:T0定时器中断函数10ms
*输入:无
*输出:无
*******************************************************************************/
voidT0_INT(void)interrupt1
{
//这里不是减去10000是因为在C51单片机中,每执行一条语句需要花费1ms时间。减去的是误差值。
//经过测试,大概每一分钟还是会有0.8s的误差……
//实际的秒表还是得专业的时钟芯片
TL0=(65536-9000)/256;
TH0=(65536-9000)%256;
ms++;
}
/*******************************************************************************
*函数名:main
*函数功能:主函数
*输入:无
*输出:无
*******************************************************************************/
voidmain(void)
{
TMOD=0x61;//01100001//方式一
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();//防止按键重复检测
}
}
}
}
voiddisplayTime(void)//刷新时间显示
{
miao=ms/100-fen*60;//秒数
ms2=ms/10%10;//毫秒数的10位
//已启动计时,并且开启了声音并且处于一秒刚开始的0.1秒内(即新的一秒刚刚开始)
if(state==1&&isBeep==true&&ms2
{
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
}
voiddisPlay(ucharnum,ucharloc)//数码管、led显示函数
{
P0=0xff;//消除重影
P2=locCode[loc];//位码输出
P0=disCode[num];//段码输出
Delay1ms(1);//增加显示时间,防止显示过暗
}
/*******************************************************************************
*函数名:Delay1ms(多个)
*函数功能:延时函数,延时n*1ms
*输入:n-延时次数
*输出:无
*******************************************************************************/
voidDelay1ms(unsignedintn)
{
unsignedchari,j;
for(;n>0;n--)
for(i=0;i<10;i++)
for(j=0;j<33;j++);
}