/* Copyright (c) 2025 Rodrigo Arias Mallo * SPDX-License-Identifier: GPL-3.0-or-later */ /* * ATmega328p * +---------+ * (PCINT14/RESET) PC6 -|1 \_/ 28|- PC5 (ADC5/SCL/PCINT13) * (PCINT16/RXD) PD0 -|2 27|- PC4 (ADC4/SDA/PCINT12) * (PCINT17/TXD) PD1 -|3 26|- PC3 (ADC3/PCINT11) * (PCINT18/INT0) PD2 -|4 25|- PC2 (ADC2/PCINT10) * (PCINT19/OC2B/INT1) PD3 -|5 24|- PC1 (ADC1/PCINT9) * (PCINT20/XCK/T0) PD4 -|6 23|- PC0 (ADC0/PCINT8) * VCC -|7 22|- GND * GND -|8 21|- AREF * (PCINT6/XTAL1/TOSC1) PB6 -|9 20|- AVCC * (PCINT7/XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK/PCINT5) * (PCINT21/OC0B/T1) PD5 -|11 18|- PB4 (MISO/PCINT4) * (PCINT22/OC0A/AIN0) PD6 -|12 17|- PB3 (MOSI/OC2A/PCINT3) * (PCINT23/AIN1) PD7 -|13 16|- PB2 (SS/OC1B/PCINT2) * (PCINT0/CLKO/ICP1) PB0 -|14 15|- PB1 (OC1A/PCINT1) * +---------+ * * * ATMEL ATMEGA8 & 168 / ARDUINO * * +-\/-+ * PC6 1| |28 PC5 (AI 5) * (D 0) PD0 2| |27 PC4 (AI 4) * (D 1) PD1 3| |26 PC3 (AI 3) * (D 2) PD2 4| |25 PC2 (AI 2) * PWM+ (D 3) PD3 5| |24 PC1 (AI 1) * (D 4) PD4 6| |23 PC0 (AI 0) * VCC 7| |22 GND * GND 8| |21 AREF * PB6 9| |20 AVCC * PB7 10| |19 PB5 (D 13) * PWM+ (D 5) PD5 11| |18 PB4 (D 12) * PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM * (D 7) PD7 13| |16 PB2 (D 10) PWM * (D 8) PB0 14| |15 PB1 (D 9) PWM * +----+ * * */ enum pinout { /* Inputs */ PIN_POWER_ON = 8, PIN_HOT = 9, //PIN_FLOW = PIN_D5, /* Outputs */ PIN_LED_GREEN = 5, PIN_LED_RED = 6, PIN_HEAT = 7, PIN_PUMP = 12, PIN_BUZZ = 10, /* Analog */ PIN_NTC = PIN_A0, }; enum logic { ON = 1, OFF = 0, }; #define DEBOUNCE_TIME 20L /* ms */ #define TEMP_MIN 600 #define TEMP_MAX 700 #define LED_MIN_VALUE 0 enum state { SLEEPING, DEBOUNCE, HEATING, HOT, BREWING, COOLING, }; long debounce_t0 = 0; int state = SLEEPING; enum button { BUTTON_ON = 0, BUTTON_HOT, MAX_BUTTON, }; enum button_state { RESTING = 0, PRESSING, PRESSED, RELEASING, RELEASED, }; enum buzz_state { BUZZ_OFF = 0, BUZZ_HEY, BUZZ_STOP, }; int buzz_state; int button_pin[MAX_BUTTON] = { [BUTTON_ON] = PIN_POWER_ON, [BUTTON_HOT] = PIN_HOT, }; int button_state[MAX_BUTTON]; unsigned long button_press_t0[MAX_BUTTON]; unsigned long button_release_t0[MAX_BUTTON]; int read_input(int pin) { return !digitalRead(pin); } void relay(int pin, enum logic st) { /* Relays are active low */ if (st == ON) digitalWrite(pin, 0); else digitalWrite(pin, 1); } void setled(int pin, enum logic st) { /* LEDs are active high */ if (st == ON) digitalWrite(pin, 1); else digitalWrite(pin, 0); } void update_buttons() { for (int i = 0; i < MAX_BUTTON; i++) { int st = button_state[i]; int pin = button_pin[i]; if (st == RESTING) { if (read_input(pin) == ON) { button_state[i] = PRESSING; button_press_t0[i] = millis(); } } else if (st == PRESSING) { if (read_input(pin) != ON) { button_state[i] = RESTING; } else if (millis() - button_press_t0[i] > DEBOUNCE_TIME) { button_state[i] = PRESSED; } } else if (st == PRESSED) { if (read_input(pin) != ON) { button_state[i] = RELEASING; button_release_t0[i] = millis(); } } else if (st == RELEASING) { if (read_input(pin) == ON) { button_state[i] = PRESSED; } else if (millis() - button_release_t0[i] > DEBOUNCE_TIME) { button_state[i] = RELEASED; } } else if (st == RELEASED) { button_state[i] = RESTING; } } } int red_min = 50; int red_state = red_min; unsigned long brewing_time = 3000UL; /* 3 seconds */ unsigned long cooling_time = 3000UL; /* 3 seconds */ unsigned long max_heating_time = 10000UL; /* 10 seconds */ unsigned long max_idle_time = 10000UL; /* 10 seconds */ void progress() { int temp = analogRead(PIN_NTC); int on = (button_state[BUTTON_ON] == RELEASED); int hot = (button_state[BUTTON_HOT] == PRESSED); static unsigned long brewing_t0 = 0; static unsigned long cooling_t0 = 0; static unsigned long heating_t0 = 0; static unsigned long hot_t0 = 0; Serial.print("state="); Serial.print(state); Serial.print(" on="); Serial.print(on); Serial.print(" temp="); Serial.println(temp); /* Pressing ON cancels any operation */ if (state != SLEEPING && on) { state = SLEEPING; return; } if (state == SLEEPING) { if (on) { state = HEATING; heating_t0 = millis(); Serial.println("heating"); } } else if (state == HEATING) { if (temp > TEMP_MAX) { state = HOT; hot_t0 = millis(); buzz_state = BUZZ_HEY; Serial.println("hot"); } else if (millis() - heating_t0 > max_heating_time) { /* TODO: Add alarm state */ state = SLEEPING; Serial.println("cannot heat, going to sleep"); } } else if (state == HOT) { if (hot) { state = BREWING; brewing_t0 = millis(); Serial.println("brewing"); } else if (millis() - hot_t0 > max_idle_time) { state = SLEEPING; Serial.println("idle timeout, going to sleep"); } } else if (state == BREWING) { if (millis() - brewing_t0 > brewing_time) { state = COOLING; cooling_t0 = millis(); Serial.println("cooling"); } } else if (state == COOLING) { /* TODO: Wait a bit and go back to heating */ if (millis() - cooling_t0 > cooling_time) { state = HEATING; heating_t0 = millis(); Serial.println("heating"); } } } void update_leds() { static int r = 0; static int g = 0; if (state == HEATING || state == COOLING) { analogWrite(PIN_LED_RED, r); setled(PIN_LED_GREEN, 0); if (r >= 255) r = 0; else r += 3; } else if (state == HOT) { setled(PIN_LED_RED, 0); setled(PIN_LED_GREEN, 1); r = 0; } else if (state == BREWING) { setled(PIN_LED_RED, 0); analogWrite(PIN_LED_GREEN, g); if (g >= 255) g = 0; else g += 3; } else { setled(PIN_LED_RED, 0); setled(PIN_LED_GREEN, 0); r = 0; } } void update_heater() { if (state == HEATING || state == HOT || state == BREWING) { int temp = analogRead(PIN_NTC); if (temp < TEMP_MIN) relay(PIN_HEAT, ON); else if (temp > TEMP_MAX) relay(PIN_HEAT, OFF); } else { relay(PIN_HEAT, OFF); } } void update_pump() { if (state == BREWING) { relay(PIN_PUMP, ON); } else { relay(PIN_PUMP, OFF); } } void update_buzz() { static unsigned long started = 0; if (buzz_state == BUZZ_HEY) { tone(PIN_BUZZ, 1500); if (started == 0) started = millis(); else if (millis() - started > 20) { buzz_state = BUZZ_OFF; } } else if (buzz_state == BUZZ_STOP) { tone(PIN_BUZZ, 220); } else if (buzz_state == BUZZ_OFF) { noTone(PIN_BUZZ); started = 0; } } void setup() { Serial.begin(9600); Serial.println("Booting"); pinMode(PIN_POWER_ON, INPUT); pinMode(PIN_HOT, INPUT); pinMode(PIN_LED_RED, OUTPUT); pinMode(PIN_LED_GREEN, OUTPUT); pinMode(PIN_HEAT, OUTPUT); pinMode(PIN_PUMP, OUTPUT); /* Turn all relays off */ relay(PIN_HEAT, OFF); relay(PIN_PUMP, OFF); Serial.println("Ready"); } void loop() { //Serial.println("Looping..."); update_buttons(); progress(); update_leds(); update_heater(); update_pump(); update_buzz(); delay(5); }