51单片机简易秒表的设计(含源代码、编译过的 HEX 文件以及仿真图)

题目要求

  • 一个精度为0.1s的秒表系统。
  • 有启动按钮、暂停按钮及清零按钮。
  • 每到一秒钟有声音提醒功能,可通过按钮打开及关闭该提醒音。

运行效果

最终实现的运行效果

完整代码

#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,0x40,0x80};                   //位码
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++);
}

完整的 proteus 仿真图布局

完整的 proteus 仿真图布局

打包下载

源代码、编译过的 HEX 文件以及仿真图已打包上传,下载地址:
https://download.csdn.net/download/oqqmoon1234/9719460

猜你喜欢

转载自blog.csdn.net/oqqmoon1234/article/details/106325779
hex