Debouncing works... most of the time :-(

Dear enthusiasts,

Currently I’m interfacing a Tipping Bucket Rain Gauge (TBRG) to an Arduino Uno.

The TBRG, when it tips, swings a magnet in front of a reed switch which then momentarily closes and pulls the line LOW.
I am using a traditional de-bouncing circuit that is attached to a 74HC14 (Inverted Schmitt Trigger). The output of the 74HC14, which is inverted, is connected to pin 2 of the UNO. This pin is monitored by an interrupt which starts the TBRG function. Every tip detected is then added to the counter which is then transmitted to home base via an nRF24L01.

The de-bouncing circuit has a capacitor of 10 uF and a resistor of 1 kiloOhm. This should give me a R/C time delay of 10 milliseconds. The interrupt also creates a 100 milliseconds delay. The TBRG tips at a maximum rate of 1 Hz, so, plenty of time between tips.
So basically I’ve got a hardware de-bounce circuit and a software de-bounce routine.

The problem:
This system runs like a dream. However, now and then and without any changes, the output of the Schmitt Trigger stays HIGH all the time! I have tried removing the capacitor, as I thought it stayed saturated when switching too fast, but to no avail.

I have attached my schematic of the circuit to this posting.

Here is my code:

/* nRF24L01 Transmitter code, 20-03-2018
Set up nRF24L01 radio on SPI bus (pins 10, 11, 12, 13) plus pins 7 & 8
Connections for UNO: GND= GND, VCC= +3.3V, CE= pin7, CSN= pin8, MOSI= pin11, MISO= pin12, SCK= pin13, IRQ= not used
Connections for MEGA2560: GND= GND, VCC= +3.3V, CE= pin7, CSN= pin8, MISO= pin50, MOSI= pin51, SCK= pin52, IRQ= not used
Date and time functions using DS3231 RTC connected via I2C and Wire lib
To set time see other sketch "DS3231_Adjust_date_and_time" in same folder*/
#include <SPI.h>            //For nRF24L01
#include <RF24.h>           //For nRF24L01
#include <Wire.h>           //For RTC
#include <Sodaq_DS3231.h>   //For RTC
//LOOP time delay variables
  unsigned int PreviousMillis = 0;
  const int Interval = 1000; //Create delay of 1 second for main program to run
//TBRG variables
  const int TbrgPin = 2;    //TBRG connected to pin 2
  byte TbrgTip;
  volatile int AccVal = 0;  //Accumulated tips as measured by TBRG
//DS3132 variables
  char TimeBuffer[20] = "";
  byte LastDay;
//LDR variables
  int LDRvalue;
//nRF24L01 variables
  RF24 radio(9, 10); // CE, CSN
  byte addresses[][6] = {"0"}; //Identify the transmitting and receiving bit

/*TBRG INTERRUPT ROUTINE*/
void isr () {
  static unsigned int LastInterruptTime = 0;
  unsigned int InterruptTime = millis();
  if (InterruptTime - LastInterruptTime > 100) {
    if (digitalRead(TbrgPin) == HIGH){
      AccVal++ ;}
    LastInterruptTime = InterruptTime;}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void setup() {
  Serial.begin(9600);
   pinMode(TbrgPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(TbrgPin), isr, HIGH);
  Serial.println("THIS IS THE TRANSMITTER CODE");
  rtc.begin(); // Start the RTC library code  
  radio.begin();  // Initiate the radio object
  radio.setChannel(124);  // 0 to 124, frequencies between 2.4 and 2.5 Ghz in chunks of 100 MHz. Use a channel unlikely to be used by Wifi, Microwave ovens etc 
  radio.setPALevel(RF24_PA_MIN);  // Set the transmit power to lowest available to prevent power supply related issues, can also be set to MAX  
  radio.setDataRate(RF24_2MBPS);  // Set the speed of the transmission to the quickest available, can be set to 250KB or 1MBPS to increase range  
  radio.openWritingPipe(addresses[0]);  // Open a writing and reading pipe on each radio, with opposite addresses
  radio.openReadingPipe(1, addresses[0]); 
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void loop() {
  unsigned int CurrentMillis = millis();
  if(CurrentMillis - PreviousMillis >= Interval) { 
  Clock();
  LDR();
  TBRG();
  Radio();  // TX data
  SerMon(); //Display on serial monitor
  PreviousMillis = CurrentMillis;}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void LDR() {
    LDRvalue = analogRead(A0);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Radio() {
  radio.write(&LDRvalue, 4); // Second parameter specifies amount of bytes, float = 4 bytes
  radio.write(&TimeBuffer, 20);
  radio.write(&TbrgTip, 2);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void SerMon() {
   Serial.print("TX at "); Serial.print(TimeBuffer); Serial.print(" the LDR value = "); Serial.println(LDRvalue);
   Serial.print("TBRG accumulated value for current day= "); Serial.println(TbrgTip);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Clock() {
  DateTime now = rtc.now(); //Read the current date-time from the RTC
  sprintf(TimeBuffer, "%04d-%02d-%02d %02d:%02d:%02d", now.year(), now.month(), now.date(), now.hour(), now.minute(), now.second());

  if (now.date() != LastDay){ // If read date is not equal to current date than write total value to EEPROM and reset the TBRG tips to 0
    //Add code here to write to EEPROM
    AccVal = 0;} // Reset AccVal to zero at midnight
  LastDay = now.date();
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 void TBRG() {
if (AccVal != TbrgTip) {
    Serial.println("xxxxxxxxxxxxx");
    Serial.print("TBRG tips = "); Serial.println(AccVal);
    Serial.println("xxxxxxxxxxxxx");
    TbrgTip = AccVal;}
    //Write tip event to EEPROM including timestamp
}
 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Any ideas what could be causing this problem? As it is for a TBRG feeding into a weather station I want it to be reliable.
Many thanks in advance.
Cheers,

Luc

Shorting a 10uF cap with your switch may not be the root of your problem...

...but it probably isn't the best practice.

Try this:

From this page.

Hi Dave,

Well spotted!. However, to build my case for this forum I hastily drew up the schematic and unfortunately I put the capacitor in the wrong spot.
In my real life application I have the capacitor of 10 uF between the 10k resistor and input pin 1 of the Schmitt Trigger.
My apologies for that.
Nevertheless this could be useful information for others as it shows how critical it is to put the components in the correct place.
Thanks for the link about the de-bouncing. In return I've bumped up your karma.
Cheers,

Luc

I spotted a problem in your code

  static unsigned int LastInterruptTime = 0;
  unsigned int InterruptTime = millis();

should be

  static unsigned long LastInterruptTime = 0;
  unsigned long InterruptTime = millis();

as millis() returns an unsigned long.

The following scenario could happen.
An unsigned int rolls over after ~65 seconds, (restarts at 0)

So there is a chance that in the next ISR call, the if condition

    if (InterruptTime - LastInterruptTime > 100)

is not true while more than a minute has passed.

Chance is approx 100/65535 = 1/655.
And although this looks small, there are 1440 minutes in a day,
==> this will happen on average 2-3 times per day.

R1 is the timing capacitor, not R2. Make R1 1k, R2 100 ohms.

Hi Rob,

Thanks for the coding tips. I thought I was going to reduce the size of the program by using "int" instead of "long" (And it did by about 100 kB). I thought, because there's so much time between tips (Tip frequency maximum 1 Hz), there was no need for these big numbers and extra memory allocations.
Anyway, in the scheme of things it doesn't make much difference and I will revert back to "long".
Many thanks for the explanation as well as it all makes sense.
Cheers,

Luc

Thanks MarkT!
I will change the values of the resistors as per your suggestions. I will do that tonight (after I'm back from work).
Great feedback, thanks!
Cheers,

Luc