Watchdog sleep (or a 1 hour timer?) whilst external interrupt available...

Hello.

Currently prototyping a 433Mhz sending weather station jobby. I know there are many examples online, but as for the sake of getting my “hands dirty” I decided to try make my own…without copy pasta…

I am using an RTC (DS1307) as I thought it would be useful to time stamp stuff and keep an “accurate” clock…but I want simplicity…fewer ICs the better.

I will send the data to a Rx on another board (probably with an ATMEGA328 as well) to then decoded and passed to a RaspberryPi via Serial.

So I currently have a set up with INT0 and INT1 connected to a reed switch and the DS1307 heart beat (1s square wave 0V-Vcc)

It counts the actuations of the reed switch and seconds “well”. Once x seconds have elapsed, the number of reed switch actuations are sent via my protocol via the 433Mhz Tx.

The unit goes back to sleep between each Interrupt.

The Interrupts flip a boolean value, the main() checks boolean values and does the dirty work, sending the MCU back to sleep.

How can I have say just the watchdog timer (1% accuracy is fine for this application!) and the INT0 pin with the reed switch triggering it.
I want the watchdog to tick over till an hour has passed (3600 / 8 = 450 watchdog cycles), whilst the reed switch counts RISING (or FALLING) edges without running in to any potential “hang ups”?

Not that it is particularly useful for my problem, but my current code…but a lot will go once the DS1307 RTC is out the way:

#include <avr/sleep.h>
#include <avr/wdt.h>                  //Sleep and WDT libraries.
#include <Wire.h>
#include <DHT.h>

#define DS1307_ADDRESS 0x68            // RTC 1-wire address
#define DHTTYPE DHT22                // Define the model of DHT sensor

#define DHTPIN  4                     //Connected DNT to IDE pin 4 (IC pin 6) -> 100k PDR
#define led 8                         //debugging LED
#define rf 9                        //433Mhz module DATA pin

#define sd 600                      //Delays for Rf sending
#define ld 1800


DHT dht(DHTPIN, DHTTYPE);

volatile boolean rtc_trigger = false;  // RTC 1 second HeartBeat Interupt Flag
volatile boolean reed_trigger = false; // Reed switch Interupt flag
byte last_hour = 0;          // Stores the last hour from the RTC for comparison
float humidity, temp_f;  // Values read from DHT22 sensor
unsigned int seconds = 0; // Variable to count seconds (from RTC heartbeat).
unsigned int reed_count = 0; // Variable to count Reed Switch actuations (anemometer).
unsigned int test_count = 0; // Vairable for a test count...

void setup() {
  Wire.begin();                             //Start Wire library functions/setup
  pinMode(led, OUTPUT);                     // Make the debug LED an output
  attachInterrupt(0, reed_sw, RISING);      //Set an interrupt pin on INT0 for the reed switch
  attachInterrupt(1, rtc, RISING);        // Set an interrupt pin on INT1 for the RTC's heartbeat
  if (sqw_on()) {                         //Turn the square wave output on...flash to confirm.
    setup_flash();
  }

}

void loop() {

  if (reed_trigger) {
    reed_count++;
    reed_trigger = 0;

    set_sleep_mode (SLEEP_MODE_PWR_DOWN);
    ADCSRA = 0;
    sleep_enable();
    interrupts ();             // guarantees next instruction executed
    sleep_cpu ();              // sleep within 3 clock cycles of above

  }

  if (rtc_trigger) {
    seconds++;
    digitalWrite(led, 1);
    delay(10);
    digitalWrite(led, 0);

    if (seconds >= 60) {
      dec_flash(reed_count);
      delay(200);
      dec_flash(DHT_tempC());
      digitalWrite(rf,1);
      delay(10);
      digitalWrite(rf,0);
      delay(10);
      send_uint_CHKD(reed_count);

      delay(10);
      send_uint_CHKD(test_count);
    seconds = 0;
  }

}

rtc_trigger = 0;
reed_trigger = 0;

set_sleep_mode (SLEEP_MODE_PWR_DOWN);
//noInterrupts();
// disable ADC
ADCSRA = 0;
sleep_enable();
interrupts ();             // guarantees next instruction executed
sleep_cpu ();              // sleep within 3 clock cycles of above

}


void reed_sw() {
  reed_trigger = true;
}

void rtc() {
  rtc_trigger = true;
  test_count++;
}

byte decToBcd(byte val) {
  // Convert normal decimal numbers to binary coded decimal
  return ( (val / 10 * 16) + (val % 10) );
}

byte bcdToDec(byte val)  {
  // Convert binary coded decimal to normal decimal numbers
  return ( (val / 16 * 10) + (val % 16) );
}


boolean sqw_on() {

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0X07);
  Wire.write(B00010000);
  byte x = Wire.endTransmission();
  if (x == 0) {
    return true;
  }
}

void setup_flash() {
  for (byte x = 0; x < 10; x++) {
    digitalWrite(led, 1);
    delay(25);
    digitalWrite(led, 0);
    delay(25);

  }
}

void dec_flash(unsigned int f) {
  for (byte x = 0; x < f / 10; x++) {
    digitalWrite(led, 1);
    delay(100);
    digitalWrite(led, 0);
    delay(100);
  }

  delay(200);
  for (byte x = 0; x < f % 10; x++) {
    digitalWrite(led, 1);
    delay(50);
    digitalWrite(led, 0);
    delay(50);
  }
}

float DHT_tempC() {
  temp_f = dht.readTemperature(true);

  Serial.print("\nTemperature in F is...");
  Serial.println(temp_f);
  float temp_c = ((temp_f - 32) * 5) / 9.0;
  return temp_c;
}

void send_ulong(unsigned long x) {
  DDRB = 0
         | (1 << PB1); //Set pin PB1 as output
  unsigned long mask = 0b10000000000000000000000000000000;
  // Use the mask to shift bits out...


  while (mask) {

    if (mask & x) { // A 1 bit = A High, Low, High, Low.
      PORTB = 0 | ( 1 << PB1);
      delayMicroseconds(sd);
      PORTB = 0;
      delayMicroseconds(sd);
      PORTB = 0 | ( 1 << PB1);
      delayMicroseconds(sd);
      PORTB = 0;
      delayMicroseconds(sd);
    }
    else {            // A 0 bit = A High followed by nada.
      PORTB = 0 | ( 1 << PB1);
      delayMicroseconds(sd);
      PORTB = 0;
      delayMicroseconds(ld);
    }
    mask = mask >> 1;
  }

}

void send_uint_CHKD(unsigned long x) {

  // Takes a u_int and the !u_int appended and sends as a 32bit packet using send_ulong

  unsigned long a = x << 16;
  a += x;


  send_ulong(a);

}

My guess is I need to use the ISR_WDT thingy majig that lets main() know if it was a wdt trigger or a INT0 trigger.

How can I then get the MCU to go back to sleep like as though it wasn’t disturbed and completes the 8second WDT sleep?

Configure the watchdog timer to interrupt only mode:

    cli();
    wdt_reset();
    MCUSR &= ~_BV(WDRF);
    /* Start the WDT Config change sequence. */
    WDTCSR |= _BV(WDCE) | _BV(WDE);
    /* Configure the prescaler to 8s and the WDT for interrupt mode only*/
    WDTCSR =  _BV(WDP0) | _BV(WDP3) | _BV(WDIE);
    sei();

If configured this way the watchdog does only call the interrupt vector but does not reset. In the watchdog interrupt handler you can increase the counter and go to sleep again immediately if not a certain value is reached.
In the external interrupt handler just increase the counter and go to sleep immediately afterwards. Don't forget to activate interrupts before sleeping!