Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4693628fc | |||
0246999214 | |||
d48e89328f | |||
53f331cc12 |
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@ -1,23 +0,0 @@
|
||||
---
|
||||
name: Build Firmware
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-firmware:
|
||||
name: Compile
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup AVR-GCC
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y gcc-avr binutils-avr avr-libc
|
||||
avr-gcc --version
|
||||
|
||||
- name: Compile
|
||||
working-directory: firmware
|
||||
run: make compile info
|
@ -1,5 +1,3 @@
|
||||
View this project on [CADLAB.io](https://cadlab.io/node/863).
|
||||
|
||||
# Senseo Control 2.0
|
||||
|
||||
A completely rebuilt AVR based hard- and software for Senseo® HD782x coffee machine.
|
||||
|
@ -56,4 +56,4 @@ fuses:
|
||||
@$(AVRDUDE) -p $(MCU) -q -q -u -V -c $(PGMDEV) $(PGMOPT) -U lfuse:w:0xE1:m -U hfuse:w:0x12:m
|
||||
|
||||
clean:
|
||||
@$(REMOVE) $(TARGET).elf $(TARGET).hex
|
||||
@$(REMOVE) $(TARGET).elf
|
||||
|
290
firmware/main.c
290
firmware/main.c
@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
* SenseoControl 2.0 *
|
||||
* Copyright (C) 2013-2022 Stefan Kalscheuer *
|
||||
* Copyright (C) 2013-2018 Stefan Kalscheuer *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
@ -36,16 +36,12 @@
|
||||
#include "main.h"
|
||||
|
||||
// variables:
|
||||
volatile unsigned int time_counter; // Global time counter (ms).
|
||||
volatile unsigned int user_time_counter = 0; // Universal time counter (ms).
|
||||
volatile unsigned int sec_counter = 0; // Second-counter (for AutoOff).
|
||||
volatile unsigned int button_1_cup_counter = 0; // Left button counter (1 cup).
|
||||
volatile unsigned int button_2_cup_counter = 0; // Left button counter (2 cups).
|
||||
volatile unsigned char button_power_counter = 0; // Power button counter.
|
||||
volatile unsigned char led = 0; // LED status flags.
|
||||
volatile unsigned char state; // Water-, temperature-, clean-flags.
|
||||
volatile unsigned char make_coffee = NO_COFFEE; // Coffee mode flag.
|
||||
volatile unsigned char pump_time = 0; // Pump time.
|
||||
volatile unsigned int time_counter, user_time_counter = 0, sec_counter = 0; // Global and universal time counter (ms) and second-counter (for AutoOff).
|
||||
volatile unsigned int button_1_cup_counter = 0, button_2_cup_counter = 0; // Button counter.
|
||||
volatile unsigned char button_power_counter = 0;
|
||||
volatile unsigned char led = 0; // LED status flags.
|
||||
volatile unsigned char state; // Water-, temperature-, clean-flags.
|
||||
volatile unsigned char make_coffee = 0, pump_time = 0; // Pump time, clean mode flag.
|
||||
|
||||
/**
|
||||
* Main program.
|
||||
@ -54,21 +50,20 @@ volatile unsigned char pump_time = 0; // Pump time.
|
||||
*/
|
||||
int main(void) {
|
||||
init(); // Initialization.
|
||||
power_off(); // Power off after init sequence.
|
||||
power_off(); // Power off after init sequece.
|
||||
|
||||
while (1) { // Main loop.
|
||||
if (sec_counter >= AUTO_OFF_THRESHOLD) {
|
||||
if (sec_counter >= AUTO_OFF_THRESHOLD)
|
||||
button_power_counter = BUTTON_THRESHOLD; // Check for AutoOff Timer (generate OnOff-button push).
|
||||
}
|
||||
|
||||
update_water(); // Update water state.
|
||||
update_temperature(); // Update temperature.
|
||||
|
||||
if (button_power_counter >= BUTTON_THRESHOLD) { // Button "OnOff" pushed:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off
|
||||
make_coffee = NO_COFFEE; // Clear coffee flag.
|
||||
make_coffee = 0; // Clear coffee flag.
|
||||
|
||||
while (button_power_counter > 0); // Wait until button is released (debounce)
|
||||
while (button_power_counter > 0); // Wait until button is releasd (debounce)
|
||||
|
||||
power_off(); // Call power off sequence
|
||||
|
||||
@ -76,29 +71,125 @@ int main(void) {
|
||||
while (button_power_counter > 0);
|
||||
}
|
||||
|
||||
process_buttons();
|
||||
if (button_1_cup_counter >= BUTTON_CLEAN_THR && button_2_cup_counter >= BUTTON_CLEAN_THR) {
|
||||
// Both coffee buttons pushed: enter clean mode.
|
||||
set_bit(state, S_CLEAN); // Set clean flag.
|
||||
led = BLUE; // Set blue LED.
|
||||
while (button_1_cup_counter > 0 && button_2_cup_counter > 0); // Debounce buttons.
|
||||
} else if (button_1_cup_counter >= BUTTON_THRESHOLD && button_2_cup_counter < BUTTON_THRESHOLD) {
|
||||
// Left coffee button pushed: call espresso.
|
||||
sec_counter = 0; // Reset AutoOff counter.
|
||||
|
||||
if (state & S_WATER) { // Water OK:
|
||||
if (state & S_CLEAN) { // If clean-flag is set:
|
||||
do_clean();
|
||||
} else if (state & S_TEMP) { // Temperature OK:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
led = GREEN; // Set green LED.
|
||||
if (make_coffee > NO_COFFEE) { // If coffee flag is set:
|
||||
do_coffee();
|
||||
if ((state & S_WATER) && (state & S_TEMP)) { // Machine ready:
|
||||
while (button_1_cup_counter > 0) { // Check if button is pushed long time.
|
||||
if (button_1_cup_counter > BUTTON_LONG_THR) { // Button pushed for a long time:
|
||||
make_coffee = 1; // Set coffee flag to 1 (1 espresso).
|
||||
button_1_cup_counter = 0; // Clear button counter.
|
||||
}
|
||||
}
|
||||
} else { // Temperature too low.
|
||||
if (make_coffee != 1) {
|
||||
make_coffee = 3; // Set coffee flag to 3 (1 coffee) otherwise.
|
||||
}
|
||||
} else if (COFFEE_WISH) { // Save coffee wish.
|
||||
make_coffee = 3;
|
||||
}
|
||||
} else if (button_1_cup_counter < BUTTON_THRESHOLD && button_2_cup_counter >= BUTTON_THRESHOLD) {
|
||||
// Right coffee button pushed: call coffee.
|
||||
sec_counter = 0; // Reset AutoOff counter.
|
||||
|
||||
if ((state & S_WATER) && (state & S_TEMP)) { // Machine ready:
|
||||
while (button_2_cup_counter > 0) { // Check if button is pushed long time.
|
||||
if (button_2_cup_counter > BUTTON_LONG_THR) { // Button pushed for a long time:
|
||||
make_coffee = 2; // Set coffee flag to 2 (2 espresso).
|
||||
button_2_cup_counter = 0; // Clear button counter.
|
||||
}
|
||||
}
|
||||
if (make_coffee != 2) {
|
||||
make_coffee = 4; // Set coffee flag to 4 (2 coffee) otherwise.
|
||||
}
|
||||
} else if (COFFEE_WISH) { // Save coffee wish
|
||||
make_coffee = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state & S_WATER)) { // Water OK:
|
||||
if ((state & S_CLEAN)) { // If clean-flag is set:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
clear_bit(state, S_ESC); // Init escape-flag.
|
||||
while ((state & S_WATER) && (state & S_ESC)) { // Pump until water is empty or escape flag is set.
|
||||
if (detect_zero_crossing() <= 100) { // Detect zero crossing.
|
||||
clear_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Generate trigger impulse for pump triac.
|
||||
_delay_ms(3);
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
}
|
||||
update_water(); // Update water state.
|
||||
|
||||
if (button_power_counter > BUTTON_THRESHOLD) {
|
||||
set_bit(state, S_ESC); // Check power button counter and set escape flag.
|
||||
}
|
||||
}
|
||||
clear_bit(state, S_CLEAN); // Clear clean flag.
|
||||
} else if ((state & S_TEMP)) { // Temperature OK:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
|
||||
led = GREEN; // Set green LED.
|
||||
|
||||
if (make_coffee > 0) { // If coffee flag is set:
|
||||
if (make_coffee < 3) {
|
||||
led = ORANGE_BLINK; // Set orange LED blink for espresso.
|
||||
} else {
|
||||
led = GREEN_BLINK; // Set green LED blink for coffee.
|
||||
}
|
||||
|
||||
if (make_coffee == 1) {
|
||||
pump_time = TIME_1_ESPRESSO; // 1 cup of espresso (2s preinfusion included).
|
||||
} else if (make_coffee == 2) {
|
||||
pump_time = TIME_2_ESPRESSO; // 2 cups of espresso (2s preinfusion included).
|
||||
} else if (make_coffee == 3) {
|
||||
pump_time = TIME_1_COFFEE; // 1 cup of coffee.
|
||||
} else if (make_coffee == 4) {
|
||||
pump_time = TIME_2_COFFEE; // 2 cups of coffee.
|
||||
} else {
|
||||
make_coffee = 0;
|
||||
}
|
||||
|
||||
user_time_counter = 0; // Reset user time counter.
|
||||
clear_bit(state, S_ESC); // Init escape flag.
|
||||
|
||||
// loop until pump time is reached or water is empty
|
||||
while (user_time_counter < (pump_time * 1000) && (state & S_WATER) && !(state & S_ESC)) {
|
||||
// Check for preinfusion break.
|
||||
if (make_coffee > 2 || (user_time_counter < 2000 || user_time_counter > 4000)) {
|
||||
if (detect_zero_crossing() <= 100) { // Detect zero crossing.
|
||||
clear_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Generate trigger impulse for pump triac.
|
||||
_delay_ms(3);
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
}
|
||||
}
|
||||
|
||||
update_water(); // Update water state.
|
||||
|
||||
if (button_power_counter > BUTTON_THRESHOLD) {
|
||||
set_bit(state, S_ESC); // Check for power button counter and set escape flag.
|
||||
}
|
||||
}
|
||||
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Pump off
|
||||
make_coffee = 0; // Clear coffee flag.
|
||||
sec_counter = 0; // Reset AutoOff timer.
|
||||
}
|
||||
} else { // Temperature too low.
|
||||
clear_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler on.
|
||||
if (make_coffee > NO_COFFEE) { // Set violet LED blink if coffee wish is saved.
|
||||
if (make_coffee > 0) { // Set red/blue LED blink if coffee wish is saved.
|
||||
led = VIOLET_BLINK;
|
||||
} else { // Set red LED blink if no coffee wish is saved.
|
||||
led = RED_BLINK;
|
||||
}
|
||||
}
|
||||
} else { // Water too low:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Pump off.
|
||||
led = BLUE_BLINK; // Set blue LED blink.
|
||||
} else { // Water too low:
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Pump off.
|
||||
led = BLUE_BLINK; // Set blue LED blink.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,7 +198,7 @@ int main(void) {
|
||||
* Initializes relevant bits, timer and ADC.
|
||||
*/
|
||||
void init() {
|
||||
clear_bit(ZERO_CROSSING_ddr, ZERO_CROSSING_pin); // Zero crossing detection pins as input.
|
||||
clear_bit(ZERO_CROSSING_ddr, ZERO_CROSSING_pin); // Zero crossing dection pins as input-
|
||||
clear_bit(ZERO_CROSSING_w, ZERO_CROSSING_pin); // No internal pull-up (for ADC).
|
||||
|
||||
clear_bit(BUTTON_1_CUP_ddr, BUTTON_1_CUP_pin); // Button pins as input.
|
||||
@ -153,7 +244,7 @@ void init() {
|
||||
/**
|
||||
* Clear bits and set controller to sleep mode.
|
||||
*/
|
||||
void power_off(void) {
|
||||
void power_off() {
|
||||
cli(); // Disable interrupts.
|
||||
set_bit(GIMSK, INT0); // Activate interrupt 0 (for wake-up).
|
||||
clear_bit(TIMSK, TOIE1); // Deactivate timer 1.
|
||||
@ -221,139 +312,6 @@ unsigned int detect_zero_crossing() {
|
||||
return (sense_H << 8) | sense_L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process button inputs and update states accordingly.
|
||||
*/
|
||||
static void process_buttons(void) {
|
||||
if (button_1_cup_counter >= BUTTON_CLEAN_THR && button_2_cup_counter >= BUTTON_CLEAN_THR) {
|
||||
// Both coffee buttons pushed: enter clean mode.
|
||||
set_bit(state, S_CLEAN); // Set clean flag.
|
||||
led = BLUE; // Set blue LED.
|
||||
while (button_1_cup_counter > 0 && button_2_cup_counter > 0); // Debounce buttons.
|
||||
} else if (button_1_cup_counter >= BUTTON_THRESHOLD && button_2_cup_counter < BUTTON_THRESHOLD) {
|
||||
// Left coffee button pushed: call espresso.
|
||||
sec_counter = 0; // Reset AutoOff counter.
|
||||
|
||||
if ((state & S_WATER) && (state & S_TEMP)) { // Machine ready:
|
||||
while (button_1_cup_counter > 0) { // Check if button is pushed long time.
|
||||
if (button_1_cup_counter > BUTTON_LONG_THR) { // Button pushed for a long time:
|
||||
make_coffee = ONE_ESPRESSO; // Set coffee flag to 1 (1 espresso).
|
||||
button_1_cup_counter = 0; // Clear button counter.
|
||||
}
|
||||
}
|
||||
if (make_coffee != ONE_ESPRESSO) {
|
||||
make_coffee = ONE_COFFEE; // Set coffee flag to 3 (1 coffee) otherwise.
|
||||
}
|
||||
} else if (COFFEE_WISH) { // Save coffee wish.
|
||||
make_coffee = ONE_COFFEE;
|
||||
}
|
||||
} else if (button_1_cup_counter < BUTTON_THRESHOLD && button_2_cup_counter >= BUTTON_THRESHOLD) {
|
||||
// Right coffee button pushed: call coffee.
|
||||
sec_counter = 0; // Reset AutoOff counter.
|
||||
|
||||
if ((state & S_WATER) && (state & S_TEMP)) { // Machine ready:
|
||||
while (button_2_cup_counter > 0) { // Check if button is pushed long time.
|
||||
if (button_2_cup_counter > BUTTON_LONG_THR) { // Button pushed for a long time:
|
||||
make_coffee = TWO_ESPRESSO; // Set coffee flag to 2 (2 espresso).
|
||||
button_2_cup_counter = 0; // Clear button counter.
|
||||
}
|
||||
}
|
||||
if (make_coffee != TWO_ESPRESSO) {
|
||||
make_coffee = TWO_COFFEE; // Set coffee flag to 4 (2 coffee) otherwise.
|
||||
}
|
||||
} else if (COFFEE_WISH) { // Save coffee wish
|
||||
make_coffee = TWO_COFFEE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute cleaning routine.
|
||||
* Pump water without additional heating, until the water tank is empty or the power button is pushed.
|
||||
*/
|
||||
static void do_clean(void) {
|
||||
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off.
|
||||
clear_bit(state, S_ESC); // Init escape-flag.
|
||||
|
||||
// Pump until water is empty or escape flag is set.
|
||||
while ((state & S_WATER) && (state & S_ESC)) {
|
||||
// Detect zero crossing and trigger impulse for the pump triac.
|
||||
if (detect_zero_crossing() <= 100) {
|
||||
clear_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
_delay_ms(3);
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
}
|
||||
|
||||
// Update water state.
|
||||
update_water();
|
||||
|
||||
// Check power button counter and set escape flag.
|
||||
if (button_power_counter > BUTTON_THRESHOLD) {
|
||||
set_bit(state, S_ESC);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clean flag.
|
||||
clear_bit(state, S_CLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the actual coffee making routine.
|
||||
*/
|
||||
static void do_coffee(void) {
|
||||
// Set orange LED blink for espresso and green blink for coffee.
|
||||
if (IS_ESPRESSO(make_coffee)) {
|
||||
led = ORANGE_BLINK;
|
||||
} else {
|
||||
led = GREEN_BLINK;
|
||||
}
|
||||
|
||||
// Determine the correct pump time for espresso (including 2s preinfusion break) and coffee.
|
||||
switch (make_coffee) {
|
||||
case ONE_ESPRESSO:
|
||||
pump_time = TIME_1_ESPRESSO;
|
||||
break;
|
||||
case 2:
|
||||
pump_time = TIME_2_ESPRESSO;
|
||||
break;
|
||||
case ONE_COFFEE:
|
||||
pump_time = TIME_1_COFFEE;
|
||||
break;
|
||||
case TWO_COFFEE:
|
||||
pump_time = TIME_2_COFFEE;
|
||||
break;
|
||||
default:
|
||||
make_coffee = NO_COFFEE;
|
||||
}
|
||||
|
||||
user_time_counter = 0; // Reset user time counter.
|
||||
clear_bit(state, S_ESC); // Init escape flag.
|
||||
|
||||
// loop until pump time is reached or water is empty
|
||||
while (user_time_counter < (pump_time * 1000) && (state & S_WATER) && !(state & S_ESC)) {
|
||||
// Check for preinfusion break.
|
||||
if ((IS_COFFEE(make_coffee) || (user_time_counter < 2000 || user_time_counter > 4000)) &&
|
||||
detect_zero_crossing() <= 100) { // Detect zero crossing.
|
||||
// Generate trigger impulse for pump triac.
|
||||
clear_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
_delay_ms(3);
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
|
||||
}
|
||||
|
||||
// Update water state.
|
||||
update_water();
|
||||
|
||||
// Check for power button counter and set escape flag.
|
||||
if (button_power_counter > BUTTON_THRESHOLD) {
|
||||
set_bit(state, S_ESC);
|
||||
}
|
||||
}
|
||||
|
||||
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Pump off
|
||||
make_coffee = NO_COFFEE; // Clear coffee flag.
|
||||
sec_counter = 0; // Reset AutoOff timer.
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function for wake-up.
|
||||
*/
|
||||
|
@ -117,15 +117,6 @@
|
||||
#define S_CLEAN 2
|
||||
#define S_ESC 3
|
||||
|
||||
// Coffee mode flags.
|
||||
#define NO_COFFEE 0
|
||||
#define ONE_ESPRESSO 1
|
||||
#define TWO_ESPRESSO 2
|
||||
#define ONE_COFFEE 3
|
||||
#define TWO_COFFEE 4
|
||||
#define IS_COFFEE(VAR) (VAR > 2)
|
||||
#define IS_ESPRESSO(VAR) (VAR > 0 && VAR < 3)
|
||||
|
||||
// LED color flags.
|
||||
#define RED 0b00000001
|
||||
#define RED_BLINK 0b00000010
|
||||
@ -139,11 +130,8 @@
|
||||
#define VIOLET_BLINK 0b00100010
|
||||
|
||||
// Prototypes:
|
||||
void init(void); // Initialization.
|
||||
void power_off(void); // Power off to sleep mode.
|
||||
void init(); // Initialization.
|
||||
void power_off(); // Power off to sleep mode.
|
||||
void update_water(void); // Update water state.
|
||||
void update_temperature(void); // Update temperature state.
|
||||
unsigned int detect_zero_crossing(void); // Detect zero crossing.
|
||||
static void process_buttons(void);
|
||||
static void do_coffee(void);
|
||||
static void do_clean(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user