From 4a2f3d87c5bd8e9ffc9369dccfdb8940ee3656ea Mon Sep 17 00:00:00 2001 From: to-scho Date: Sun, 29 Mar 2020 17:05:52 +0200 Subject: [PATCH] Enhanced counter debouncing New commands CounterDebounceLow and CounterDebounceHigh to allow individual debounce times for low and high pulse widths to discard non valid falling edges. These are checked before legacy CounterDebounce checks distance between to valid falling edges. Useful to have robust counter results when using e.g. an TCRT5000 optical sensor to count electromechanical "Ferraris" electricity meters. --- tasmota/settings.h | 4 ++- tasmota/xsns_01_counter.ino | 59 ++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/tasmota/settings.h b/tasmota/settings.h index fa98a8ecf..7bbb0e5de 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -470,8 +470,10 @@ struct SYSCFG { uint8_t bri_preset_high; // F07 int8_t hum_comp; // F08 - uint8_t free_f09[179]; // F09 + uint8_t free_f09[175]; // F09 + uint16_t pulse_counter_debounce_low; // FB8 + uint16_t pulse_counter_debounce_high; // FBA uint32_t keeloq_master_msb; // FBC uint32_t keeloq_master_lsb; // FC0 uint32_t keeloq_serial; // FC4 diff --git a/tasmota/xsns_01_counter.ino b/tasmota/xsns_01_counter.ino index 095693771..663d9413a 100644 --- a/tasmota/xsns_01_counter.ino +++ b/tasmota/xsns_01_counter.ino @@ -27,16 +27,20 @@ #define D_PRFX_COUNTER "Counter" #define D_CMND_COUNTERTYPE "Type" #define D_CMND_COUNTERDEBOUNCE "Debounce" +#define D_CMND_COUNTERDEBOUNCELOW "DebounceLow" +#define D_CMND_COUNTERDEBOUNCEHIGH "DebounceHigh" const char kCounterCommands[] PROGMEM = D_PRFX_COUNTER "|" // Prefix - "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE ; + "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE "|" D_CMND_COUNTERDEBOUNCELOW "|" D_CMND_COUNTERDEBOUNCEHIGH ; void (* const CounterCommand[])(void) PROGMEM = { - &CmndCounter, &CmndCounterType, &CmndCounterDebounce }; + &CmndCounter, &CmndCounterType, &CmndCounterDebounce, &CmndCounterDebounceLow, &CmndCounterDebounceHigh }; struct COUNTER { uint32_t timer[MAX_COUNTERS]; // Last counter time in micro seconds + uint32_t timer_low_high[MAX_COUNTERS]; // Last low/high counter time in micro seconds uint8_t no_pullup = 0; // Counter input pullup flag (1 = No pullup) + uint8_t pin_state = 0; // LSB0..3 Last state of counter pin; LSB7==0 IRQ is FALLING, LSB7==1 IRQ is CHANGE bool any_counter = false; } Counter; @@ -51,7 +55,30 @@ void CounterUpdate4(void) ICACHE_RAM_ATTR; void CounterUpdate(uint8_t index) { uint32_t time = micros(); - uint32_t debounce_time = time - Counter.timer[index]; + uint32_t debounce_time; + + if (Counter.pin_state) { + // handle low and high debounce times when configured + if (digitalRead(pin[GPIO_CNTR1 +index]) == bitRead(Counter.pin_state, index)) { + // new pin state to be ignored because debounce time was not met during last IRQ + return; + } + debounce_time = time - Counter.timer_low_high[index]; + if bitRead(Counter.pin_state, index) { + // last valid pin state was high, current pin state is low + if (debounce_time <= Settings.pulse_counter_debounce_high * 1000) return; + } else { + // last valid pin state was low, current pin state is high + if (debounce_time <= Settings.pulse_counter_debounce_low * 1000) return; + } + // passed debounce check, save pin state and timing + Counter.timer_low_high[index] = time; + Counter.pin_state ^= (1< Settings.pulse_counter_debounce * 1000) { Counter.timer[index] = time; if (bitRead(Settings.pulse_counter_type, index)) { @@ -103,7 +130,13 @@ void CounterInit(void) if (pin[GPIO_CNTR1 +i] < 99) { Counter.any_counter = true; pinMode(pin[GPIO_CNTR1 +i], bitRead(Counter.no_pullup, i) ? INPUT : INPUT_PULLUP); - attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING); + if ((0 == Settings.pulse_counter_debounce_low) && (0 == Settings.pulse_counter_debounce_high)) { + Counter.pin_state = 0; + attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING); + } else { + Counter.pin_state = 0x8f; + attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], CHANGE); + } } } } @@ -213,6 +246,24 @@ void CmndCounterDebounce(void) ResponseCmndNumber(Settings.pulse_counter_debounce); } +void CmndCounterDebounceLow(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { + Settings.pulse_counter_debounce_low = XdrvMailbox.payload; + CounterInit(); + } + ResponseCmndNumber(Settings.pulse_counter_debounce_low); +} + +void CmndCounterDebounceHigh(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { + Settings.pulse_counter_debounce_high = XdrvMailbox.payload; + CounterInit(); + } + ResponseCmndNumber(Settings.pulse_counter_debounce_high); +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/