Confusing behavior with setting pinMode in a loop

Objective - 4 PIR sensors which trigger different things. I have an Uno 3 with a 4 relay shield.
I got a single sensor to sense and activate a specific relay fairly easily with all the examples online. Instead of writing that code 4x I thought I'd put everything in arrays and use loops to set stuff, sense each sensor etc. The code is below.

No matter what I did, the first input pin set by pinMode in the loop would never sense!
I could switch sensors and it followed the pin. I could switch order of pin assigned (ie. instead of 3,6,9, 11 set 6,3,9,11) and it's always the first pin set which was not functional.
I could manually set the pin in an additional statement after the loop and it would work.

The pinMode for output pins was not a problem. I was setting both input and output pins with pinMode in the same loop. I switched the order - input pins first and no joy.
However, I found if I set the input pins with pinMode in it's own loop - it worked!?

I am not a programmer though an engineer who has hacked some C code to make something work - so don't know if doing something that's not best practice here.

I am using the common HC-SR501 PIR which everyone uses. 5V from the shield pin to sensor, grnd, input line.

Here's where it gets more confusing, and I would start to question the guy posting - I would...
At one point I got tired of waving at the sensors and just put 5V directly to the pin which was not working with the sensor- it worked! ?!

I was assuming there was something in the compiler / my sketch wasn't best practice which didn't like the way I was using pinMode (I'm using the standalone IDE 2.1.1).

I could also believe that the level from the sensor was not as good/noisy or something as a direct 5V to the pin.

It makes no sense how what I'm doing could cause the first pin not to work with sensor in the combined loop, work with the sensor if in it's own loop - but work when directly putting 5V to that pin in both cases.

I'm hoping I've just done something stupid, some mistake in code to explain this.
I stripped out most everything from the sketch I had and verified code below behaves as I've described. Thanks in advance for any help/explantion!


```cpp
/*
 * Non-Working mode active.  Working method is commented out below
 *  4 PIR sensors which when triggered activate 4 different relays
 */
 
const int num=4;                // number of sensors and solenoids managed
char buffer[40];                // buffer for sprintf

const int calibrationTime = 6;       // time to let sensor calibrate - should be longer than 6 sec in practice    

const int Time[num] = {500, 500, 500, 500} ;  // milliseconds for solenoids to activate

int StateCurrent[num] = {LOW, LOW, LOW, LOW};     // sensor states
int StatePrevious[num] = {LOW, LOW, LOW, LOW};


// input defs
int Sol[num] = {4,7,8,12} ;         // chosing pins for activating solenoids
int inputPin[num] = {3,6,9,11} ;    // chosing the input pins for PIR sensors

// Event Counters
int event[num] = {0,0,0,0};         // detection counter array            

void setup() {
  Serial.begin(9600);


                                            // for reasons I don't understand when setting input pin mode in same loop with output pin mode
                                            // the first index of index loop doesn't work!!!  The other input pins/indexs work
                                            // Problem follows the pin assignment not the PIR sensor. Can switch sensor and always first pin assigned. 
                                            // Problem follows the 1st pin assigned. Can switch pin assignement (ie. assign 6 first then 3) and always first pin
                                            // 

 for (int i = 0; i <= num; i++) {    // assign pins
    pinMode(Sol[i], OUTPUT) ;         // output for driving solenoids
    pinMode(inputPin[i], INPUT) ;     // inputs for PIR sensors
  }

  Serial.println("");                         // new line
  Serial.println("");                         // new line
  Serial.println("");                         // new line
  Serial.println("Running Non-Working Example");     // output sketch running


/*
// Running loops for assignment of pins for output and pins for input separately works!
  for (int i = 0; i <= num; i++) {    // assign pins
    pinMode(Sol[i], OUTPUT) ;         // output for driving solenoids
  }

  for (int i = 0; i <= num; i++) {    // assign pins
    pinMode(inputPin[i], INPUT) ;     // inputs for PIR sensors
  }

  Serial.println("");                         // new line
  Serial.println("");                         // new line
  Serial.println("");                         // new line
  Serial.println("Running Working Example");     // output sketch running
*/


  Serial.print("Time for Sensors to Calibrate ");     // give sensor time to calibrate
    for(int i = 0; i < num; i++){
      Serial.print(".");
      delay(1000);                          // one second for each loop
    }
  Serial.println("Calibration Complete");
  Serial.println("Sensors Active");
 

  Serial.println("Testing Solenoids") ;     // check solenoids are working
  for (int i = 0; i < num; i++){
    Serial.print("Testing Solenoid ") ;
    Serial.println(i+1) ;
    digitalWrite(Sol[i], HIGH) ;
    delay(1000) ;
    digitalWrite(Sol[i], LOW ) ;
  }

}
 
void loop(){

/*  debug to read pins directly
  if(digitalRead(3) == HIGH) {
    Serial.println("Here pin 3");
  }  
    if(digitalRead(6) == HIGH) {
    Serial.println("Here pin 6");
  }  
    if(digitalRead(9) == HIGH) {
    Serial.println("Here pin 9");
  }  
    if(digitalRead(11) == HIGH) {
    Serial.println("Here pin 11");
  }  
*/  

  for (int i=0; i < num; i++){                    
    StatePrevious[i]=StateCurrent[i];             // store old state
//    delay(100);                                 // was just to debug, see if delays made it more reliable, etc.
    StateCurrent[i] = digitalRead(inputPin[i]);   // set current state
//    sprintf(buffer,"%i  %i%i  %i%i  %i%i  %i%i", i ,StatePrevious[0],StateCurrent[0],StatePrevious[1],StateCurrent[1],StatePrevious[2],StateCurrent[2],StatePrevious[3],StateCurrent[3]);
//    Serial.println(buffer);
  } 

  for (int i=0; i < num; i++){

    if (StatePrevious[i] == LOW && StateCurrent[i] == HIGH) {                        // A state change: LOW -> HIGH
      event[i] = event[i]+1 ; 
      sprintf(buffer,"Motion detected on Sensor %i - Event #%i",i+1 ,event[i]);
      Serial.println(buffer);
      sprintf(buffer,"Activating Solenoid %i", i+1);
      Serial.println(buffer);
      digitalWrite(Sol[i], HIGH);
      delay(Time[i]);
      digitalWrite(Sol[i], LOW);
    }
    else  if (StatePrevious[i] == HIGH && StateCurrent[i] == LOW) {               // state change: HIGH -> LOW
        Serial.print("Detection Ended on Sensor ");
        Serial.println(i+1) ;

    } 
  }
}                                                         // end of loop

```

Since array indices start at 0, this needs to have i < num to avoid overflowing the end of the array. Once you overflow the array, you probably overwrite some other variable, which can cause all sorts of mysterious problems.

Thanks! that was it! Obvious but blind to it until you point it out. I appreciate it.

Kinda weird it works in some cases (like the in a loop by itself) - I guess in all cases it's trying to do something with whatever is in whatever address that bad reference would point - surprised anything worked. Still weird it would work with different inputs...

But this has driven me crazy for way too long and happy to find the bug.
Thanks again.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.