## 功能概述
基于 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 位数码管额外点亮小数点实现秒/毫秒分隔 小数点跳动
