From 4193ec1618230f7bbc927e1d2280976a9d5dd464 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 3 Nov 2019 19:13:00 +0100 Subject: Add relay toggle code --- sw/Makefile | 1 + sw/common.hpp | 12 +++++++ sw/ltc2400.h | 2 +- sw/main.cpp | 46 +++++++++++++++++++++----- sw/pins.h | 99 ------------------------------------------------------- sw/pins.hpp | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ sw/relays.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sw/relays.hpp | 7 ++++ 8 files changed, 256 insertions(+), 108 deletions(-) delete mode 100644 sw/pins.h create mode 100644 sw/pins.hpp diff --git a/sw/Makefile b/sw/Makefile index bd9f6ff..0b76729 100644 --- a/sw/Makefile +++ b/sw/Makefile @@ -23,6 +23,7 @@ BUILD_DIR=build APP_NAME = sw HEADERS = \ + pins.hpp \ common.hpp \ relays.hpp \ lib/Arduino.h \ diff --git a/sw/common.hpp b/sw/common.hpp index 345f34b..fa0ee8e 100644 --- a/sw/common.hpp +++ b/sw/common.hpp @@ -26,6 +26,7 @@ #include #include +#include struct timer_t { uint32_t seconds_ = 0; /* Timer in seconds */ @@ -58,6 +59,11 @@ struct timer_t { (seconds_ == rhs.seconds_ and ticks_ > rhs.ticks_); } + bool operator<(const timer_t& rhs) const { + return (seconds_ < rhs.seconds_) or + (seconds_ == rhs.seconds_ and ticks_ < rhs.ticks_); + } + void normalise() { while (ticks_ >= 10) { seconds_++; @@ -91,3 +97,9 @@ struct timer_t { static constexpr int ms_to_ticks(int ms) { return ms / 100; } }; + +enum class relay_id_t { + K1, + K2, + K3, +}; diff --git a/sw/ltc2400.h b/sw/ltc2400.h index 9a046b2..ac99521 100644 --- a/sw/ltc2400.h +++ b/sw/ltc2400.h @@ -27,7 +27,7 @@ #include #include -#include "pins.h" +#include "pins.hpp" void ltc2400_init(); diff --git a/sw/main.cpp b/sw/main.cpp index f62fa27..fc61986 100644 --- a/sw/main.cpp +++ b/sw/main.cpp @@ -35,7 +35,8 @@ #include #include "common.hpp" -#include "pins.h" +#include "pins.hpp" +#include "relays.hpp" #include "ltc2400.h" extern "C" { @@ -55,8 +56,19 @@ constexpr double R_SHUNT = 5e-3; // Ohm constexpr double THRESHOLD_K1 = 1200.0 * 3600; constexpr double THRESHOLD_K2 = 1000.0 * 3600; constexpr double THRESHOLD_K3 = 600.0 * 3600; +constexpr double THRESHOLD_HYSTERESIS = 10.0 * 3600; + +constexpr double THRESHOLD_K1_UP = 1200.0 * 3600 - THRESHOLD_HYSTERESIS; +constexpr double THRESHOLD_K2_UP = 1000.0 * 3600 - THRESHOLD_HYSTERESIS; +constexpr double THRESHOLD_K3_UP = 600.0 * 3600 - THRESHOLD_HYSTERESIS; + +constexpr double THRESHOLD_K1_DOWN = 1200.0 * 3600 + THRESHOLD_HYSTERESIS; +constexpr double THRESHOLD_K2_DOWN = 1000.0 * 3600 + THRESHOLD_HYSTERESIS; +constexpr double THRESHOLD_K3_DOWN = 600.0 * 3600 + THRESHOLD_HYSTERESIS; + constexpr double MAX_CAPACITY = 1500.0 * 3600; -uint32_t current_capacity; +static uint32_t current_capacity; +static uint32_t previous_capacity; /* Storage of battery capacity in mC. * 3600 mC = 1mAh */ @@ -65,8 +77,9 @@ uint32_t current_capacity; uint32_t EEMEM stored_capacity1; uint32_t EEMEM stored_capacity2; uint32_t EEMEM stored_capacity3; -uint32_t last_store_time; /* In seconds */ +uint32_t last_store_time_seconds; +uint32_t last_threshold_calculation_seconds; timer_t last_ltc2400_measure; timer_t last_ltc2400_print_time; @@ -124,6 +137,8 @@ static void load_capacity_from_eeprom() current_capacity = cap2; // arbitrary #warning "Have a meaningful value for the very first startup value" } + + previous_capacity = current_capacity; } static void store_capacity_to_eeprom() @@ -139,6 +154,11 @@ static void store_capacity_to_eeprom() } } +static void handle_thresholds() +{ +#warning "compare previous_capacity and current_capacity to thresholds and toggle relays accordingly" +} + static char timestamp_buf[16]; static void send_message(const char *message) { @@ -201,6 +221,8 @@ int main() pins_set_status(true); + relays_init(); + // Initialise SPI and LTC2400 ltc2400_init(); @@ -247,8 +269,10 @@ int main() /* Load capacity stored in EEPROM */ current_capacity = 0; load_capacity_from_eeprom(); - last_ltc2400_print_time = last_ltc2400_measure = system_timer; - last_store_time = system_timer.get_seconds_atomic(); + last_ltc2400_print_time = + last_ltc2400_measure = system_timer; + last_store_time_seconds = + last_threshold_calculation_seconds = system_timer.get_seconds_atomic(); /* Enable interrupts */ sei(); @@ -265,7 +289,7 @@ int main() pins_set_status(time_now.get_ticks_atomic() == 0); - if (last_store_time + 3600 * 5 >= time_now.seconds_) { + if (last_store_time_seconds + 3600 * 5 >= time_now.seconds_) { store_capacity_to_eeprom(); } @@ -294,16 +318,22 @@ int main() if (accum > MAX_CAPACITY) { accum = MAX_CAPACITY; } current_capacity = lrint(accum); - -#warning "Handle thresholds for relays" } } + constexpr auto threshold_calculation_interval = 4; + if (last_threshold_calculation_seconds + threshold_calculation_interval > time_now.seconds_) { + last_threshold_calculation_seconds += threshold_calculation_interval; + handle_thresholds(); + } + const auto ltc2400_print_interval = timer_t(10, 0); if (last_ltc2400_print_time + ltc2400_print_interval > time_now) { last_ltc2400_print_time += ltc2400_print_interval; send_capacity(current_capacity); } + +#warning "Add call to relays_handle" } return 0; diff --git a/sw/pins.h b/sw/pins.h deleted file mode 100644 index b22b2c9..0000000 --- a/sw/pins.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Matthias P. Braendli - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ - -#pragma once - -#include -#include -#include -#include - -// Definitions allocation pin - -/* All relay signals PINx_Kx have external pulldown. - * All pins whose name ends in 'n' are active low */ - -// For arduino pin numbers (not used in this file), see -// lib/pins_arduino.h - -// PORT B -constexpr uint8_t PINB_STATUSn = _BV(0); -// Pins 2,3,4,5 = SPI -constexpr uint8_t PINB_SPI_LTC_CSn = _BV(2); // with external pullup -constexpr uint8_t PINB_SPI_MOSI = _BV(3); -constexpr uint8_t PINB_SPI_MISO = _BV(4); -constexpr uint8_t PINB_SPI_SCK = _BV(5); - -constexpr uint8_t PINB_OUTPUTS = - PINB_STATUSn | PINB_SPI_SCK | PINB_SPI_MOSI | PINB_SPI_LTC_CSn; - -constexpr uint8_t PINB_INIT = - PINB_STATUSn | PINB_SPI_LTC_CSn; - -// PORT C -constexpr uint8_t PINC_ADC0 = _BV(0); -constexpr uint8_t PINC_ADC1 = _BV(1); -constexpr uint8_t PINC_K3_RESET = _BV(2); -constexpr uint8_t PINC_K3_SET = _BV(3); -constexpr uint8_t PINC_K2_RESET = _BV(4); -constexpr uint8_t PINC_K2_SET = _BV(5); - -constexpr uint8_t PINC_OUTPUTS = - PINC_K3_RESET | PINC_K3_SET | - PINC_K2_RESET | PINC_K2_SET; - -constexpr uint8_t PINC_INIT = 0; - -// PORT D -// Pins 0,1 = UART RX,TX -constexpr uint8_t PIND_UART_RX = _BV(0); -constexpr uint8_t PIND_UART_TX = _BV(1); - -constexpr uint8_t PIND_ONEWIRE = _BV(4); // with exteral pullup - -constexpr uint8_t PIND_K1_RESET = _BV(5); -constexpr uint8_t PIND_K1_SET = _BV(6); - -constexpr uint8_t PIND_OUTPUTS = - PIND_UART_TX | - PIND_K1_RESET | PIND_K1_SET; - -constexpr uint8_t PIND_INIT = 0; - -inline void pins_set_status(bool enable) -{ - if (enable) { - PORTB &= ~PINB_STATUSn; - } - else { - PORTB |= PINB_STATUSn; - } -} - -enum class relay_id_t { - K1, - K2, - K3, -}; - diff --git a/sw/pins.hpp b/sw/pins.hpp new file mode 100644 index 0000000..7654819 --- /dev/null +++ b/sw/pins.hpp @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include + +// Definitions allocation pin + +/* All relay signals PINx_Kx have external pulldown. + * All pins whose name ends in 'n' are active low */ + +// For arduino pin numbers (not used in this file), see +// lib/pins_arduino.h + +// PORT B +constexpr uint8_t PINB_STATUSn = _BV(0); +// Pins 2,3,4,5 = SPI +constexpr uint8_t PINB_SPI_LTC_CSn = _BV(2); // with external pullup +constexpr uint8_t PINB_SPI_MOSI = _BV(3); +constexpr uint8_t PINB_SPI_MISO = _BV(4); +constexpr uint8_t PINB_SPI_SCK = _BV(5); + +constexpr uint8_t PINB_OUTPUTS = + PINB_STATUSn | PINB_SPI_SCK | PINB_SPI_MOSI | PINB_SPI_LTC_CSn; + +constexpr uint8_t PINB_INIT = + PINB_STATUSn | PINB_SPI_LTC_CSn; + +// PORT C +constexpr uint8_t PINC_ADC0 = _BV(0); +constexpr uint8_t PINC_ADC1 = _BV(1); +constexpr uint8_t PINC_K3_RESET = _BV(2); +constexpr uint8_t PINC_K3_SET = _BV(3); +constexpr uint8_t PINC_K2_RESET = _BV(4); +constexpr uint8_t PINC_K2_SET = _BV(5); + +constexpr uint8_t PINC_OUTPUTS = + PINC_K3_RESET | PINC_K3_SET | + PINC_K2_RESET | PINC_K2_SET; + +constexpr uint8_t PINC_INIT = 0; + +// PORT D +// Pins 0,1 = UART RX,TX +constexpr uint8_t PIND_UART_RX = _BV(0); +constexpr uint8_t PIND_UART_TX = _BV(1); + +constexpr uint8_t PIND_ONEWIRE = _BV(4); // with exteral pullup + +constexpr uint8_t PIND_K1_RESET = _BV(5); +constexpr uint8_t PIND_K1_SET = _BV(6); + +constexpr uint8_t PIND_OUTPUTS = + PIND_UART_TX | + PIND_K1_RESET | PIND_K1_SET; + +constexpr uint8_t PIND_INIT = 0; + +inline void pins_set_status(bool enable) +{ + if (enable) { + PORTB &= ~PINB_STATUSn; + } + else { + PORTB |= PINB_STATUSn; + } +} + diff --git a/sw/relays.cpp b/sw/relays.cpp index 6604323..cb83626 100644 --- a/sw/relays.cpp +++ b/sw/relays.cpp @@ -23,5 +23,109 @@ */ #include "relays.hpp" +#include "pins.hpp" #include #include + +struct pending_event_t { + timer_t when; + relay_id_t relay; + bool set_not_reset; + bool level; + bool pending; +}; + +static constexpr int RELAY_SIGNAL_HOLD_TIME_MS = 400; + +static constexpr size_t PENDING_EVENTS_SIZE = 8; + +static pending_event_t pending_events[PENDING_EVENTS_SIZE]; + +void relays_init() +{ + for (size_t i = 0; i < PENDING_EVENTS_SIZE; i++) { + pending_events[i].pending = false; + } +} + +static void handle_event(pending_event_t& event) +{ + switch (event.relay) { + case relay_id_t::K1: + if (event.level) { + PORTD |= (event.set_not_reset ? PIND_K1_SET : PIND_K1_RESET); + } + else { + PORTD &= (event.set_not_reset ? ~PIND_K1_SET : ~PIND_K1_RESET); + } + break; + case relay_id_t::K2: + if (event.level) { + PORTC |= (event.set_not_reset ? PINC_K2_SET : PINC_K2_RESET); + } + else { + PORTC &= (event.set_not_reset ? ~PINC_K2_SET : ~PINC_K2_RESET); + } + break; + case relay_id_t::K3: + if (event.level) { + PORTC |= (event.set_not_reset ? PINC_K3_SET : PINC_K3_RESET); + } + else { + PORTC &= (event.set_not_reset ? ~PINC_K3_SET : ~PINC_K3_RESET); + } + break; + } + + event.pending = false; +} + +void relays_handle(const timer_t& time_now) +{ + for (size_t i = 0; i < PENDING_EVENTS_SIZE; i++) { + if (pending_events[i].pending and pending_events[i].when < time_now) { + handle_event(pending_events[i]); + } + } +} + +bool relays_toggle(relay_id_t relay, bool set_not_reset, const timer_t& when) +{ + size_t num_free_events = 0; + + for (size_t i = 0; i < PENDING_EVENTS_SIZE; i++) { + if (not pending_events[i].pending) { + num_free_events++; + } + } + + if (num_free_events < 2) { + return false; + } + + for (size_t i = 0; i < PENDING_EVENTS_SIZE; i++) { + if (not pending_events[i].pending) { + pending_events[i].pending = true; + pending_events[i].relay = relay; + pending_events[i].when = when; + pending_events[i].level = true; + pending_events[i].set_not_reset = set_not_reset; + break; + } + } + + for (size_t i = 0; i < PENDING_EVENTS_SIZE; i++) { + if (not pending_events[i].pending) { + pending_events[i].pending = true; + pending_events[i].relay = relay; + pending_events[i].when = when + + timer_t{0, timer_t::ms_to_ticks(RELAY_SIGNAL_HOLD_TIME_MS)}; + + pending_events[i].level = false; + pending_events[i].set_not_reset = set_not_reset; + break; + } + } + return true; +} + diff --git a/sw/relays.hpp b/sw/relays.hpp index f6fc18b..8dd180e 100644 --- a/sw/relays.hpp +++ b/sw/relays.hpp @@ -26,4 +26,11 @@ #include #include +#include "common.hpp" + +void relays_init(); + +void relays_handle(const timer_t& time_now); + +bool relays_toggle(relay_id_t relay, bool set_not_reset, const timer_t& when); -- cgit v1.2.3