Pages: [1] 2   Go Down
Author Topic: How to monitor a switch's state and do X if switch has remained in state B  (Read 1400 times)
0 Members and 1 Guest are viewing this topic.
Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How to monitor a switch's state and do X if switch has remained in state B for length of time T?

Basically I want to alert the user audibly if a toggle switch remains in and "on" position for longer than 2hrs but don't know how to do it logically.

Would appreciate any tips

Thanks
Logged

California
Online Online
Faraday Member
**
Karma: 88
Posts: 3360
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Declare global variable to keep track of the time that the switch has remained in it's position.
Record the edge time for when the switch changed states.
Keep checking for the the time it's been since it's been switched (millis() - timeSwitched) and compare that to your interval time.
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Declare global variable to keep track of the time that the switch has remained in it's position.
Record the edge time for when the switch changed states.
Keep checking for the the time it's been since it's been switched (millis() - timeSwitched) and compare that to your interval time.

Yes that's what I thought initially, but how do I avoid overwriting the timeSwitched with millis() everytime the IF statement checks to see if the switch is still HIGH?

Thanks!
Logged

Pennsylvania, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This should get you on the right path.  I think I got all of the conditions but didn't test anything.

Code:
#define SWITCH_TIMELIMIT 7200000
#define SWITCH_PIN 2

void loop()
{
  static unsigned long switch_timestamp = 0;
  bool switch_state = digitalRead(SWITCH_PIN);

  if(switch_state && switch_timestamp && (millis() - switch_timestamp) >= SWITCH_TIMELIMIT)
  {
    //Do something important here.

    //if you want to reset the warning:
    //switch_timestamp = 0;
  }
  else if (!switch_timestamp && switch_state)
  {
    //The !switch_timestamp is to make sure we don't refresh the timer if the switch remained on.
    //The pin just changed to on, start the timer
    switch_timestamp = millis();
  }
  else if(!switch_state && switch_timestamp)
  {
    //Switch went off, while timer was running, disable the timer
    switch_timestamp = 0;
  }

}

Logged

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12549
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Declare global variable to keep track of the time that the switch has remained in it's position.
Record the edge time for when the switch changed states.
Keep checking for the the time it's been since it's been switched (millis() - timeSwitched) and compare that to your interval time.

Yes that's what I thought initially, but how do I avoid overwriting the timeSwitched with millis() everytime the IF statement checks to see if the switch is still HIGH?

Thanks!

Remember the previous state of the switch, and only record the 'start time' when you see the switch change to state B. This is what Arrch refers to as the edge time.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

California
Online Online
Faraday Member
**
Karma: 88
Posts: 3360
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Remember the previous state of the switch, and only record the 'start time' when you see the switch change to state B. This is what Arrch refers to as the edge time.
Yup. The "Edge time" refers to the time in which the state changes. The rising or positive edge is when the state goes from low to high, and the falling or negative edge is low to high. Do you will need to keep track of one of those by keeping track of the last state.

So the pseudo code for tracking the positive edge would be:

get current state

if last state is low and current state is high
  // Positive Edge
   set edge time to current

set last state to current state

if edge time minus current time is greater than threshold time
  // Do something here

 
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for the proto code! I will test it tonight. I don't unnerstand this
Code:
switch_state && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)
(i.e. how it is able to do what it does!) which worries me but maybe after playing with it I will.

Is there an easy way to call a function (to play a tone on a piezo speaker) every two minutes when the switch has remained "on" for the pre-determined time limit? Or would I need to use variables to a) track when the piezo function was called and b) create an "alert" state which would control when the function was called?

Code:
  static unsigned long switch_timestamp = 0;
  bool switch_state = digitalRead(switchPin1);
  const int switchPin1 = 1;   
  long switchPin1TriggeredTime = 7200000;

  if(switch_state && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)   {
  //play a short alert tone every minute
    }
 
  else if (!switch_timestamp && switch_state)   {
    //The !switch_timestamp is to make sure we don't refresh the timer if the switch remained on.
    //The pin just changed to on, start the timer
    switch_timestamp = millis();
  }
 
  else if(!switch_state && switch_timestamp)   {
    //Switch went off, while timer was running, disable the timer
    switch_timestamp = 0;
  }
 
  if(switch_state)  {

//actual code for when switch is on goes here?
}
Logged

Pennsylvania, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'll try to explain this for you:
Code:
if(switch_state && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)

Is functionally identical to this:
Code:
if (switch_state == HIGH) //The switch is depressed
{
     if (switch_timestamp > 0)  //The switch was depressed the last time we checked it too
     {
          if (millis() - switch_timestamp >= switchPin1TriggeredTime)  //It's been 2 minutes.
          {
                 //Play a short tone.
          }
     }
}

To call a function every 2 minutes, you are correct - you would need a variable to track the last time it was called, and update the variable every time you called it.  Same exact logic we're using to determine when to press it the first time.

One "hack" you could do to get this working fast, is every time you play the tone, reset the switchPin1TriggeredTime back to the current system clock.

Like so:
Code:

  if(switch_state && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)   {
  //play a short alert tone every minute
     playWarningTone();
     switch_timestamp = millis() + ( 6000 );  //Re-fire the event every minute after the first 2 minute warning.
    }
 
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(This was posted before tgm175 posted his explanation.)

OK I've made some changes to the code and tested it and with acknowledgements and thanks to tgm1175 who was the chef here, I wasn't even the sous chef, I was the washer-upper.

This is tested working.

THANKS

Code:
#include <Bounce.h>
const int switchPin1 = 7;    
long switchPin1TriggeredTime = 10000;
Bounce bouncer = Bounce( switchPin1,5 );

void setup()
{
  Serial.begin(57600);
  pinMode(switchPin1, INPUT);
  digitalWrite(switchPin1, HIGH); //pull up
  Serial.println("TEST");
  pinMode(13, OUTPUT);    
}
void loop()
{
  bouncer.update ( );
  int value = !bouncer.read();
  static unsigned long switch_timestamp = 0;
  if(value && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)   {
    Serial.println("HEY SWITCH HAS BEEN 'ON' TOO LONG!!");
  }
  else if (!switch_timestamp && value)   {
    //The !switch_timestamp is to make sure we don't refresh the timer if the switch remained on.
    //The pin just changed to on, start the timer
    switch_timestamp = millis();
  }
  else if(!value && switch_timestamp)   {
    //Switch went off, while timer was running, disable the timer
    switch_timestamp = 0;
    Serial.println("TURNED OFF");
  }
  if(value)  {
    digitalWrite(13, HIGH);   // LED on
  }
  if(!value)  {
    digitalWrite(13, LOW);   // LED off
  }
}
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One "hack" you could do to get this working fast, is every time you play the tone, reset the switchPin1TriggeredTime back to the current system clock.

Like so:
Code:

  if(switch_state && switch_timestamp && (millis() - switch_timestamp) >= switchPin1TriggeredTime)   {
  //play a short alert tone every minute
     playWarningTone();
     switch_timestamp = millis() + ( 6000 );  //Re-fire the event every minute after the first 2 minute warning.
    }
 


Thank you for this hack, it seems to have a lot of potential. However when using it, I've found that what happens is that the warning tone is re-fired after switchPin1TriggeredTime - not every minute. Would you mind seeing if there's something simple to address to get it working? I've had a play myself to no avail :-)

THANKS AGAIN
Logged

California
Online Online
Faraday Member
**
Karma: 88
Posts: 3360
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
switch_timestamp = millis() + ( 6000 );

What this means (assuming timestamp isn't changed), is that after 6 seconds, the timestamp will will be equal to the current time, so that means overall, it will run again 6 + interval seconds. If you want it to run every minute, then you simply need to add 1 minute to what the current timestamp is:
Code:
switch_timestamp += 60000;
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
switch_timestamp = millis() + ( 6000 );

What this means (assuming timestamp isn't changed), is that after 6 seconds, the timestamp will will be equal to the current time, so that means overall, it will run again 6 + interval seconds. If you want it to run every minute, then you simply need to add 1 minute to what the current timestamp is:
Code:
switch_timestamp += 60000;

Hmmm - tried that - it didn't do the trick either. Thanks though!
Logged

Toronto, Canada
Offline Offline
Edison Member
*
Karma: 2
Posts: 1234
"Keep it R.E.I.L. - "Research, Experiment, Investigate and Learn"
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know this code may give you some idea about the state of a switch and help you for some insight...

Here a code. The code is a gear shifter. It got a Up and Down button. The switch go from HIGH to LOW. I hope it give you some insight.

Code:
/*
  size : 1774 byte
 
  Version 2.1
 
  file name : gearshifter.pde
 
  It simulate a gear shifter using 2 push-button switch.
  The circuit use a 7 segment display and 2 led for the
  simulated selenoid.
 
  Gear sequence:   Gear Number   A   B
                       1         1   1
                       2         0   1
                       3         0   0
                       4         1   0
 
  Here the parts you need :

  1 Commun Anode 7 segment Display
  2 Red LED
  2 Push Button Switch
  9 2N3904 NPN Transistor
  11 1 K resistor
  9 330 ohms resistor
 
  How it work :
 
  1. Init the gear at 1.
  2. Press Upshift Button to increase the gears
  3. Press Downshift Button to decrease the gears.
 
  Program by Serge J Desjardins aka techone / tech37

  Compile and Tested <-- Test on a breadboard

  Disclaimer:

  I am not responsible for any damages, losses, injuries or death.
  The user is responsabe for any damages, losses, injuries or death.
 
  And Murphy's Law is always there, bear that in mind.
   
*/
// Arduino Digital pins
const byte outpin[9] = {4,5,6,7,8,9,10,11,12};
const byte inpin[2] = {2,3};
// Selenoid and Display array pattern
boolean gearone[9] = {1,1,0,0,0,0,1,1,0};
boolean geartwo[9] = {0,1,1,0,1,1,0,1,1};
boolean gearthree[9] = {0,0,1,0,0,1,1,1,1};
boolean gearfour[9] = {1,0,1,1,0,0,1,1,0};

byte gear;

int upshift=1;
int downshift=1;
int oldupshift=1;
int olddownshift=1;

boolean state=0;

void setup()
{
  // init the digital pins
  for (int i=0; i<9; i++)
  {
  pinMode(outpin[i],OUTPUT);
  }
  pinMode(inpin[0],INPUT);
  pinMode(inpin[1],INPUT);
  // Put in gear one
  gear=1;
 
  for (int i=0;i<9;i++)
  {
    digitalWrite(outpin[i],gearone[i]);
  }
}

void loop()
{
  readswitch();
  while(state==0)
  {
    readswitch();     
  }
  // a switch as been pressed
  // Check for the upshift
  if ((upshift==0) && (state==1))
  { 
     gear++;
     if ((gear>=1) && (gear<=4))
     {
       switch(gear)
       {
         case 1: selectone();break;
         case 2: selecttwo();break;
         case 3: selectthree();break;
         case 4: selectfour();break;
       }
     }
     else gear=4;
   }
  // check for the downshift 
  if ((downshift==0) && (state==1))
  { 
     gear--;
     if ((gear>=1) && (gear<=4))
     {
       switch(gear)
       {
         case 1: selectone();break;
         case 2: selecttwo();break;
         case 3: selectthree();break;
         case 4: selectfour();break;
       }
     }
     else gear=1;
   }   
   
}

void selectone()
{
   for (int i=0;i<9;i++)
   {
     digitalWrite(outpin[i],gearone[i]);
   }
   state=0; 
}

void selecttwo()
{
   for (int i=0;i<9;i++)
   {
     digitalWrite(outpin[i],geartwo[i]);
   }
   state=0; 
}

void selectthree()
{
   for (int i=0;i<9;i++)
   {
     digitalWrite(outpin[i],gearthree[i]);
   }
   state=0; 
}

void selectfour()
{
   for (int i=0;i<9;i++)
   {
     digitalWrite(outpin[i],gearfour[i]);
   }
   state=0; 
}

/* The subroutine is a modify switch example in page
   51 of the book "Getting Started with Arduino"
   
   The switch is configure with a pull-up resistor,
   so it always a 1, when press, it is a 0.
*/   
void readswitch()
{
  upshift=digitalRead(inpin[0]);
  // check upshift transition
  if ((upshift==0) && (oldupshift==1))
  {
    state=1;
    delay(50);
  } 
  oldupshift=upshift;
  downshift=digitalRead(inpin[1]);
  // check downshift transition
  if ((downshift==0) && (olddownshift==1))
  {
    state=1;
    delay(50);
  } 
  olddownshift=downshift; 
}
Logged

California
Online Online
Faraday Member
**
Karma: 88
Posts: 3360
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmmm - tried that - it didn't do the trick either. Thanks though!
I've done that in my code and it's worked, so it sounds like there is another issue with another part of your code, then.
Logged

Wales
Offline Offline
Full Member
***
Karma: 0
Posts: 244
Don't take things too seriously
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

so it sounds like there is another issue with another part of your code, then.

Maybe I put your snippet in the wrong place?
Code:
long switchPinsWaitTime = 30000; //30 seconds
Code:
  static unsigned long switch_timestamp1 = 0;

  if(value2 && switch_timestamp1 && (millis() - switch_timestamp1) >= switchPinsWaitTime)   
  {
    //    playTone(100, 1000);
    //    playTone(100, 3000);
    //    playTone(100, 1000);
    //    playTone(100, 3000);
    switch_timestamp1 += 60000;
  }

  else if (!switch_timestamp1 && value2)   
  {
    //The !switch_timestamp1 is to make sure we don't refresh the timer if the switch remained on.
    //The pin just changed to on, start the timer
    switch_timestamp1 = millis();
  }
  else if(!value2 && switch_timestamp1)   
  {
    //Switch went off, while timer was running, disable the timer
    switch_timestamp1 = 0;
  }
Logged

Pages: [1] 2   Go Up
Jump to: