文件下载:
https://pan.baidu.com/s/1_xHZK1pvxi2uWYGDxGLhFQ?pwd=fg26 提取码: fg26

一、代码核心思想

这段代码通过 51单片机 实现了一个 4位秒表 功能,支持 启动、暂停、复位 操作,显示范围 00.00~99.99秒(精确到10ms)。核心思想如下:

  1. 硬件设计
    • 使用 4位共阳极数码管 显示时间(格式:秒.毫秒)。
    • 通过 独立按键 控制秒表的启停和复位。
    • 利用 定时器T0 实现10ms精确定时。
  2. 软件逻辑
    按键消抖:通过延时函数消除机械按键抖动。
    动态扫描:分时刷新4位数码管,避免显示闪烁。
    中断计时:定时器每10ms触发一次中断,累加时间并更新显示。

二、代码流程解析

1. 头文件与宏定义
#include "reg52.h"
#define uint unsigned int
#define uchar unsigned char

头文件:包含51单片机寄存器定义。
宏定义:简化代码书写,uintuchar分别表示无符号整型和字符型。

2. 硬件接口定义
sbit k1 = P1^0;  // 启动按键
sbit k2 = P1^1;  // 暂停按键
sbit k3 = P1^2;  // 复位按键

// 数码管段码表(共阳极,0~9对应编码)
uchar code table[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

按键接口:连接到P1口的低三位。
数码管段码:共阳极数码管的0~9编码,例如0xc0对应数字“0”。


3. 延时函数
void delay(uint a) {
    uint i, j;
    for (i=0; i<a; i++)
        for (j=0; j<120; j++);
}

作用:通过双重循环实现简单延时,用于按键消抖和动态扫描。
参数a控制延时时间,数值越大延时越长。


4. 按键扫描函数
void Scankey() {
    if (k1 == 0) {         // 启动按键按下
        delay(5);          // 消抖
        if (k1 == 0) TR0 = 1; // 启动定时器
    } 
    else if (k2 == 0) {    // 暂停按键按下
        delay(5);
        if (k2 == 0) TR0 = 0; // 关闭定时器
    } 
    else if (k3 == 0) {    // 复位按键按下
        delay(5);
        if (k3 == 0) { sec=0; ms=0; } // 时间归零
    }
}

逻辑
• 检测按键是否按下,延时消抖后确认操作。
k1:启动定时器,开始计时。
k2:暂停定时器,停止计时。
k3:复位秒和毫秒变量。


5. 数码管显示函数
void Display() {
    P2 = 0x01;                   // 选中第1位(秒十位)
    P0 = table[sec/10];          // 显示秒十位
    delay(1);
    
    P2 = 0x02;                   // 选中第2位(秒个位,带小数点)
    P0 = table[sec%10] & 0x7f;   // 0x7f用于点亮小数点
    delay(1);
    
    P2 = 0x04;                   // 选中第3位(毫秒十位)
    P0 = table[ms/10];
    delay(1);
    
    P2 = 0x08;                   // 选中第4位(毫秒个位)
    P0 = table[ms%10];
    delay(1);
}

动态扫描:依次点亮4位数码管,利用人眼视觉暂留实现“同时显示”。
小数点处理:秒个位通过&0x7f操作点亮小数点(共阳极数码管的最高位为小数点)。


6. 定时器初始化
void Time0() {
    TMOD = 0x01;        // 设置定时器T0为模式1(16位定时)
    TH0 = (65535-10000)/256; // 10ms定时初值(假设晶振12MHz)
    TL0 = (65535-10000)%256;
    ET0 = 1;           // 允许定时器T0中断
    EA = 1;            // 开启总中断
    TR0 = 0;           // 初始状态定时器关闭
}

定时器配置
模式1:16位定时模式,最大定时时长约65ms(12MHz晶振)。
初值计算:10ms定时需重装载值10000(即65536-10000)。


7. 主函数
void main() {
    Time0();           // 初始化定时器
    while(1) {         // 主循环
        Display();     // 刷新显示
        Scankey();     // 检测按键
    }
}

主循环:不断刷新显示和检测按键,确保实时响应。


8. 中断服务函数
void zd() interrupt 1 {
    TH0 = (65535-10000)/256; // 重装初值
    TL0 = (65535-10000)%256;
    
    ms++;              // 毫秒计数+1
    if (ms >= 100) {   // 满100ms(即1秒)
        ms = 0;
        sec++;
        if (sec >= 99) sec = 0; // 秒最大值99
    }
}

中断逻辑
• 每10ms触发一次中断,累计100次后秒加1。
• 秒变量sec范围:0~99,实现最大99.99秒显示。


三、关键实现原理

  1. 定时器精度
    • 定时器T0每10ms产生一次中断,通过累加中断次数实现毫秒级计时。
    • 公式:1秒 = 100次中断 × 10ms

  2. 动态扫描显示
    • 分时点亮4位数码管,每次只显示一位,利用视觉暂留效果实现“同时显示”。

  3. 按键消抖
    • 机械按键按下时会产生抖动,通过延时函数(约5ms)消除误触发。


四、总结

本代码通过 硬件+软件协同设计 实现了高精度秒表功能,核心在于定时器中断和动态扫描技术。初学者可通过以下步骤进一步优化:

  1. 增加显示范围:修改sec上限为999,支持更长时间显示。
  2. 优化消抖算法:使用状态机或硬件电路消抖。
  3. 添加蜂鸣器提示:在计时完成时触发声音提示(需扩展硬件)。

希望这篇解析能帮助你理解代码逻辑!如果对细节有疑问,欢迎在评论区讨论~

完整代码

#include "reg52.h"
#define uint unsigned int
#define uchar unsigned char

sbit k1=P1^0;
sbit k2=P1^1;
sbit k3=P1^2;

uint num;
uint sec=0;
uint ms=0;
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,
                    0x92,0x82,0xf8, 0x80,0x90};


void delay(uint a)
{
   uint i,j;
	for(i=0;i<a;i++)
	for(j=0;j<120;j++);
	
}

void Scankey()
{
	if(k1==0)
	{
	 delay(5);
		if(k1==0)
		{
			 TR0=1;
		}
	}
	else if(k2==0)
	{
	 delay(5);
		if(k2==0)
		{
			 TR0=0;
		}
	}
		else if(k3==0)
	{
	 delay(5);
		if(k3==0)
		{
			 sec=0;ms=0;
		}
	}

}
void Display()
{
		P2=0x01;
		P0=table[sec/10];
	  delay(1);
		P2=0x02;
		P0=table[sec%10]&0x7f;	
	  delay(1);
	
		P2=0x04;
		P0=table[ms/10];
	  delay(1);
		P2=0x08;
		P0=table[ms%10];	
	  delay(1);

}



void Time0()
{
TMOD=0x01;
TH0=(65535-10000)/256;
TL0=(65535-10000)%256;
ET0=1;
EA=1;	
TR0=0;
}

/**************
四位数码管显示
00.00-99.99
1s=1000ms,定时10ms++
**************/


void main()
{
Time0();
while(1)
{
		
Display();
Scankey();
 }
	
}

void zd() interrupt 1
{
TH0=(65535-10000)/256;
TL0=(65535-10000)%256;
	ms++;
	if(ms>=100)
	{
	  ms=0;
	  sec++;
  if(sec>=99)
   {
   sec=0;
   }
 }
}


仿真图
在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐