0

I have 2 doors closet, that I want to lit when door is open.

I use 2 prox sensors to detect state, an Arduino Pro mini, and 2 led strips.

I use same code and hardware ( minus not needed doubled hardware ) also for 1 door closet, as you can see in code.

Each door have timeOut to stay on and then goes off to avoid keep it on.

Code is quite simple, using interrupts and sleep when Timeout is over/ or door gets closed.

Code is tested using a simple button and a single led ( still not using the prox sensr ).

Problem description:

1) since there are 2 door invlolved including TimeOuts, Arduino goes to sleep after TO is over ( if defined ), this works fine ( both inTimeOut should be false)

2) from time to time I get wierd results, like Arduino wakes up ( shooting a message to Serial monitor ), but does not activating the LED.

3) Trying to isolate this, I disable the second interrupt and this still happens.

4) Adding delays in go2sleep helps, but still few triggers get lost ( again interrupt fire OK but not truning on the LED )

Appreciate help

Guy

my Question is:

When go2Sleep is disabled, code run as expected- interrupts are triggering lights every time. When go2sleep is enabled, interrupts are working as execpted but not entering turnOn_relay or turnOn_relay while I know that system has awaken successfully. So I guess that somewhere my code is not defined as needed when sleep is involved.

Appreciate any thoughts.

EDIT 2 code was based TUTORIAL:A GUIDE TO PUTTING YOUR ARDUINO TO SLEEP

#include <avr/sleep.h>

#define NUM_SENSORS     1        // <----- NEED TO CHANGE BY USER
#define PWRDOWN_TIMEOUT 1000 * 5 // <----- NEED TO CHANGE BY USER
#define RelayON HIGH


const int sensorPin_1      = 2;
const int sensorPin_2      = 3;
const int relayPin_1       = 4;
const int relayPin_2       = 5;
long unsigned last_input   = 0;
bool volatile doorOpen_1   = 0;
bool volatile doorOpen_2   = 0;

const int sensorsPin[2]             = {sensorPin_1, sensorPin_2};
const int relaysPin[2]              = {relayPin_1, relayPin_2};
bool volatile sensorsState[2]       = {false, false};
bool volatile last_sensorsState[2]  = {false, false};
long unsigned onCounters[2]         = {0, 0};
long unsigned lastInputs[2]         = {0, 0};
bool inTimeOUT [2]                  = {false, false};


// ~~~~~~ Sleep~~~~~~~~~
void go2sleep(int *sensAmount) {
        Serial.print("go2sleep\n");


        sleep_enable();
        for (int i=0; i<sensAmount; i++) {
                reAttach(i);
        }
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        delay(100);
        sleep_cpu();

        // ~~~~~~~~~~~~~~~~~~~
        Serial.print("wake\n");
        // Serial.println(i);
        delay(100);
}
// ~~~~~~~~~~~~~~~~~~~~~

// ~~~ Switching Power ~~~~~~~
void turnOff_relay(int i){
        if (digitalRead(relaysPin[i]) == RelayON) {
                digitalWrite(relaysPin[i], !RelayON);
                last_sensorsState[i]=!RelayON;
                sensorsState[i] = !RelayON;  // need for TO
                onCounters[i] = 0;

                // Serial.print("Off, Sensor #");
                // Serial.println(i);
        }
}
void turnOn_relay(int i){
        if (digitalRead(relaysPin[i])==!RelayON) {
                digitalWrite(relaysPin[i], RelayON);
                last_sensorsState[i] = RelayON;
                sensorsState[i] = RelayON;  // need for TO
                onCounters[i] = millis();

                // Serial.print("On, Sensor #");
                // Serial.println(i);
        }
}
void checkSensor(int i) {
        if (sensorsState[i]!=last_sensorsState[i]) { // enter on change only
                // if (millis()-lastInputs[i]>100) { // ms of debounce
                if (sensorsState[i] == true) {
                        turnOn_relay(i);
                }
                else {
                        turnOff_relay(i);
                }
                lastInputs[i] = millis();
        }
        // }
}
void offBy_timeout(int i){
        if (PWRDOWN_TIMEOUT == 0 ) { // user not using TO
                inTimeOUT[i] = false;
        }
        if (PWRDOWN_TIMEOUT > 0) { // user setup TO ?
                if (millis()-onCounters[i]>=PWRDOWN_TIMEOUT) { //TO ended
                        turnOff_relay(i);
                        inTimeOUT[i] = false;
                }
                else { //Still in TO
                        inTimeOUT[i] = true;
                }
        }
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~

// ~~~~~~~ Interrupts ~~~~~~~~
void reAttach(int i){
        if (i==0) {
                attachInterrupt(digitalPinToInterrupt(sensorsPin[i]), sensor0_ISR, CHANGE);
        }
        if (i==1) {
                attachInterrupt(digitalPinToInterrupt(sensorsPin[i]), sensor1_ISR, CHANGE);
        }
}
void sensorActivated(int i) {
        sleep_disable();
        // Serial.print("Door, Sensor #");
        // Serial.println(i);
        sensorsState[i] = digitalRead(sensorsPin[i]);
        detachInterrupt(digitalPinToInterrupt(sensorsPin[i]));
}
void sensor0_ISR(){
        sensorActivated(0);
}
void sensor1_ISR(){
        sensorActivated(1);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~

// ~~~~ Constructors ~~~~~~~
void startSensors(int i){
        pinMode(relaysPin[i], OUTPUT);
        pinMode(sensorsPin[i], INPUT_PULLUP);
        digitalWrite(relaysPin[i], RelayON);
        last_sensorsState[i] = digitalRead(sensorsPin[i]);
}
void looperSensors(int i){
        checkSensor(i);
        offBy_timeout(i);
        reAttach(i);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~

void setup() {
        // Serial.begin(115200);
        // startSensors(1);
        startSensors(0);
}

void loop() {
        delay(1000);

        // looperSensors(1);
        looperSensors(0);
        int sum = 0;
        for (int i=0; i<NUM_SENSORS; i++) {
                sum += inTimeOUT[i];
        }
        if (sum == 0){ //inTimeOUT[0]==false && inTimeOUT[1]==false) {
                 go2sleep(NUM_SENSORS);
         }
        delay(100);


}
  • And the question is? Anyway, ISR should be as short as possible on AVR based MCUs, as it can't handle any other interrupt when it's handling another interrupt (it's not completely impossible, but it's really tricky). Just set some flag (volatile variable) and handle it inside of loop(). Also you should take a look to examples like Blink without delay. – KIIV May 6 at 5:22
  • @KIIV- Q edited, see if it help to understand what help do I seek for. As said, also when tested with single interrupt I get the same results, while my ISR routine is very short. – Guy . D May 6 at 12:41
  • It's little bit better. Anyway, you can't use Serial print inside of ISR. It works until you fill the buffer. If it's full, you've got the dead lock. Also it can't send anything in PWR_DOWN mode (in modes with USART running it'll wake up after sending each character from the buffer?). Maybe you should just use empty ISRs to wake up, but check it in the main code instead. Or use polling, but counters aren't working in PWR DOWN (except for WDT, but it has some limitations with bootloaders) – KIIV May 6 at 13:21
  • In my opionion you are going much to complicate. Using sleep() often is bad practice because it delays the whole program which is the problem you actually face. If you implement the delays with if and timestamps (refer to the "blink without delay"-example) there actually should be no need for using interrupts to handle your task – Sim Son May 6 at 15:13
  • @KIIV, & Sim - my code was on link ( edit2 in my Q ) – Guy . D May 6 at 15:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.