项目代码
- //-----------------------------------------------------
- // Kitchen Timer with TM1637 Display
- // by: mircemk
- // License: GNU GPl 3.0
- // Created: April 2025
- //-----------------------------------------------------
-
-
- #include <TM1637Display.h>
-
- // Pin definitions
- #define CLK 2
- #define DIO 3
- #define POT_PIN A0
- #define START_BUTTON 4
- #define RESET_BUTTON 5
- #define BUZZER_PIN 6
- #define RANGE_BUTTON 7
-
- // Constants
- #define QUANTIZE_INTERVAL 30
- #define POT_SMOOTHING 30
- #define POT_READ_DELAY 50
- #define ALARM_FREQ 500
- #define ALARM_ON_TIME 200
- #define ALARM_OFF_TIME 200
- #define COLON_ON_TIME 500
- #define COLON_OFF_TIME 500
- #define RANGE_DISPLAY_TIME 1000
- #define BUTTON_DEBOUNCE_TIME 300
-
- // Timer ranges in seconds
- const int TIMER_RANGES[] = {600, 1800, 3600}; // 10min, 30min, 60min
- const int NUM_RANGES = 3;
-
- // Display instance
- TM1637Display display(CLK, DIO);
-
- // Variables
- unsigned long previousMillis = 0;
- const long interval = 1000;
- bool timerRunning = false;
- int remainingTime = 0;
- bool colonState = true;
- unsigned long lastBuzzTime = 0;
- unsigned long lastColonToggle = 0;
- bool alarmOn = false;
- bool displayOn = true;
- int lastDisplayedTime = -1;
- unsigned long lastPotRead = 0;
- unsigned long lastDisplayFlash = 0;
- int currentRangeIndex = 2; // Start with 60min range (index 2)
- unsigned long rangeDisplayStartTime = 0;
- bool showingRange = false;
- unsigned long lastRangeButtonPress = 0;
-
- // State enumeration
- enum TimerState {
- IDLE,
- SHOWING_RANGE,
- RUNNING,
- ALARMING
- };
-
- TimerState currentState = IDLE;
-
- void setup() {
- pinMode(START_BUTTON, INPUT_PULLUP);
- pinMode(RESET_BUTTON, INPUT_PULLUP);
- pinMode(RANGE_BUTTON, INPUT_PULLUP);
- pinMode(BUZZER_PIN, OUTPUT);
-
- display.setBrightness(0x0a);
- updateDisplay(quantizeTime(readSmoothedPot()));
- }
-
- void loop() {
- unsigned long currentMillis = millis();
-
- switch(currentState) {
- case SHOWING_RANGE:
- // Stay in range display mode until time elapsed
- if (currentMillis - rangeDisplayStartTime >= RANGE_DISPLAY_TIME) {
- currentState = IDLE;
- lastDisplayedTime = -1; // Force pot reading update
- } else {
- // Keep showing range
- displayRange(TIMER_RANGES[currentRangeIndex]);
- return; // Skip all other processing while showing range
- }
- break;
-
- case IDLE:
- // Handle range button
- if (digitalRead(RANGE_BUTTON) == LOW) {
- if (currentMillis - lastRangeButtonPress >= BUTTON_DEBOUNCE_TIME) {
- currentRangeIndex = (currentRangeIndex + 1) % NUM_RANGES;
- rangeDisplayStartTime = currentMillis;
- lastRangeButtonPress = currentMillis;
- currentState = SHOWING_RANGE;
- displayRange(TIMER_RANGES[currentRangeIndex]);
- return; // Exit loop immediately after changing to range display
- }
- }
-
- // Handle potentiometer input
- if (currentMillis - lastPotRead > POT_READ_DELAY) {
- lastPotRead = currentMillis;
- int potTime = quantizeTime(readSmoothedPot());
- if (potTime != lastDisplayedTime) {
- colonState = true;
- updateDisplay(potTime);
- lastDisplayedTime = potTime;
- }
- }
-
- // Handle start button
- if (digitalRead(START_BUTTON) == LOW) {
- delay(50);
- if (digitalRead(START_BUTTON) == LOW) {
- remainingTime = quantizeTime(readSmoothedPot());
- currentState = RUNNING;
- previousMillis = currentMillis;
- lastDisplayedTime = -1;
- colonState = true;
- lastColonToggle = currentMillis;
- }
- }
- break;
-
- case RUNNING:
- // Handle colon blinking
- if (colonState && (currentMillis - lastColonToggle >= COLON_ON_TIME)) {
- colonState = false;
- lastColonToggle = currentMillis;
- updateDisplay(remainingTime);
- }
- else if (!colonState && (currentMillis - lastColonToggle >= COLON_OFF_TIME)) {
- colonState = true;
- lastColonToggle = currentMillis;
- updateDisplay(remainingTime);
- }
-
- // Update timer
- if (currentMillis - previousMillis >= interval) {
- previousMillis = currentMillis;
- if (remainingTime > 0) {
- remainingTime--;
- updateDisplay(remainingTime);
- }
- if (remainingTime == 0) {
- currentState = ALARMING;
- }
- }
-
- // Check reset button
- if (digitalRead(RESET_BUTTON) == LOW) {
- delay(50);
- if (digitalRead(RESET_BUTTON) == LOW) {
- resetTimer();
- }
- }
- break;
-
- case ALARMING:
- handleAlarm();
- if (digitalRead(RESET_BUTTON) == LOW) {
- delay(50);
- if (digitalRead(RESET_BUTTON) == LOW) {
- resetTimer();
- }
- }
- break;
- }
- }
-
- void displayRange(int rangeInSeconds) {
- int minutes = rangeInSeconds / 60;
- uint8_t segments[4];
-
- segments[0] = display.encodeDigit(minutes / 10);
- segments[1] = display.encodeDigit(minutes % 10) | 0x80; // Force colon on
- segments[2] = display.encodeDigit(0);
- segments[3] = display.encodeDigit(0);
-
- display.setSegments(segments);
- }
-
- int readSmoothedPot() {
- long total = 0;
- for (int i = 0; i < POT_SMOOTHING; i++) {
- total += analogRead(POT_PIN);
- delay(1);
- }
- int average = total / POT_SMOOTHING;
- return map(average, 0, 1023, 0, TIMER_RANGES[currentRangeIndex]);
- }
-
- int quantizeTime(int seconds) {
- int quantized = (seconds / QUANTIZE_INTERVAL) * QUANTIZE_INTERVAL;
- return constrain(quantized, 0, TIMER_RANGES[currentRangeIndex]);
- }
-
- void updateDisplay(int timeInSeconds) {
- if (currentState == ALARMING && !displayOn) {
- display.clear();
- return;
- }
-
- int minutes = timeInSeconds / 60;
- int seconds = timeInSeconds % 60;
-
- uint8_t segments[4];
-
- segments[0] = display.encodeDigit(minutes / 10);
- segments[1] = display.encodeDigit(minutes % 10);
- segments[2] = display.encodeDigit(seconds / 10);
- segments[3] = display.encodeDigit(seconds % 10);
-
- if (colonState) {
- segments[1] |= 0x80;
- }
-
- display.setSegments(segments);
- lastDisplayedTime = timeInSeconds;
- }
-
- void handleAlarm() {
- unsigned long currentMillis = millis();
-
- // Handle display flashing
- if (currentMillis - lastDisplayFlash >= 500) {
- lastDisplayFlash = currentMillis;
- displayOn = !displayOn;
- updateDisplay(0);
- }
-
- // Handle intermittent alarm sound
- if (currentMillis - lastBuzzTime >= (alarmOn ? ALARM_ON_TIME : ALARM_OFF_TIME)) {
- lastBuzzTime = currentMillis;
- alarmOn = !alarmOn;
-
- if (alarmOn) {
- tone(BUZZER_PIN, ALARM_FREQ);
- } else {
- noTone(BUZZER_PIN);
- }
- }
- }
-
- void resetTimer() {
- currentState = IDLE;
- timerRunning = false;
- noTone(BUZZER_PIN);
- alarmOn = false;
- displayOn = true;
- colonState = true;
- lastDisplayedTime = -1;
- updateDisplay(quantizeTime(readSmoothedPot()));
- }
复制代码
|