Compare commits
17 Commits
ft-learnin
...
main
Author | SHA1 | Date | |
---|---|---|---|
f3cd351646 | |||
e65dcb8ef2 | |||
f21e6b8fd8 | |||
e1fc2fbe11 | |||
dc5dff81f6 | |||
43f65a2a66 | |||
4ca0582ff3 | |||
100eb00e75 | |||
b48cafe7f9 | |||
83d0be68bb | |||
|
e284baff50 | ||
ceee66421b | |||
17fbd1adc1 | |||
0b2ab61d32 | |||
dd493d8fb9 | |||
a3f23d489a | |||
ef396e5454 |
23
.github/workflows/build.yml
vendored
Normal file
23
.github/workflows/build.yml
vendored
Normal 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
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
*~
|
||||||
|
.idea
|
||||||
|
firmware/*.o
|
||||||
|
firmware/*.elf
|
||||||
|
firmware/*.hex
|
||||||
|
hardware/*.b#*
|
||||||
|
hardware/*.s#*
|
75
Makefile
75
Makefile
@ -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
110
README.md
Normal 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
59
firmware/Makefile
Normal 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
43
firmware/Makefile.config
Normal 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
428
firmware/main.c
Normal 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
149
firmware/main.h
Normal 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
2540
hardware/SenseoControl.brd
Normal file
File diff suppressed because it is too large
Load Diff
16157
hardware/SenseoControl.sch
Normal file
16157
hardware/SenseoControl.sch
Normal file
File diff suppressed because it is too large
Load Diff
BIN
hardware/layout.pdf
Normal file
BIN
hardware/layout.pdf
Normal file
Binary file not shown.
43
hardware/partlist.txt
Normal file
43
hardware/partlist.txt
Normal 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
BIN
hardware/schematic.pdf
Normal file
Binary file not shown.
369
main.c
369
main.c
@ -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
94
main.h
@ -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
|
|
Loading…
x
Reference in New Issue
Block a user