I have a 1940s Westminster clock that chimes 4 times per hour and strikes the hours, we recently moved it and now it disturbs our sleep so I decided to disable the chime and strike trains during the night using an Arduino.

After testing with an UNO r3 I built a Veroboard with an Atmega328p running on the internal clock at 8MHz. It's powered from a 2000mah 5v lithium power bank, the battery was lasting a few days so I added a regulator to drop the voltage to 3.3v this improved the battery life to about 6 days (I wind the clock every 7 days and so would prefer to change the battery at the same time)

I didn't want to add a real time clock so I'm counting the strikes using a microswitch on the star wheel of the clock, this microswitch was connected to digital pin 5. It's been running fine for several weeks but I decided to make it sleep to improve the battery life.

My programming knowledge is limited so I decided to use a library (Sleep_n0m1.h) I initially tested it on a breadboard with a momentary button instead of the microswitch. To make it wake when it strikes I connected the microswitch to an external interrupt pin digital pin 2 (int0).

Once tested I moved it to the clock and found it was not always disabling or enabling the chimes, so I did some more testing and found with or without the sleep code running it was not reading all the strikes, I tried the microswitch connected to digital pin 2 (int0) and digital pin 3 (int1) but it was the same, when I moved it back to digital pin 5 it worked consistently without any issues.

See code and a circuit diagram I have only included the code and components needed to reproduce the issue, I get the same issue using an UNO r3, it seems to be a combination of using the external interrupt pins and the microswitch on the clock star wheel but I have no clue why and hope that it makes sense to someone so they can point me in the right direction, thanks.

#include <Sleep_n0m1.h>
Sleep sleep;

// this constant won't change:
const int  switchPin = 2;
const int ledPin = 8;
const long delayforCheck = 30000;
const long delayforClear = 60000;

// Variables will change:
int strikeCounter = 0;   // counter for the number of strikes
int switchState = 0;         // current state of the switch
int lastswitchState = 0;     // previous state of the switch
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;

void setup() {
  pinMode(switchPin, INPUT);
  pinMode(ledPin, OUTPUT);
  // Serial.begin(9600);
  digitalWrite(ledPin, HIGH);
  delay(50);
  digitalWrite(ledPin, LOW);
}

void loop() {
  // read the pushswitch input pin:
  unsigned long currentMillis = millis();
  unsigned long currentMillis1 = millis();
  switchState = digitalRead(switchPin);
  // compare the switchState to its previous state
  if (switchState != lastswitchState) {
    // if the state has changed, increment the counter
    if (switchState == HIGH) {
      previousMillis = currentMillis;
      previousMillis1 = currentMillis1;
      // if the current state is HIGH then the switch went from off to on:
      strikeCounter++;
      digitalWrite(ledPin, HIGH);
      delay(50);
      digitalWrite(ledPin, LOW);
      // Serial.println(strikeCounter);
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastswitchState = switchState;
  // After 60 seconds clear strikeCounter
  if (currentMillis - previousMillis >= delayforClear) {
    strikeCounter = 0;
  }
  // After 30 seconds do something then clear strikeCounter
  if (currentMillis1 - previousMillis1 >= delayforCheck) {
    strikeCounter = 0;
  }
  previousMillis1 = currentMillis1;

  if (strikeCounter == 0) {
    // Serial.println("Sleep");
    delay(500);
    sleep.pwrDownMode(); //set sleep mode
    //Sleep till interrupt pin equals a particular state.
    //In this case "low" is state 0.
    sleep.sleepPinInterrupt(switchPin, HIGH); //(interrupt Pin Number, interrupt State)
    // Serial.println("Wake");
  }
}

image

Anything that happens here will be missed. What's the purpose of this delay?

Can you post a minimal example without the sleep code that reproduces the problem? Let's remove any complication. I'd also suggest pruning the bit with the 30 vs. 60 second periods and previousMillis(1), which in this demonstration doesn't appear to serve any function.

BTW, I would consider renaming your variables so they have more logical names. E.g. "previousStrikeMillis" would be more telling than "previousMillis", and "strikeTimeout" is more meaningful than "delayforCheck". Well, in my view at least.

I tossed your code into the wokwi simulator and built your circuit.

After considerable hacking with your code, and with an example using interrupts for the library you are using I have spent enough time to throw the library in the trash.

But with some changes to the example, I did get it to sleep and wakeup. Note: the simulator doesn't seem to do sleep. All my hacking after realizing that could be an issue was on an UNO R3.

I had to change the switch to the pulled-up configuration - switch wired between the pin and ground, no resistor. The library sets the internal pullup resistor.

I changed LOW or (was it HIGH) to FALLING in the sleepPinInterrupt() call.

I used the LED to show it when it was asleep.

# include <Sleep_n0m1.h>

Sleep sleep;

# define intPin 2
# define ledPin	8

void setup()
{
   Serial.begin(9600);
   pinMode(ledPin, OUTPUT);
}

void loop()
{
  Serial.println("\n\nexecute your code here");

  Serial.print("\nSleeping Till Interrupt");

  delay(1777); 

  sleep.pwrDownMode(); 

  digitalWrite(ledPin, HIGH);		// lamp is on during sleep, a night light
  sleep.sleepPinInterrupt(intPin, FALLING);

  digitalWrite(ledPin, LOW);		// wakey wakey
}

It can catch a bounce if you stay on the button until it falls asleep again. Releasing the button makes the pin go HIGH, but the bounce serves as the FALLING edge that wakes things up. Placing a 0.1 uF capacitor in parallel with the button should fix that. Or just make sure the button is released before the night light LED indicating sleep goes on.

If you can't get the tiny sketch above to function, it is pointless to tinker with your real code.

I said the library is in the trash. I just don't like libraries, and this one seemed to mock me as I wasted time on it, so my advice to you would be to read

and learn from the master. It is full of good stuff and simple working examples. It's a bit of a slog, but the examples are clear. Read it, ask questions, do experiments.

HTH

a7

The delay is not required, it was in the example to allow enough time for the serial output to be written before it slept on the UNO r3, I was only using serial for debugging so I have removed it.

I pulled the clock apart this morning to do more testing and follow the feed back I got from the forum but to my surprise it worked correctly without any changes other than changing the pin from 5 to 2.

On Saturday I spent hours trying to understand the problem but got nowhere, the only thing that could explain it was I put new crimps on the switch wiring before assembling the clock on Saturday evening as they had become loose due to continual disconnects/reconnects, thanks for your help sorry for wasting your time.

I came close to suggesting "maybe a bad contact somewhere" but thought better of it - go figure!

No problem, I hope this solved the problem. Also, it may be a nice trigger to rethink the coding. Improvements are certainly possible, I think. It's a nice project; not too complex, still has some challenges that are worthwhile to think about.

See previous post I solve the issue but I don't really know why it wasn't working.

Using the sleep library was just me being lazy and not having enough time. Back in 2017 I built a dummy alarm box with flashing LEDs using an ATTiny85 powered by an LIR2032 and solar panel, it's been running for the last 7 years. I read everything Nick Gammon had on power saving at the time, unfortunately I'm getting old and I don't retain knowledge too well and didn't fancy doing the research again.

Thanks for your help sorry for wasting your time.

No problem. Not a waste.

Would you please post the final sketch, or say confidently that something you already posted was exactly what worked?

I am curious, because I could not start with your code and get anything to work.

TIA

a7

My final is the same code as I posted on Sunday I didn't change anything to get it working.

I was concerned that it didn't work for you so I grabbed the code I posted on Sunday and tested it on an UNO r3 I did uncomment 3 lines so I could get serial output but that was it, see below the serial output and the code.

Thanks again for your help

I power on the Uno
It goes to sleep
I press the switch it wakes up
I press the switch 2 more times
After 30 seconds it goes back to sleep

image

#include <Sleep_n0m1.h>
Sleep sleep;

// this constant won't change:
const int  switchPin = 2;
const int ledPin = 8;
const long delayforCheck = 30000;
const long delayforClear = 60000;

// Variables will change:
int strikeCounter = 0;   // counter for the number of strikes
int switchState = 0;         // current state of the switch
int lastswitchState = 0;     // previous state of the switch
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;

void setup() {
  pinMode(switchPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  digitalWrite(ledPin, HIGH);
  delay(50);
  digitalWrite(ledPin, LOW);
}

void loop() {
  // read the pushswitch input pin:
  unsigned long currentMillis = millis();
  unsigned long currentMillis1 = millis();
  switchState = digitalRead(switchPin);
  // compare the switchState to its previous state
  if (switchState != lastswitchState) {
    // if the state has changed, increment the counter
    if (switchState == HIGH) {
      previousMillis = currentMillis;
      previousMillis1 = currentMillis1;
      // if the current state is HIGH then the switch went from off to on:
      strikeCounter++;
      digitalWrite(ledPin, HIGH);
      delay(50);
      digitalWrite(ledPin, LOW);
      Serial.println(strikeCounter);
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastswitchState = switchState;
  // After 60 seconds clear strikeCounter
  if (currentMillis - previousMillis >= delayforClear) {
    strikeCounter = 0;
  }
  // After 30 seconds do something then clear strikeCounter
  if (currentMillis1 - previousMillis1 >= delayforCheck) {
    strikeCounter = 0;
  }
  previousMillis1 = currentMillis1;

  if (strikeCounter == 0) {
    Serial.println("Sleep");
    delay(500);
    sleep.pwrDownMode(); //set sleep mode
    //Sleep till interrupt pin equals a particular state.
    //In this case "low" is state 0.
    sleep.sleepPinInterrupt(switchPin, HIGH); //(interrupt Pin Number, interrupt State)
    Serial.println("Wake");
  }
}

I was thinking, for wake from sleep, the interrupt has to go LOW and stay low until the processor wakes up and resets the interrupt flag? Is that correct?

After a skim over the datasheet, I think NOT. I was thinking of an old project with a Tiny84.

@advocas thanks. So the same only different. :wink:

Now I have some experiments I'll get to. One day. I was seeing very odd output whilst holding the button down, in one example program That looked like it would print "execute your…" I got "exexexexexe…".

A reset detector produced baffling results. Maybe my brain was still at the beach too hot.

The pin has to be HIGH, not go HIGH to wake up. Once the interrupt is taken, it doesn't matter what's on the pin until interrupts are re-enabled at the ISR exit.

If the pin is still HIGH, the interrupt is execute again. Since it is likely the ISR doesn't really do anything, it is harmless but as I dictate this it makes me wanna get to the lab and see if that can account for the behaviour I observed…

Which is either totally wrong or helps explain why RISING, FALLING and CHANGE seem to appear more often in that position than LOW or HIGH.

a7