Compare commits

...

17 Commits

Author SHA1 Message Date
f3cd351646
migrate Drone CI workflow to GitHub Actions
All checks were successful
Build Firmware / Compile (push) Successful in 12s
2025-02-02 16:08:45 +01:00
e65dcb8ef2
add Drone CI configuration to build firmware
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 14:05:17 +01:00
f21e6b8fd8
extract button processing and coffee/cleaning routines into functions 2022-11-23 11:54:56 +01:00
e1fc2fbe11
define coffee flags as pre-processor macros
Right now we need at least some knowledge about the values 0-4
representing five possible states of coffee making. Make it readable
without this knowledge.
2022-11-23 11:28:54 +01:00
dc5dff81f6
minor code cleanup 2022-11-23 10:48:30 +01:00
43f65a2a66 Replaced 5 step if-else by switch-case 2022-11-23 10:47:55 +01:00
4ca0582ff3 Switched to size optimization 2022-11-23 10:47:02 +01:00
100eb00e75 Bundled boolean flags into single 8bit mask 2022-11-23 10:47:02 +01:00
b48cafe7f9 Copyright + License; reformatting 2022-11-23 10:47:02 +01:00
83d0be68bb Separated Makefile and config; added build instructions 2022-11-23 10:47:02 +01:00
cadlab-io[bot]
e284baff50 Backlink to CADLAB.io has been added. 2018-04-11 18:36:54 +00:00
ceee66421b .gitignore 2017-07-04 17:30:31 +02:00
17fbd1adc1 ReadMe, Partlist, minor restructuring 2017-07-04 17:30:27 +02:00
0b2ab61d32 Schematic and layout added 2017-07-04 12:04:38 +02:00
dd493d8fb9 Coffee wish implemented with violet led indicator 2017-07-04 12:04:38 +02:00
a3f23d489a Defined constant flags for LED colors 2017-07-04 12:04:38 +02:00
ef396e5454 Code reformatted
Constants for pump times in main.h (more readable code, easier to adjust)
2017-07-04 12:04:24 +02:00
16 changed files with 19559 additions and 538 deletions

23
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,23 @@
---
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

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*~
.idea
firmware/*.o
firmware/*.elf
firmware/*.hex
hardware/*.b#*
hardware/*.s#*

View File

@ -1,75 +0,0 @@
# SenseoControl 2.0
#
# File: Makefile
# Author: Stefan Kalscheuer
# Date: 22.04.2013
#
# Platform: ATtiny26
# Internal RC-oscillator 8 MHz, CKDIV8 Enabled
# Project specific settings
TARGET = SenseoControl-2.0
MCU = attiny26
SRC = main.c
# You probably want to change this to your own programming device
# AVR ISP mkII
#PGMDEV = avrispmkII
#PGMOPT = -P usb # Try -B 10 in case of programming errors
# Pony-STK200
#PGMDEV = pony-stk200
#PGMOPT = -E noreset
# STK500
PGMDEV = stk500v2
PGMOPT = -P /dev/ttyS0
# AVR-GCC and AVRDUDE need to be installed
CC = avr-gcc
OBJCOPY = avr-objcopy
AVRDUDE = avrdude
REMOVE = rm -f
# Some C flags
CFLAGS = -Wall -O3
help:
@echo
@echo "Availiable targets:"
@echo " help - Displays this help"
@echo
@echo " compile - Compiles source code"
@echo " info - Outputs device memory information"
@echo " program - Programs the device"
@echo " clean - Deletes temporary files"
@echo " fuses - Writes fuse settings to device (necessary only once per device)"
@echo
@echo " all - Compile, info, program, clean"
@echo
@echo "IMPORTANT: Device programming may only be possible as super user"
@echo
@echo "See Makefile for contact information."
@echo
all: compile info program clean
compile:
@$(CC) $(CFLAGS) -mmcu=$(MCU) $(SRC) -o $(TARGET).elf
@$(OBJCOPY) -O ihex -j .text -j .data $(TARGET).elf $(TARGET).hex
info:
avr-size $(TARGET).elf
program:
@$(AVRDUDE) -p $(MCU) -q -q -u -V -c $(PGMDEV) $(PGMOPT) -U flash:w:$(TARGET).hex:i
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

110
README.md Normal file
View File

@ -0,0 +1,110 @@
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.
It allows custom setting of cup size and temperature and includes simple support for a second cup size (e.g. espresso) by pushing the buttons longer (2s).
The original project was documented in [this blog post](https://www.stklblog.de/blog/senseo-control-20) (German), including photos of the prototype.
## Functionality
The OEM functionality (coffee, rinsing, auto-off) has been reimplemented (indications adapted to RGB LED) with a few features on top.
### Features
| | Input | Action |
|:-------:|:--------------------------------:|:----------------------------------------------------:|
| ⬤ ⭗ ⬤ | push both coffee buttons | rinsing cycle (pump cold water, until tank is empty) |
| ⬤ ⭗ ⭕ | push single coffee button | 1/2 cups of coffee |
| ⬤ ⭗ ⭕ | push single coffee button for 2s | 1/2 cups of espresso (shorter time, 2s pre-brewing) |
| ⭕ ⬤ ⭕ | push power button | start / shutdown at any time |
| ⭕ ⭗ ⭕ | 3 minutes idle | Auto-Off |
#### Optional Features
* **Coffee wish** - if enabled (see below), the machine will memorize your coffee wish during heat-up and automatically
start the coffee when finished, indicating through a violet LED (instead of green)
### LED Signals
| Color | Light | Flashing |
|:------:|:------------------------------------------:|:------------------------------------------------------------:|
| red | - | <span style="color:red"></span> heating up |
| green | <span style="color:green"></span> ready | <span style="color:green"></span> coffee running |
| orange | - | <span style="color:orange"></span> espresso running |
| blue | <span style="color:blue"></span> rinsing | <span style="color:blue"></span> water empty |
| violet | - | <span style="color:violet"></span> heating up (coffee wish) |
## Platform
### Hardware
The hardware is based on an **ATtiny26** microcontroller with internal 8MHz RC oscillator.
Power supply is provided by a small transforer with a _78L05_ linear regulator.
Pump and boiler are controlled by Triacs with isolated MOC30xx drivers.
The original sensors (NTC for temperature, Hall for water tank switch) are directly attached to the new board.
### Schematic and Layout
The prototype has been built in THT on a perfboard, hence the layout provided is compatible to 2.54mm (100mil) grid.
Might as well be used for a PCB. The board is designed to fit the HD7822 model.
Files provided under _hardware/_ are compatible with CadSoft/Autodesk EAGLE™ 6 and above.
### Firmware
The firmware is written in _C_ and comes with a _Makefile_ for use with _avr-gcc_ and _avrdude_.
There are configurations available for _STK500_, _AVR ISP mkII_ and _Pony-STK200_ which can be adapted to your setup.
## Customization
The code is designed to customize functions, timing, temperature and hardware pinning.
To to so, set the corresponding fields in the _main.h_ file:
| Flag | Default | Description |
|-------------------------|---------|----------------------------------------------|
| `TIME_1_ESPRESSO` | 15 | pump time 1 espresso (seconds) |
| `TIME_2_ESPRESSO` | 28 | pump time 2 espressos (seconds) |
| `TIME_1_COFFEE` | 26 | pump time 1 coffee (seconds) |
| `TIME_2_COFFEE` | 52 | pump time 2 coffees (seconds) |
| `OPERATING_TEMPERATURE` | 125 | water temperature (ADC value) |
| `AUTO_OFF_THRESHOLD` | 180 | Auto-Off time (seconds after last action) |
| `COFFEE_WISH` | 0 | save coffee wish on heat-up (`1` to enable) |
Pinout, button-thresholds and LED-configuration is also present in this file (should be self-explaining).
## Build Instructions
* Required tools: _avr-gcc_, _avr-objcopy_, _avrdude_ (for flashing only), _make_
* All sources are bundled in the `firmware` directory
* Check `Makefile.config` for the correct settings, especially tool and port for automated flashing.
* On first build you might want to set the correct fuse bits, so run `make fuses`
* Run `make compile info program` for compilation, details about binary, and flashing
* Check `make help` for all available commands
## Notes
The Triacs need heatsink.
The prototype uses approx. 75 x 30 x 1.5 mm (3 x 1.2 x 0.06 in) aluminum sheet, which is about the minimum recommended with a maximum temperature around 70°C (158°F).
<span style="background-color:lightyellow;padding:.5em;border-left:4px orange solid;display:block">**⚡ Danger - High Voltage ⚡**<br>
Working on a live coffee machine involves voltages of 120/230V AC **!** This voltage is applied to the heatsinks and causes hazard on contact.<br>
Please make sure you know what you are doing or consult an authorized professional.<br>
<br>
Cut the power before working on the device.
First tests can be done without main power (supply the µC with 5V from the programmer), Triacs can be tested with low voltage (e.g. 12V~).
On final test use an isolating transformer or at least a RCD.</span>
## License
The project is licensed under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.de.html) license.
## Disclaimer
_"SENSEO"_ is a Trademark of _Koninklijke Philips N.V._ when used for coffee makers and a Trademark of _Sara Lee/De N.V._ when used for coffee pods.
No claim is made to the exclusive right to use _Senseo_ apart from the mark as shown.

59
firmware/Makefile Normal file
View File

@ -0,0 +1,59 @@
#############################################################################
# SenseoControl 2.0 #
# 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 #
# the Free Software Foundation version 3. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
#############################################################################
# Include environment config
include Makefile.config
# Project specific settings
TARGET = SenseoControl-2.0
MCU = attiny26
SRC = main.c
# Some C flags
CFLAGS = -Wall -Wextra -Os
help:
@echo
@echo "Availiable targets:"
@echo " help Displays this help"
@echo
@echo " compile Compiles source code"
@echo " info Outputs device memory information"
@echo " program Programs the device"
@echo " clean Deletes temporary files"
@echo " fuses Writes fuse settings to device (necessary only once per device)"
@echo
@echo " all Compile, info, program, clean"
@echo
all: compile info program clean
compile:
@$(CC) $(CFLAGS) -mmcu=$(MCU) $(SRC) -o $(TARGET).elf
@$(OBJCOPY) -O ihex -j .text -j .data $(TARGET).elf $(TARGET).hex
info:
avr-size $(TARGET).elf
program:
@$(AVRDUDE) -p $(MCU) -q -q -u -V -c $(PGMDEV) $(PGMOPT) -U flash:w:$(TARGET).hex:i
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

43
firmware/Makefile.config Normal file
View File

@ -0,0 +1,43 @@
#############################################################################
# SenseoControl 2.0 #
# 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 #
# the Free Software Foundation version 3. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
#############################################################################
#
# Set toolchain.
# AVR-GCC and AVRDUDE need to be installed
#
CC = avr-gcc
OBJCOPY = avr-objcopy
AVRDUDE = avrdude
REMOVE = rm -f
#
# You probably want to change this to your own programming device.
# Some commonly used examples shown below.
#
# STK500
PGMDEV = stk500v2
PGMOPT = -P /dev/ttyS0
# AVR ISP mkII
#PGMDEV = avrispmkII
#PGMOPT = -P usb # Try -B 10 in case of programming errors
# Pony-STK200
#PGMDEV = pony-stk200
#PGMOPT = -E noreset

428
firmware/main.c Normal file
View File

@ -0,0 +1,428 @@
/*****************************************************************************
* SenseoControl 2.0 *
* Copyright (C) 2013-2022 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 *
* the Free Software Foundation version 3. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*****************************************************************************/
/**
* SenseoControl 2.0
*
* @file main.c
* @author Stefan Kalscheuer
* @date 2013-04-22
* @brief Main program
*
* Platform: ATtiny26
* Internal RC-oscillator 8 MHz, CKDIV8 Enabled
*/
#define F_CPU 1000000UL
// includes
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#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.
/**
* Main program.
*
* @return This method should never terminate.
*/
int main(void) {
init(); // Initialization.
power_off(); // Power off after init sequence.
while (1) { // Main loop.
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.
while (button_power_counter > 0); // Wait until button is released (debounce)
power_off(); // Call power off sequence
button_power_counter = BUTTON_THRESHOLD; // Debounce again after wake up
while (button_power_counter > 0);
}
process_buttons();
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();
}
} 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.
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.
}
}
}
/**
* 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_w, ZERO_CROSSING_pin); // No internal pull-up (for ADC).
clear_bit(BUTTON_1_CUP_ddr, BUTTON_1_CUP_pin); // Button pins as input.
set_bit(BUTTON_1_CUP_w, BUTTON_1_CUP_pin); // Activate internal pull-ups.
clear_bit(BUTTON_2_CUP_ddr, BUTTON_2_CUP_pin);
set_bit(BUTTON_2_CUP_w, BUTTON_2_CUP_pin);
clear_bit(BUTTON_POWER_ddr, BUTTON_POWER_pin);
set_bit(BUTTON_POWER_w, BUTTON_POWER_pin);
set_bit(LED_RED_ddr, LED_RED_pin); // LED pins as output.
clear_bit(LED_RED_w, LED_RED_pin); // Clear outputs (LEDs off).
set_bit(LED_GREEN_ddr, LED_GREEN_pin);
clear_bit(LED_GREEN_w, LED_GREEN_pin);
set_bit(LED_BLUE_ddr, LED_BLUE_pin);
clear_bit(LED_BLUE_w, LED_BLUE_pin);
clear_bit(SENSOR_MAGNET_ddr, SENSOR_MAGNET_pin); // Sensor pins as input.
clear_bit(SENSOR_MAGNET_w, SENSOR_MAGNET_pin); // No internal pull-up (for ADC).
clear_bit(SENSOR_TEMP_ddr, SENSOR_TEMP_pin);
clear_bit(SENSOR_TEMP_w, SENSOR_TEMP_pin);
set_bit(TRIAC_BOILER_ddr, TRIAC_BOILER_pin); // Triac pins as output.
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Set outputs high (triac off).
set_bit(TRIAC_PUMP_ddr, TRIAC_PUMP_pin);
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
ADCSR = (1 << ADEN) | (1 << ADPS1); // Enable ADC, prescaler division factor 4.
// TIMER1
set_bit(TCCR1B, CTC1); // Set timer 1 to CTC-Mode.
clear_bit(TCCR1B, CS11); // Prescaler 8.
set_bit(TCCR1B, CS12);
clear_bit(TCCR1B, CS11);
clear_bit(TCCR1B, CS10);
OCR1C = 124; // Period of 1 ms.
cli(); // Disable interrupts.
clear_bit(GIMSK, INT0); // Disable interrupt 0.
set_bit(TIMSK, TOIE1); // Activate timer 1.
sei(); // Enable interrupts.
}
/**
* Clear bits and set controller to sleep mode.
*/
void power_off(void) {
cli(); // Disable interrupts.
set_bit(GIMSK, INT0); // Activate interrupt 0 (for wake-up).
clear_bit(TIMSK, TOIE1); // Deactivate timer 1.
sei(); // Re-enable interrupts.
clear_bit(LED_RED_w, LED_RED_pin); // Clear LED outputs.
clear_bit(LED_GREEN_w, LED_GREEN_pin);
clear_bit(LED_BLUE_w, LED_BLUE_pin);
set_bit(MCUCR, SM1); // Activate power-down mode.
clear_bit(MCUCR, SM0);
set_bit(MCUCR, SE);
asm volatile("sleep"::);
// Entrance point after wake-up.
time_counter = 0; // Reset counter.
sec_counter = 0;
cli(); // Disable interrupts.
clear_bit(GIMSK, INT0); // Disable interrupt 0.
set_bit(TIMSK, TOIE1); // Enable timer 1.
sei(); // Re-enable interrupts.
}
/**
* Checks hall sensor for water level.
*/
void update_water(void) {
ADMUX = SENSOR_MAGNET_adc | (1 << ADLAR);
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense = ADCH;
if (((state & S_WATER) && sense > WATER_LOW) || (!(state & S_WATER) && sense >= WATER_OK)) {
set_bit(state, S_WATER);
} else {
clear_bit(state, S_WATER);
}
}
/**
* Checks NTC sensor for temperature state.
*/
void update_temperature(void) {
ADMUX = SENSOR_TEMP_adc | (1 << ADLAR);
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense = ADCH;
if (sense >= OPERATING_TEMPERATURE) {
set_bit(state, S_TEMP);
} else {
clear_bit(state, S_TEMP);
}
}
/**
* Checks for zero crossing (with fixed offset)
*
* @return Raw ADC value.
*/
unsigned int detect_zero_crossing() {
ADMUX = ZERO_CROSSING_adc;
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense_L = ADCL;
unsigned char sense_H = ADCH;
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.
*/
ISR ( INT0_vect) {
// Nothing to do here.
}
/**
* Timer interrupt. Increments counters and controls LED.
*/
ISR ( TIMER1_OVF1_vect) {
if (time_counter < 1000)
time_counter++; // Global milliseconds counter and seconds counter (for AutoOff).
else {
time_counter = 0;
sec_counter++;
}
user_time_counter++; // Universal counter (for pump time).
unsigned char leds_blink_on; // Status flag for blinking LEDs with 1Hz.
if (time_counter < 499) {
leds_blink_on = 1;
} else {
leds_blink_on = 0;
}
if (led & (1 << LED_RED_ON) || (led & (1 << LED_RED_BLINK) && leds_blink_on)) {
set_bit(LED_RED_w, LED_RED_pin);
} else {
clear_bit(LED_RED_w, LED_RED_pin);
}
if (led & (1 << LED_GREEN_ON) || (led & (1 << LED_GREEN_BLINK) && leds_blink_on)) {
set_bit(LED_GREEN_w, LED_GREEN_pin);
} else {
clear_bit(LED_GREEN_w, LED_GREEN_pin);
}
if (led & (1 << LED_BLUE_ON) || (led & (1 << LED_BLUE_BLINK) && leds_blink_on)) {
set_bit(LED_BLUE_w, LED_BLUE_pin);
} else {
clear_bit(LED_BLUE_w, LED_BLUE_pin);
}
if (bit_is_clear(BUTTON_1_CUP_r, BUTTON_1_CUP_pin)) { // Left button counter.
if (button_1_cup_counter < 65535) {
button_1_cup_counter++;
}
} else {
if (button_1_cup_counter > 0) {
button_1_cup_counter--;
}
}
if (bit_is_clear(BUTTON_2_CUP_r, BUTTON_2_CUP_pin)) { // Right button counter.
if (button_2_cup_counter < 65535) {
button_2_cup_counter++;
}
} else {
if (button_2_cup_counter > 0) {
button_2_cup_counter--;
}
}
if (bit_is_clear(BUTTON_POWER_r, BUTTON_POWER_pin)) { // Power button counter.
if (button_power_counter < 255) {
button_power_counter++;
}
} else {
if (button_power_counter > 0) {
button_power_counter--;
}
}
}

149
firmware/main.h Normal file
View File

@ -0,0 +1,149 @@
/*****************************************************************************
* SenseoControl 2.0 *
* 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 *
* the Free Software Foundation version 3. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*****************************************************************************/
/**
* SenseoControl 2.0
*
* @file main.h
* @author Stefan Kalscheuer
* @date 2013-04-22
*/
/********************
* User settings:
*/
#define TIME_1_ESPRESSO 15 // Pump times in seconds.
#define TIME_2_ESPRESSO 28
#define TIME_1_COFFEE 26
#define TIME_2_COFFEE 52
#define OPERATING_TEMPERATURE 125 // ADC threshold for water temperature.
#define COFFEE_WISH 0 // Save coffee wish while heating up.
/*
********************/
// Function macros for setting and clearing bits.
#define set_bit(var, bit) ((var) |= (1 << (bit)))
#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit)))
#define ZERO_CROSSING_w PORTA // Zero crossing detection.
#define ZERO_CROSSING_r PINA
#define ZERO_CROSSING_pin 0
#define ZERO_CROSSING_ddr DDRA
#define ZERO_CROSSING_adc 0
#define BUTTON_1_CUP_w PORTB // Left button.
#define BUTTON_1_CUP_r PINB
#define BUTTON_1_CUP_pin 4
#define BUTTON_1_CUP_ddr DDRB
#define BUTTON_2_CUP_w PORTB // Right button.
#define BUTTON_2_CUP_r PINB
#define BUTTON_2_CUP_pin 5
#define BUTTON_2_CUP_ddr DDRB
#define BUTTON_POWER_w PORTB // Power button.
#define BUTTON_POWER_r PINB
#define BUTTON_POWER_pin 6
#define BUTTON_POWER_ddr DDRB
#define LED_RED_w PORTA // Red LED.
#define LED_RED_r PINA
#define LED_RED_pin 3
#define LED_RED_ddr DDRA
#define LED_RED_ON 0
#define LED_RED_BLINK 1
#define LED_GREEN_w PORTA // Green LED.
#define LED_GREEN_r PINA
#define LED_GREEN_pin 1
#define LED_GREEN_ddr DDRA
#define LED_GREEN_ON 2
#define LED_GREEN_BLINK 3
#define LED_BLUE_w PORTA // Blue LED.
#define LED_BLUE_r PINA
#define LED_BLUE_pin 2
#define LED_BLUE_ddr DDRA
#define LED_BLUE_ON 4
#define LED_BLUE_BLINK 5
#define SENSOR_MAGNET_w PORTA // Hall switch (water).
#define SENSOR_MAGNET_r PINA
#define SENSOR_MAGNET_pin 5
#define SENSOR_MAGNET_ddr DDRA
#define SENSOR_MAGNET_adc 4
#define WATER_LOW 30 // ADC threshold for low water.
#define WATER_OK 100 // ADC threshold for water OK.
#define SENSOR_TEMP_w PORTA // NTC (temperature)
#define SENSOR_TEMP_r PINA
#define SENSOR_TEMP_pin 4
#define SENSOR_TEMP_ddr DDRA
#define SENSOR_TEMP_adc 3
#define TRIAC_BOILER_w PORTA // Boiler triac.
#define TRIAC_BOILER_r PINA
#define TRIAC_BOILER_pin 6
#define TRIAC_BOILER_ddr DDRA
#define TRIAC_PUMP_w PORTA // Pump triac.
#define TRIAC_PUMP_r PINA
#define TRIAC_PUMP_pin 7
#define TRIAC_PUMP_ddr DDRA
#define AUTO_OFF_THRESHOLD 180 // AutoOff threshold (seconds).
#define BUTTON_CLEAN_THR 30 // Button threshold for cleaning mode (ms).
#define BUTTON_THRESHOLD 100 // Button threshold (ms).
#define BUTTON_LONG_THR 1500 // Button threshold for long time push (ms).
// Global state flags.
#define S_WATER 0
#define S_TEMP 1
#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
#define GREEN 0b00000100
#define GREEN_BLINK 0b00001000
#define BLUE 0b00010000
#define BLUE_BLINK 0b00100000
#define ORANGE 0b00000101
#define ORANGE_BLINK 0b00001010
#define VIOLET 0b00010001
#define VIOLET_BLINK 0b00100010
// Prototypes:
void init(void); // Initialization.
void power_off(void); // 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);

2540
hardware/SenseoControl.brd Normal file

File diff suppressed because it is too large Load Diff

16157
hardware/SenseoControl.sch Normal file

File diff suppressed because it is too large Load Diff

BIN
hardware/layout.pdf Normal file

Binary file not shown.

43
hardware/partlist.txt Normal file
View File

@ -0,0 +1,43 @@
Partlist
Exported from SenseoControl 2.0
Part Value Device Package Library Sheet
B1 B500D B-DIL B-DIL rectifier 1
C1 470µ CPOL-EUE2.5-6 E2,5-6 resistor 1
C2 100n C-EU025-024X044 C025-024X044 resistor 1
C4 100n C-EU025-024X044 C025-024X044 resistor 1
C5 100n C-EU025-024X044 C025-024X044 resistor 1
C6 1µ CPOL-EUTT2D5 TT2D5 resistor 1
D1 1N4004 DIODE-D-2.5 D-2.5 diode 1
D2 5V1 ZENER-DIODEZD-7.5 ZDIO-7.5 diode 1
IC1 78L05 78L2 TO92-A linear 1
IC2 TINY26P TINY26P DIL20 atmel 1
LED1 LF5 LF5 LF5 led-rgb 1
OK1 MOC3031M MOC3031M DIL06 optocoupler 1
OK2 MOC3031M MOC3031M DIL06 optocoupler 1
R1 10k R-EU_0207/12 0207/12 resistor 1
R2 150 R-EU_0204/7 0204/7 resistor 1
R3 20 R-EU_0204/7 0204/7 resistor 1
R4 120 R-EU_0204/7 0204/7 resistor 1
R5 150 R-EU_0204/7 0204/7 resistor 1
R6 150 R-EU_0204/7 0204/7 resistor 1
R7 1k R-EU_0204/7 0204/7 resistor 1
R8 1k R-EU_0204/7 0204/7 resistor 1
R9 1k R-EU_0204/7 0204/7 resistor 1
R10 1k R-EU_0204/7 0204/7 resistor 1
R11 10k R-EU_0204/7 0204/7 resistor 1
R12 1k R-EU_0204/7 0204/7 resistor 1
R13 100k R-EU_0204/7 0204/7 resistor 1
R14 100k R-EU_0204/7 0204/7 resistor 1
S1 POWER 10-XXA B3F-10XX-A switch-omron 1
S2 1 CUP 10-XXA B3F-10XX-A switch-omron 1
S3 2 CUPS 10-XXA B3F-10XX-A switch-omron 1
T1 BT136 BT136 TO220AB triac 1
T2 BT136 BT136 TO220AB triac 1
TR1 230V/6V 0.35VA EE20-1 EE20-1 trafo 1
X2 MKDSN1,5/5-5,08 MKDSN1,5/5-5,08 MKDSN1,5/5-5,08 con-phoenix-508 1
X4 Hall-Switch MPT2 2POL254 con-phoenix-254 1
X5 NTC MPT2 2POL254 con-phoenix-254 1
X6 ISP PINHD-2X3 2X03 pinhead 1

BIN
hardware/schematic.pdf Normal file

Binary file not shown.

369
main.c
View File

@ -1,369 +0,0 @@
/** SenseoControl 2.0
*
* File: main.c
* Author: Stefan Kalscheuer
* Date: 22.04.2013
* Comments: Main program
* Previous project by Paul Wilhelm (2009) - http://mosfetkiller.de/?s=kaffeecontroller
*
* Platform: ATtiny26
* Internal RC-oscillator 8 MHz, CKDIV8 Enabled
*
* License: GNU GPL v3 (see License.txt)
*/
#define F_CPU 1000000UL
// includes
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
#include "main.h"
// variables
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 bool water = false, temperature = false, make_clean = false; // water-, temperature-, clean-flags
volatile unsigned char make_coffee = 0, pump_time = 0; // pump time, clean mode flag
int main(void)
{
init(); // initialization
power_off(); // power off after init sequece
while (1) // main loop
{
if (sec_counter >= AUTO_OFF_THRESHOLD) button_power_counter = BUTTON_THRESHOLD; // check for AutoOff Timer (generate OnOff-button push)
water = get_water(); // update water state
temperature = get_temperature(); // update temperature
if (button_power_counter >= BUTTON_THRESHOLD) // button "OnOff" pushed:
{
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off
make_coffee = 0; // clear coffee flag
while (button_power_counter > 0); // wait until button is releasd (debounce)
power_off(); // call power off sequence
button_power_counter = BUTTON_THRESHOLD; // debounce again after wake up
while (button_power_counter > 0);
}
if (button_1_cup_counter >= BUTTON_CLEAN_THR && button_2_cup_counter >= BUTTON_CLEAN_THR ) // both coffee buttons pushed: clean mode:
{
make_clean = true; // clean flag true
led = 0b00010000; // 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 (water && temperature) // 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
}
}
if(make_coffee != 1) make_coffee = 3; // set coffee flag to 3 (1 coffee) else
}
}
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 (water && temperature) // 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) else
}
}
if (water) // water OK:
{
if(make_clean) // if clean-flag is set:
{
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // boiler off
bool escape = false; // init escape-flag
while (water && !escape) { // pump until water is empty or escape flag is set
unsigned int sense = detect_zero_crossing(); // detect zero crossing
if (sense <= 100) {
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);
}
water = get_water(); // update water state
if (button_power_counter > BUTTON_THRESHOLD) escape = true; // check for power button counter and set escape flag
}
make_clean = false; // clear clean flag
}
else if (temperature) // temperature OK:
{
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // boiler off
led = 0b00000100; // set green LED
if (make_coffee > 0) // if coffee flag is set:
{
if(make_coffee<3) led = 0b00001010; // set orange LED blink
else led = 0b00001000; // set green LED blink
if (make_coffee == 1) pump_time = 15; // 1 cup of espresso (2s preinfusion included)
else if (make_coffee == 2) pump_time = 28; // 2 cups of espresso (2s preinfusion included)
else if (make_coffee == 3) pump_time = 26; // 1 cup of coffee
else if (make_coffee == 4) pump_time = 52; // 2 cups of coffee
else make_coffee = 0;
user_time_counter = 0; // reset user time counter
bool escape = false; // init escape flag
while (user_time_counter < (pump_time * 1000) && water && !escape) // loop until pump time is reached or water is empty
{
if(make_coffee > 2 ||
(user_time_counter < 2000 || user_time_counter > 4000) ) { // check for preinfusion break
unsigned int sense = detect_zero_crossing(); // detect zero crossing
if (sense <= 100)
{
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);
}
}
water = get_water(); // update water state
if (button_power_counter > BUTTON_THRESHOLD) escape = true; // 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
led = 0b00000010; // set red 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 = 0b00100000; // set blue LED blink
}
}
}
/* function: init()
* return: void
*
* Initializes relevant bits, timer and ADC.
*/
void init()
{
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
set_bit(BUTTON_1_CUP_w, BUTTON_1_CUP_pin); // activate internal pull-ups
clear_bit(BUTTON_2_CUP_ddr, BUTTON_2_CUP_pin);
set_bit(BUTTON_2_CUP_w, BUTTON_2_CUP_pin);
clear_bit(BUTTON_POWER_ddr, BUTTON_POWER_pin);
set_bit(BUTTON_POWER_w, BUTTON_POWER_pin);
set_bit(LED_RED_ddr, LED_RED_pin); // LED pins as output
clear_bit(LED_RED_w, LED_RED_pin); // clear outputs (LEDs off)
set_bit(LED_GREEN_ddr, LED_GREEN_pin);
clear_bit(LED_GREEN_w, LED_GREEN_pin);
set_bit(LED_BLUE_ddr, LED_BLUE_pin);
clear_bit(LED_BLUE_w, LED_BLUE_pin);
clear_bit(SENSOR_MAGNET_ddr, SENSOR_MAGNET_pin); // sensor pins as input
clear_bit(SENSOR_MAGNET_w, SENSOR_MAGNET_pin); // no internal pull-up (for ADC)
clear_bit(SENSOR_TEMP_ddr, SENSOR_TEMP_pin);
clear_bit(SENSOR_TEMP_w, SENSOR_TEMP_pin);
set_bit(TRIAC_BOILER_ddr, TRIAC_BOILER_pin); // triac pins as output
set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // set outputs high (triac off)
set_bit(TRIAC_PUMP_ddr, TRIAC_PUMP_pin);
set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin);
ADCSR = (1 << ADEN) | (1 << ADPS1); // enable ADC, prescaler division factor 4
// TIMER1
set_bit(TCCR1B, CTC1); // set timer 1 to CTC-Mode
clear_bit(TCCR1B, CS11); // prescaler 8
set_bit(TCCR1B, CS12);
clear_bit(TCCR1B, CS11);
clear_bit(TCCR1B, CS10);
OCR1C = 124; // period of 1 ms
cli(); // disable interrupts
clear_bit(GIMSK, INT0); // disable interrupt 0
set_bit(TIMSK, TOIE1); // activate timer 1
sei(); // enable interrupts
}
/* function: power_off()
* return: void
*
* Clear bits and set controller to sleep mode.
*/
void power_off()
{
cli(); // disable interrupts
set_bit(GIMSK, INT0); // activate interrupt 0 (for wake-up)
clear_bit(TIMSK, TOIE1); // deactivate timer 1
sei(); // enable interrupts
clear_bit(LED_RED_w, LED_RED_pin); // clear LED outputs
clear_bit(LED_GREEN_w, LED_GREEN_pin);
clear_bit(LED_BLUE_w, LED_BLUE_pin);
set_bit(MCUCR, SM1); // activate power-down mode
clear_bit(MCUCR, SM0);
set_bit(MCUCR, SE);
asm volatile("sleep"::);
// entrance after wake-up:
time_counter = 0; // reset counter
sec_counter = 0;
cli(); // disable interrupts
clear_bit(GIMSK, INT0); // disable interrupt 0
set_bit(TIMSK, TOIE1); // enable timer 1
sei(); // enable interrupts
}
/* function: get_water()
* return: true water OK
* false not enough water
*
* Checks hall sensor for water state.
*/
bool get_water()
{
ADMUX = SENSOR_MAGNET_adc | (1 << ADLAR); // ADLAR
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense = ADCH;
if ((water && sense > WATER_LOW) || (!water && sense >= WATER_OK)) return true;
return false;
}
/* function: get_temperature()
* return: true temperature OK
* false temperature too low
*
* Checks NTC sensor for temperature state.
*/
bool get_temperature()
{
ADMUX = SENSOR_TEMP_adc | (1 << ADLAR); // ADLAR
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense = ADCH;
if (sense >= OPERATING_TEMPERATURE) return true;
return false;
}
/* function: detect_zero_crossing()
* return: unsigned int ADC value
*
* Checks for zero crossing (with fixed offset)
*/
unsigned int detect_zero_crossing()
{
ADMUX = ZERO_CROSSING_adc;
set_bit(ADCSR, ADSC);
loop_until_bit_is_clear(ADCSR, ADSC);
unsigned char sense_L = ADCL;
unsigned char sense_H = ADCH;
return (sense_H << 8) | sense_L;
}
/* interrupt function: INT0_vect
*
* Dummy function for wake-up.
*/
ISR(INT0_vect)
{
}
/* interrupt function: TIMER1_OVF1_vect
*
* Timer interrupt. Increments counters and controls LED.
*/
// Millisekundenzähler, LED-Steuerung, Tastenzähler
ISR(TIMER1_OVF1_vect)
{
if (time_counter < 1000) time_counter++; // blobal milliseconds counter und seconds counter (für AutoOff)
else {
time_counter = 0;
sec_counter++;
}
user_time_counter++; // universal counter (for pump time)
bool leds_blink_on; // status flag for blinking LEDs with 1Hz
if (time_counter < 499) leds_blink_on = true;
else leds_blink_on = false;
if (led & ( 1 << LED_RED_ON ) || (led & ( 1 << LED_RED_BLINK ) && leds_blink_on)) set_bit(LED_RED_w, LED_RED_pin);
else clear_bit(LED_RED_w, LED_RED_pin);
if (led & ( 1 << LED_GREEN_ON ) || (led & ( 1 << LED_GREEN_BLINK ) && leds_blink_on)) set_bit(LED_GREEN_w, LED_GREEN_pin);
else clear_bit(LED_GREEN_w, LED_GREEN_pin);
if (led & ( 1 << LED_BLUE_ON ) || (led & ( 1 << LED_BLUE_BLINK ) && leds_blink_on)) set_bit(LED_BLUE_w, LED_BLUE_pin);
else clear_bit(LED_BLUE_w, LED_BLUE_pin);
if (bit_is_clear(BUTTON_1_CUP_r, BUTTON_1_CUP_pin)) { // left button counter
if (button_1_cup_counter < 65535) button_1_cup_counter++;
} else {
if (button_1_cup_counter > 0) button_1_cup_counter--;
}
if (bit_is_clear(BUTTON_2_CUP_r, BUTTON_2_CUP_pin)) { // right button counter
if (button_2_cup_counter < 65535) button_2_cup_counter++;
} else {
if (button_2_cup_counter > 0) button_2_cup_counter--;
}
if (bit_is_clear(BUTTON_POWER_r, BUTTON_POWER_pin)) { // power button counter
if (button_power_counter < 255) button_power_counter++;
} else {
if (button_power_counter > 0) button_power_counter--;
}
}

94
main.h
View File

@ -1,94 +0,0 @@
/** SenseoControl 2.0
*
* File: main.h
* Author: Stefan Kalscheuer
* Date: 22.04.2013
*
* License: GNU GPL v3 (see License.txt)
*/
// functions for setting and clearing bits
#define set_bit(var, bit) ((var) |= (1 << (bit)))
#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit)))
#define ZERO_CROSSING_w PORTA // zero crossing detection
#define ZERO_CROSSING_r PINA
#define ZERO_CROSSING_pin 0
#define ZERO_CROSSING_ddr DDRA
#define ZERO_CROSSING_adc 0
#define BUTTON_1_CUP_w PORTB // left button
#define BUTTON_1_CUP_r PINB
#define BUTTON_1_CUP_pin 4
#define BUTTON_1_CUP_ddr DDRB
#define BUTTON_2_CUP_w PORTB // right button
#define BUTTON_2_CUP_r PINB
#define BUTTON_2_CUP_pin 5
#define BUTTON_2_CUP_ddr DDRB
#define BUTTON_POWER_w PORTB // power button
#define BUTTON_POWER_r PINB
#define BUTTON_POWER_pin 6
#define BUTTON_POWER_ddr DDRB
#define LED_RED_w PORTA // red LED
#define LED_RED_r PINA
#define LED_RED_pin 3
#define LED_RED_ddr DDRA
#define LED_RED_ON 0
#define LED_RED_BLINK 1
#define LED_GREEN_w PORTA // green LED
#define LED_GREEN_r PINA
#define LED_GREEN_pin 1
#define LED_GREEN_ddr DDRA
#define LED_GREEN_ON 2
#define LED_GREEN_BLINK 3
#define LED_BLUE_w PORTA // blue LED
#define LED_BLUE_r PINA
#define LED_BLUE_pin 2
#define LED_BLUE_ddr DDRA
#define LED_BLUE_ON 4
#define LED_BLUE_BLINK 5
#define SENSOR_MAGNET_w PORTA // hall switch (water)
#define SENSOR_MAGNET_r PINA
#define SENSOR_MAGNET_pin 5
#define SENSOR_MAGNET_ddr DDRA
#define SENSOR_MAGNET_adc 4
#define WATER_LOW 30 // ADC threshold for low water
#define WATER_OK 100 // ADC threshold for water OK
#define SENSOR_TEMP_w PORTA // NTC (temperature)
#define SENSOR_TEMP_r PINA
#define SENSOR_TEMP_pin 4
#define SENSOR_TEMP_ddr DDRA
#define SENSOR_TEMP_adc 3
#define OPERATING_TEMPERATURE 115 // ADC threshold for water temperature
#define TRIAC_BOILER_w PORTA // boiler triac
#define TRIAC_BOILER_r PINA
#define TRIAC_BOILER_pin 6
#define TRIAC_BOILER_ddr DDRA
#define TRIAC_PUMP_w PORTA // pump triac
#define TRIAC_PUMP_r PINA
#define TRIAC_PUMP_pin 7
#define TRIAC_PUMP_ddr DDRA
#define AUTO_OFF_THRESHOLD 180 // AutoOff threshold (seconds)
#define BUTTON_CLEAN_THR 30 // button threshold for cleaning mode (ms)
#define BUTTON_THRESHOLD 100 // button threshold (ms)
#define BUTTON_LONG_THR 1500 // button threshold for long time push (ms)
// prototypes:
void init(); // initialization
void power_off(); // power off to sleep mode
bool get_water(); // update water state
bool get_temperature(); // update tehmerature state
unsigned int detect_zero_crossing(); // detect zero crossing