From b48cafe7f98f9df40d33a3545d30eab49e599d38 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Fri, 9 Feb 2018 19:39:26 +0100 Subject: [PATCH] Copyright + License; reformatting --- firmware/main.c | 717 +++++++++++++++++++++++------------------------- firmware/main.h | 93 ++++--- 2 files changed, 393 insertions(+), 417 deletions(-) diff --git a/firmware/main.c b/firmware/main.c index 0632e1b..67ef63a 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -1,18 +1,33 @@ -/** SenseoControl 2.0 +/***************************************************************************** + * 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 . * + *****************************************************************************/ + +/** + * 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 + * @file main.c + * @author Stefan Kalscheuer + * @date 2013-04-22 + * @brief Main program * * Platform: ATtiny26 * Internal RC-oscillator 8 MHz, CKDIV8 Enabled - * - * License: GNU GPL v3 (see License.txt) */ -#define F_CPU 1000000UL +#define F_CPU 1000000UL // includes #include @@ -21,400 +36,346 @@ #include #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 +// 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 +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 +/** + * Main program. + * + * @return This method should never terminate. + */ +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) + 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 + 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 + 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) + while (button_power_counter > + 0); // wait until button is releasd (debounce) - power_off (); // call power off sequence + 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 = 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 (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 - } + button_power_counter = BUTTON_THRESHOLD; // debounce again after wake up + while (button_power_counter > 0); } - if (make_coffee != 1) - make_coffee = 3; // set coffee flag to 3 (1 coffee) else - } - else if(COFFEE_WISH) { // Save coffee wish - make_coffee = 3; - } - } - else if (button_1_cup_counter < BUTTON_THRESHOLD - && button_2_cup_counter >= BUTTON_THRESHOLD) // right coffee button pushed: call coffee - { - sec_counter = 0; // reset AutoOff counter + if (button_1_cup_counter >= BUTTON_CLEAN_THR && button_2_cup_counter >= BUTTON_CLEAN_THR) { + // Both coffee buttons pushed: enter clean mode. + make_clean = true; // 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 (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 - } - else if(COFFEE_WISH) { // Save coffee wish - make_coffee = 4; - } - } - - 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 = GREEN; // set green LED - - if (make_coffee > 0) // if coffee flag is set: - { - if (make_coffee < 3) - led = ORANGE_BLINK; // set orange LED blink - else - led = GREEN_BLINK; // set green LED blink - - if (make_coffee == 1) - pump_time = TIME_1_ESPRESSO; // 1 cup of espresso (2s preinfusion included) - else if (make_coffee == 2) - pump_time = TIME_2_ESPRESSO; // 2 cups of espresso (2s preinfusion included) - else if (make_coffee == 3) - pump_time = TIME_1_COFFEE; // 1 cup of coffee - else if (make_coffee == 4) - pump_time = TIME_2_COFFEE; // 2 cups of coffee - else - make_coffee = 0; - - user_time_counter = 0; // reset user time counter - 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); - } + 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) otherwise. + } + } else if (COFFEE_WISH) { // Save coffee wish. + make_coffee = 3; } + } else if (button_1_cup_counter < BUTTON_THRESHOLD && button_2_cup_counter >= BUTTON_THRESHOLD) { + // Right coffee button pushed: call coffee. + sec_counter = 0; // Reset AutoOff counter. - 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 + 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) otherwise. + } + } else if (COFFEE_WISH) { // Save coffee wish + make_coffee = 4; + } } - } - else // temperature too low: - { - clear_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // boiler on - if (make_coffee > 0) // set red/blue LED blink if coffee wish is saved - led = VIOLET_BLINK; - else // set red LED blink if no coffee wish is saved - led = RED_BLINK; - } - } - else // water too low: - { - set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // boiler off - set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // pump off - led = BLUE_BLINK; // set blue LED blink - } + 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 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 = GREEN; // Set green LED. + + if (make_coffee > 0) { // If coffee flag is set: + if (make_coffee < 3) { + led = ORANGE_BLINK; // Set orange LED blink for espresso. + } else { + led = GREEN_BLINK; // Set green LED blink for coffee. + } + + if (make_coffee == 1) { + pump_time = TIME_1_ESPRESSO; // 1 cup of espresso (2s preinfusion included). + } else if (make_coffee == 2) { + pump_time = TIME_2_ESPRESSO; // 2 cups of espresso (2s preinfusion included). + } else if (make_coffee == 3) { + pump_time = TIME_1_COFFEE; // 1 cup of coffee. + } else if (make_coffee == 4) { + pump_time = TIME_2_COFFEE; // 2 cups of coffee. + } else { + make_coffee = 0; + } + + user_time_counter = 0; // Reset user time counter. + bool escape = false; // Init escape flag. + + // loop until pump time is reached or water is empty + while (user_time_counter < (pump_time * 1000) && water && !escape) { + // Check for preinfusion break. + if (make_coffee > 2 || (user_time_counter < 2000 || user_time_counter > 4000)) { + 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. + if (make_coffee > 0) { // Set red/blue LED blink if coffee wish is saved. + led = VIOLET_BLINK; + } else { // Set red LED blink if no coffee wish is saved. + led = RED_BLINK; + } + } + } else { // Water too low: + set_bit(TRIAC_BOILER_w, TRIAC_BOILER_pin); // Boiler off. + set_bit(TRIAC_PUMP_w, TRIAC_PUMP_pin); // Pump off. + led = BLUE_BLINK; // Set blue LED blink. + } + } } -/* 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) +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); + 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. - */ -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) - - 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 + 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); - if (led & (1 << LED_BLUE_ON) - || (led & (1 << LED_BLUE_BLINK) && leds_blink_on)) - set_bit(LED_BLUE_w, LED_BLUE_pin); - else + set_bit(LED_BLUE_ddr, LED_BLUE_pin); 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--; - } + 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); - 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--; - } + 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); - 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--; - } + 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() { + 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. + * + * @return @c true if water level is OK, @c false otherwise. + */ +bool get_water() { + ADMUX = SENSOR_MAGNET_adc | (1 << 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; +} + +/** + * Checks NTC sensor for temperature state. + * + * @return @c true if temperature is OK, @c false if it is too low + */ +bool get_temperature() { + 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) + return true; + return false; +} + +/** + * 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; +} + +/** + * 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). + + 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--; + } } diff --git a/firmware/main.h b/firmware/main.h index 0535ec3..547f115 100644 --- a/firmware/main.h +++ b/firmware/main.h @@ -1,79 +1,94 @@ -/** SenseoControl 2.0 +/***************************************************************************** + * 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 . * + *****************************************************************************/ + +/** + * SenseoControl 2.0 * - * File: main.h - * Author: Stefan Kalscheuer - * Date: 22.04.2013 - * - * License: GNU GPL v3 (see License.txt) + * @file main.h + * @author Stefan Kalscheuer + * @date 2013-04-22 */ -/******************* - * USER SETTINGS +/******************** + * User settings: */ -#define TIME_1_ESPRESSO 15 // pump times in seconds +#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 +#define OPERATING_TEMPERATURE 125 // ADC threshold for water temperature. +#define COFFEE_WISH 0 // Save coffee wish while heating up. /* - ******************* - */ + ********************/ -// functions for setting and clearing bits -#define set_bit(var, bit) ((var) |= (1 << (bit))) -#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit))) +// 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_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_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_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_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_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_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_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_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 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 @@ -81,20 +96,20 @@ #define SENSOR_TEMP_ddr DDRA #define SENSOR_TEMP_adc 3 -#define TRIAC_BOILER_w PORTA // boiler triac +#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_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) +#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). #define RED 0b00000001 #define RED_BLINK 0b00000010 @@ -107,9 +122,9 @@ #define VIOLET 0b00010001 #define VIOLET_BLINK 0b00100010 - // 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 +// 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.