counters

Hi, Im looking for advice for how to manage 6 PIR sensors; each needs its own counter.

for context, each PIR controls a bay of lighting. when a PIR state goes to HIGH it flips a solid state relay to turn on lights. Turning on the lights is easy (with no scripting experience). Turning them off is more difficult. After a specified amount of time after initially switched on the lights need to be turned off -this means each PIR needs to have a corresponding timer/counter.

if you have an idea for the best method of programming please let me know. Right now I'm trying to figure out a switch case scenario.

thanks

I think that using “millis” to get a timestamp for each event would be the way go.
Probably best to use an array of timestamps.
Check the difference between the current time and each element of the timestamp array each time through “loop()”

the simplest way is to define an array of 6 unsigned longs that hold the time when to shut the light OFF. The value is calculated when the light is switched on

pseudo code for PIR with timing to get the idea

#define SIZE 6
int relay[SIZE ] = { ...}
int PIR[SIZE ] = {...}
unsigned long off[SIZE ] = {0,0,0,0,0,0};
unsigned long offset[SIZE ] = {60, 40, 60, 30, 30, 1}; // time in seconds

void setup()
{
 
 ... 
}

void loop()
{
  for (int i =0; i<SIZE; i++)
  {
    // CHECK MOVEMENT
    if (digitalRead(PIR[i]) == HIGH)
    {
       digitalWrite(relay[i], HIGH);          // light ON
       off[i] = millis() + offset[i]*1000;     // off contains time to switch off in milliseconds
    }
    // CHECK SWITCH OFF
    if (millis() > off[i]) digitalWrite(relay[i], LOW);
  }
}

Hopes this helps

       off[i] = millis() + offset[i]*1000;     // off contains time to switch off in milliseconds

Adding to the output of millis() is not a good idea. Addition can cause overflow. Reversing the logic, and subtracting "now" from when the light was turned on is a better idea, since subtraction can not cause an overflow.

The correct tests for 'before' and 'after' with time values that can wrap-around are like this:

if (millis () - time_to_act >= 0)
{
   // do the action
}

By subtracting you guarantee to get a sign that doesn't depend on whether millis() is currently wrapping-around - the only caveat is that time_to_act mustn't be more than 2^31 milliseconds in the future or the past.

Thanks guys, Im wondering if this logic will allow for any of the 6 sensor/relay to work simultaneously- ie if relay1 is switched on for 30 seconds, will relay2 be able to be switched on without losing the count for relay1... Im assuming this is what the array is allowing.

Is each variable in the array getting its own millis?

Is each variable in the array getting its own millis?

Yes.

off[i] = millis() + offset[i]*1000;     // off contains time to switch off in milliseconds

The "i" variable indexes into the array so each sensor has it's own counter. ie off[1] is the counter for the second sensor.

@rob Not sure about the naming of "offset", I spent a few seconds wondering why there would be any offsets in a program like this :) , then I twigged off-set.


Rob

@rob
Not sure about the naming of “offset”, I spent a few seconds wondering why there would be any offsets in a program like this smiley , then I twigged off-set.

Just did a braindump at time of writing, off and offset are at least a bit confusing I agree.
off*: contains the time the Relay should switch OFF*
offset*: contains the duration the Relay should be kept ON => duration should be a better name I guess*

Thanks,
What do you think I should screen print to debug this code?

The intention is that a HIGH state of a PIR switches a relay on for 3 seconds then switches the relay off unless another HIGH state occurs before 3 seconds expires.

#define SIZE 6
int relay[SIZE] = {
  8, 9, 10, 11, 12, 13};  // output digital pins to solid state relays
int pir[SIZE] = {
  2, 3, 4, 5, 6, 7};      // input digital pins from Parallax PIR sensor
unsigned long off[SIZE ] = { 
  0,0,0,0,0,0};                  // time relay switched OFF
unsigned long offset[SIZE ] = {
  3, 3, 3, 3, 3, 3};             // time relay switched ON

void setup()
{
  Serial.begin (9600);           // what can I Serial.print to debug this..?
  pinMode(relay[SIZE], OUTPUT);  //
  pinMode(pir[SIZE], INPUT);
                          
}
void loop()
{
  for (int i =0; i<SIZE; i++)
  {

    if (digitalRead(pir[i]) == HIGH)       // check PIR state
    {
      digitalWrite(relay[i], HIGH);          // switch relay ON 
      off[i] = millis() + offset[i]*1000;     // off contains time to switch off in milliseconds
    }
    if (millis() > off[i]) digitalWrite(relay[i], LOW); // switch relay OFF after x
  }
}

Fixed the code to some extend

  • subtract the millis() to handle overflow after 49 days,
  • changed names of two arrays to reflect usage better
  • init pinMode correctly
  • added some debug statements to serial (comma separated so you can copy it to Excel :wink:

(not compiled or tested, just edited)

#define SIZE 6

int relay[SIZE] = {  8, 9, 10, 11, 12, 13 };  // output digital pins to solid state relays
int pir[SIZE] = {  2, 3, 4, 5, 6, 7 };            // input digital pins from Parallax PIR sensor

unsigned long startTime[SIZE ] = {  0,0,0,0,0,0 };                  // time relay switched ON
unsigned long duration[SIZE ] = { 3000, 3000, 3000, 3000, 3000, 3000 };               // for how long in milli-seconds (note this is minimum time)

void setup()
{
  Serial.begin (115200);                           
  Serial.println("Start PIR monitor 0.1");

  for (int i=0; i < SIZE; i++)
  {
    pinMode(relay[i], OUTPUT);      
    pinMode(pir[i], INPUT);
  }
}

void loop()
{
  for (int i =0; i<SIZE; i++)
  {

    if (digitalRead(pir[i]) == HIGH)       // check PIR state
    {
      digitalWrite(relay[i], HIGH);          // switch relay ON 
      startTime[i] = millis();
      Serial.print(millis()); Serial.print(", ON, ");  Serial.println(i);
    }

    if ((millis() - duration[i]) >= startTime[i])  // time to switch off ??
    {
      digitalWrite(relay[i], LOW); // switch relay OFF after x
      Serial.print(millis()); Serial.print(", OFF, ");  Serial.println(i);
    }
  }
}

Thanks! I'll let you know how it works out,

Hi guys,
After a lot of wiring and replacing PIRs (for 10$ youd think they’d be more reliable), all is up and running.

I am having one issue that is not hardware related. The 6th relay pin (5th in the array) will not act like the others in the loop. It is constantly on for the given amount of time (unsigned long duration) and then shuts off for a moment, then back on. Otherwise this code is working wonderfully, thanks again.

This is, in the case of the code below, Relay PIN 13 and Pir PIN 7.

Any ideas?

#define SIZE 6

int relay[SIZE] = {  
  8, 9, 10, 11, 12, 13 };  // output digital pins to solid state relays
int pir[SIZE] = {  
  2, 3, 4, 5, 6, 7 };            // input digital pins from Parallax PIR sensor

unsigned long startTime[SIZE ] = {  
  0,0,0,0,0,0 };                  // time relay switched ON
unsigned long duration[SIZE ] = { 
  3000, 3000, 3000, 3000, 3000, 3000 };               // for how long in milli-seconds (note this is minimum time)

void setup()
{
  Serial.begin (9600);                           
  //Serial.println("Start PIR monitor 0.1");

  for (int i=0; i < SIZE; i++)
  {
    pinMode(relay[i], OUTPUT);      
    pinMode(pir[i], INPUT);
  }
}

void loop()
{
  for (int i =0; i<SIZE; i++)
  {

    if (digitalRead(pir[i]) == HIGH)       // check PIR state
    {
      digitalWrite(relay[i], HIGH);          // switch relay ON 
      startTime[i] = millis();
      Serial.print(millis()); 
      Serial.print(", ON, ");  
      Serial.println(i);
    }

    if ((millis() - duration[i]) >= startTime[i])  // time to switch off ??
    {
      digitalWrite(relay[i], LOW); // switch relay OFF after x
      Serial.print(millis()); 
      Serial.print(", OFF, ");  
      Serial.println(i);
    }
  }
delay(500);
}
delay(500);

It was all going so well well up to there.

Ah sorry! the delay was removed. Still has the same issue just doesn’t delay.

hold on.. might be a hardware issue.

PIN 13 is of course a special one, it has the led and that could just make a difference, other max load, don't know the details, just that its different.

try to swap the relays from pin13 and pin12 . if the problem is in the relay, pin 12 should give trouble, otherwise its the LED I guess

Fixed. finally. Thanks for the help. It was a hardware/wiring/sensor issue that was freaking something out. 4 PIRs later it works. Thanks for the help earlier. You can check out the project here http://khmay.info/ it's the first post, however there are no arduino pics yet. only the space.

KM