DIY 可调倒计时器:Arduino Mega 2560 驱动 4 位数码管
项目简介
一个独立、实用的倒计时器:通过 4 个按钮设定时间(0-9999 秒),启动后数码管实时倒计时,归零蜂鸣器报警。无需修改代码重新上传即可调整时间,适合厨房、实验室、健身等场景。代码封装了 PrintNumber(int n, int time) 函数,可直接复用于其他 4 位数码管项目,解决了动态扫描显示的时序难题。
所需材料
- Arduino Mega 2560(Uno/Nano 亦可,引脚需对应修改)
- 4 位共阴/共阳数码管模块(裸屏需自行加限流电阻)
- 轻触按钮 ×4(设置+、设置-、启动/暂停、复位)
- 无源蜂鸣器
- 全尺寸面包板、杜邦线若干
引脚分配(可在代码修改)
| 功能 | Arduino 引脚 |
|---|---|
| 段选 a-g | D2-D8 (A0 作为段选 e) |
| 位选 1-4 (左到右) | D6, D9, D10, D11 (PWM 引脚) |
| 蜂鸣器 | D15 (A1) |
| 按钮 1 (启动/暂停) | D13 |
| 按钮 2 (复位/停止) | D12 |
| 按钮 3 (时间 -) | D16 (A2) |
| 按钮 4 (时间 +) | D17 (A3) |
所有按钮启用内部上拉 (INPUT_PULLUP),按下接地触发低电平。
核心代码结构
关键函数
lightNumber(int num):根据数字 0-9 (10 为熄灭) 驱动段选SwitchDigit(int pos):开启指定位选,关闭其它 (PWM 控制亮度)IntToDigits(int n):将 0-9999 拆解为 4 位数组,前导零熄灭PrintNumber(int n, int ms):在指定毫秒内持续扫描显示数字 n,期间检测按钮 2 中止Countdown(int n, int del):从 n 递减到 0,每数调用PrintNumber,返回是否正常结束reset():设置模式,按钮 3/4 长按加减,按钮 1 确认进入倒计时
完整代码
#include <math.h>
int digit_pin[] = {6, 9, 10, 11};
int speakerPin = 15;
#define DIGIT_ON LOW
#define DIGIT_OFF HIGH
int segA = 2, segB = 3, segC = 4, segD = 5;
int segE = A0, segF = 7, segG = 8;
int button1 = 13, button2 = 12, button3 = 16, button4 = 17;
int countdown_time = 60;
struct Digits { int d[4]; };
void setup() {
pinMode(segA, OUTPUT); pinMode(segB, OUTPUT); pinMode(segC, OUTPUT);
pinMode(segD, OUTPUT); pinMode(segE, OUTPUT); pinMode(segF, OUTPUT); pinMode(segG, OUTPUT);
for (int i = 0; i < 4; i++) pinMode(digit_pin[i], OUTPUT);
pinMode(speakerPin, OUTPUT);
pinMode(button1, INPUT_PULLUP); pinMode(button2, INPUT_PULLUP);
pinMode(button3, INPUT_PULLUP); pinMode(button4, INPUT_PULLUP);
}
void playTone(int tone, int duration) {
for (long k = 0; k < duration * 1000L; k += tone * 2) {
digitalWrite(speakerPin, HIGH); delayMicroseconds(tone);
digitalWrite(speakerPin, LOW); delayMicroseconds(tone);
}
}
void lightNumber(int n) {
#define SEG_ON HIGH
#define SEG_OFF LOW
switch (n) {
case 0: digitalWrite(segA, SEG_ON); digitalWrite(segB, SEG_ON); digitalWrite(segC, SEG_ON);
digitalWrite(segD, SEG_ON); digitalWrite(segE, SEG_ON); digitalWrite(segF, SEG_ON);
digitalWrite(segG, SEG_OFF); break;
case 1: digitalWrite(segA, SEG_OFF); digitalWrite(segB, SEG_ON); digitalWrite(segC, SEG_ON);
digitalWrite(segD, SEG_OFF); digitalWrite(segE, SEG_OFF); digitalWrite(segF, SEG_OFF);
digitalWrite(segG, SEG_OFF); break;
// ... case 2-9 同理,case 10 全熄灭
}
}
void SwitchDigit(int pos) {
for (int i = 0; i < 4; i++)
digitalWrite(digit_pin[i], (i == pos) ? DIGIT_ON : DIGIT_OFF);
}
Digits IntToDigits(int n) {
Digits dg; int zeros = 0, d;
for (int i = 0; i < 4; i++) {
d = n / pow(10, 3 - i);
zeros += d;
n -= d * pow(10, 3 - i);
dg.d[i] = (zeros != 0 || i == 3) ? d : 10;
}
return dg;
}
void PrintNumber(int n, int ms) {
Digits dg = IntToDigits(n);
for (int i = 0; i <= ms / 20; i++) {
if (digitalRead(button2) == LOW) return; // 按钮 2 中止
for (int j = 0; j < 4; j++) {
SwitchDigit(j); lightNumber(dg.d[j]); delay(5);
}
}
}
bool Countdown(int n, int del) {
for (int q = n; q > 0; q--) {
PrintNumber(q, del);
if (digitalRead(button2) == LOW) return false;
}
PrintNumber(0, 0);
playTone(1519, 1000);
return true;
}
void reset() {
int pressed3 = 0, pressed4 = 0;
Digits dg = IntToDigits(countdown_time);
while (digitalRead(button1) == HIGH) { // 等待按钮 1 确认
for (int j = 0; j < 4; j++) { SwitchDigit(j); lightNumber(dg.d[j]); delay(5); }
if (digitalRead(button3) == LOW) {
if (pressed3 == 0 || pressed3 > 30) { if (countdown_time > 0) countdown_time--; dg = IntToDigits(countdown_time); }
pressed3++;
} else if (digitalRead(button4) == LOW) {
if (pressed4 == 0 || pressed4 > 30) { if (countdown_time < 9999) countdown_time++; dg = IntToDigits(countdown_time); }
pressed4++;
}
if (digitalRead(button3) == HIGH) pressed3 = 0;
if (digitalRead(button4) == HIGH) pressed4 = 0;
}
}
void loop() {
reset();
while (!Countdown(countdown_time, 962)) reset();
while (digitalRead(button2) == HIGH); // 等待按钮 2 复位
}
使用说明
- 上电进入设置模式,数码管显示当前预设时间 (默认 60 秒)
- 短按/长按 按钮 3 (-) / 按钮 4 (+) 调整时间
- 按 按钮 1 (启动) 开始倒计时
- 倒计时过程中按 按钮 2 (复位) 可中止并返回设置模式
- 倒计时归零,蜂鸣器响 1 秒,再次按按钮 2 复位
扩展建议
- 改用 TM1637/HT16K33 驱动芯片模块,省去动态扫描代码,亮度可调
- 增加 EEPROM 存储上次设定时间,掉电记忆
- 加入暂停/继续功能 (按钮 1 切换)
- 设计外壳,配电池盒做便携计时器
- 移植到 ATtiny85 + TM1637 做极简版本
制造工艺
- 液晶显示器(LCD):技术、制造与未来展望
- Primal Display:树莓派 LCD 温度监测仪
- Kuman 3.5″ TFT 显示屏在 RetroPie 上安装全步骤指南
- 用 Arduino UNO 和 OLED 显示屏制作经典 Pong 游戏:分步教程
- 理解看门狗定时器:如何防止单片机死机卡死
- ATmega328P 双芯片外星人主题老虎机:完整概率数学与 I²C 从机显示
- 基于 Arduino Mega 与 Nextion 显示屏的交互式气象站
- 使用 SparkFun 7 段数码管构建可靠的 Arduino 倒计时器
- Arduino 驱动的真空荧光显示器(VFD)控制器套件
- 可调减震器:提升车身高度与操控性能的进阶方案
- 掌握 C# 方法重载:核心概念、实战示例与最佳实践
- 理解Verilog任务:函数vs任务、语法与用法全解析