Sakura616のBlog
首页项目归档照片墙音乐说说杂谈友链关于
封面

基于51单片机的简易秒表设计

2026-05-15 12:43:22

## 功能概述

基于 STC89C51 的简易秒表,三个按键控制**启动、暂停、清零**,4位共阴数码管显示秒数和毫秒。

## 硬件连接

| 引脚 | 功能 |

|------|------|

| P1^0 | 启动按钮 |

| P1^1 | 暂停按钮 |

| P1^2 | 清零按钮 |

| P2 | 数码管段选 |

| P3 低4位 | 数码管位选 |

## 核心逻辑

  • 晶振 12MHz,定时器 T1 工作方式 1
  • 每 50ms 中断一次,累计 20 次 = 1 秒
  • flag_Pause 控制计时启停,初始为暂停状态 (参考学习通章节3.5.1)
  • 按键消抖 (参考学习通章节2.1.3)

## 完整代码

#include <reg51.h>
//#include "delay.h" //这里是我自己的delay库 方便大家使用就注释掉了

//delay延时
void delay(unsigned int xms) //@12.000MHz
{
	unsigned char  i, j;
	while(xms--)
	{i = 2;j = 239;do
	{while (--j);} while (--i);}
}
  static const char LED_table[] = {
      0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92,
      0x82, 0xF8, 0x80, 0x90, 0x88, 0x83,
      0xC6, 0xA1, 0x86, 0x8E
  }; //段码表
  unsigned char buf[] = {0, 0, 0, 0}; //显示缓冲 代表数码管的4个位
  unsigned int miao = 0; //定义一个整型型miao变量
  static unsigned char count = 0; //定义一个静态变量count

  sbit BT1 = P1^0; // 启动
  sbit BT2 = P1^1; // 暂停
  sbit BT3 = P1^2; // 清零
  bit flag_Pause = 1; // 初始暂停 (1停 0开)因为初始是高电平的 打开了降为低电平0

//这部分就是秒表计时了(参考学习通章节3.5.2)
  void timer_1() interrupt 3
  {
      TH1 = (65536 - 50000) / 256;
      TL1 = (65536 - 50000) % 256;
      if (flag_Pause == 0) { //这里我们添加一个if判断 让count的累加只在秒表启动时++
          count++; //50ms加一次
          if (count >= 20) { //如果到了20次 count为0 让miao+1 代表到了1秒
              count = 0;
              miao++;
              if (miao >= 1000)//因为作业要求前三位秒数这里改成1000
                  miao = 0;
          }
      }
  }

//(参考学习通章节3.5.3)数码管动态显示

  void led_show(unsigned char i, unsigned char disp_data)
  {
      P3 |= 0x0f;//低四位
      P2 = ~LED_table[disp_data];//段码获取
      if (i == 3)//led_display的led_i参数从1~4这个是位号 3代表第三位
				if(flag_Pause == 0){//这里也是 只有运行的时候小数点闪烁
					 if (count < 10)  //因为要跟随秒数跳动 count到20又=0了 
                                      //我们就取一半 count小于10次我们就亮
						 P2 |= 0x80; //这里是给第三位加. 利用或语句 或一个点的段码给数码管第三位
					 else//当count>=10次后 我们再给它熄灭 |大概是在整体里加上一个HEX 
                         //&则是在整体里去和对应的HEX去作用
						 P2 &=~0x80;//我们与上0x80 取反给它关掉
				 }else{//这个else对应的是if(flag_Pause == 0) 当不运行的时候
					 P2 &= ~0x80;//不运行就熄灭小数点咯
				 }
      P3 &= ~(1 << (i - 1));//动态扫描相关
  }

//(参考学习通章节3.5.3)数码管动态显示
  void led_display(unsigned char led_buff[])
  {
      static unsigned char led_i = 1;
      if (led_i > 4) led_i = 1;
      led_show(led_i, led_buff[led_i - 1]);
      led_i++;
  }

////(参考学习通章节3.5.2)数码管显示函数
  void disNUM(unsigned int i)
  {
      unsigned int ms = count/2;//看buf[3]的解释
      buf[0] = i/100; //这里参考学习通课程资料:第一个的1.4.1部分 百位
      buf[1] = (i/10)%10; //十位--比如124/10=12 12%10=2 得到十位
      buf[2] = i%10; //个位 例:133%10=3 %代表取余数
      buf[3] = ms;//一个count 50ms=0.05秒 假设count=6 50*6=300ms=0.3秒 6/2=3 这个3就对应了0.3的那个3 
									//所以这个是用来显示小数点后一位的
									//如果显示0.0x位 就是count*5
									//比如count=7 7*50=350ms=0.35秒 我们这里改成7*5=35 35/10得到0.x位 35%10得到0.0x位 
  }
  void Bt_ctl() //按键检测函数
  {
          //开启功能
      if (BT1 == 0) { //这里的结构参考学习通2.13的按键检测程序
          delay(10); //消抖
          if (BT1 == 0) { //判断
              flag_Pause = 0; //参考学习通3.5.1的中断
              while (BT1 == 0); //释放
          }
      } //下面这些一样的格式
        //停止功能
      if (BT2 == 0) {
          delay(10);
          if (BT2 == 0) {
              flag_Pause = 1; //中断
              while (BT2 == 0);
          }
      }
        //清零功能
      if (BT3 == 0) {
          delay(10);
          if (BT3 == 0) {
              flag_Pause = 1;//停止
              miao = 0; //秒数与cout设为0
              count = 0;
              while (BT3 == 0);
          }
      }
  }

  void main()
  {
      //定时器配置 参考学习通的即可
      TMOD = 0x10;
      TH1 = (65536 - 50000) / 256;
      TL1 = (65536 - 50000) % 256;
      ET1 = 1;
      EA = 1;
      TR1 = 1;
      while (1) {
          disNUM(miao);//调用计算出来的数
          led_display(buf);//刷新显示缓冲区的数字
          Bt_ctl();//按键检测
      }
  }

说明

  • 显示格式:SSS.s
  • 第 3 位数码管额外点亮小数点实现秒/毫秒分隔 小数点跳动

‍

💬 评论区

使用 GitHub 账号登录即可评论

avatar

Sakura616

一个在代码、建模、AI方面感兴趣的普通人。 ——"AI赋能,Vibe驱动。所想,即所得。"

RECOMMENDED

Hello World

2026-05-15

Table of Contents