Hello all,
I am having an issue with millis() and case switch.
I would like to integrate three millis() but it seems like in the automatic mode, the millis() for the LED blocks anything bellow it. Am I doing something wrong or is millis() not compatible with switch statements?
#include "IRremote.h"
/*-----( Declare Constants )-----*/
int IR = 4; // pin 1 of IR receiver to Arduino digital pin 11
int LEDACT = 3; // LED activity
int RELAY = 6; // RELAY
const int ledPin = 2;// the number of the LED pin
int ledState = LOW;
// read the input on analog pin 0:
int PHOTO = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = PHOTO * (5.0 / 1023.0);
/*-----( Declare objects )-----*/
IRrecv irrecv(IR); // create instance of 'irrecv'
decode_results results; // create instance of 'decode_results'
/*--------- delays -----*/
const unsigned long delay_1h30 = 5400000; // 1h30 to ms is 5400000
const unsigned long delay_12h = 43200000; // 12h to ms is 43200000
const unsigned long interval = 1; // 1000Hz
const unsigned long interval1 = 1000; // read voltage every 1 second
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long currentMillis = millis();
/* ------ PHOTO --------*/
void setup() /*----( SETUP: RUNS ONCE )----*/
{
Serial.begin(9600);
Serial.println("Snow detector");
irrecv.enableIRIn(); // Start the receiver
pinMode(LEDACT, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, LOW);
}/*--(end setup )---*/
void loop(){ /*----( LOOP: RUNS CONSTANTLY )----*/
if (irrecv.decode(&results)) // have we received an IR signal?
{
// Serial.println(results.value, HEX); UN Comment to see raw values
translateIR();
irrecv.resume(); // receive the next value
}
}/* --(end main loop )-- */
/*-----( Declare User-written Functions )-----*/
void translateIR() // takes action based on IR code received
{
switch(results.value)
{
case 0xFFA25D:
Serial.println(" TOGGLE RELAY ON ");
for (int i = 0; i <= 0; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
digitalWrite(RELAY, HIGH);
digitalWrite(RELAY, LOW);
break;
case 0xFF629D:
Serial.println(" Automatic mode ");
for (int i = 0; i <= 1; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
unsigned long presentMillis = millis();
if((millis() - currentMillis) > interval) //EDIT
{
digitalWrite(ledPin, LOW);
delay(1); //wait here
digitalWrite(ledPin, HIGH);
}
break;
case 0xFFE21D:
Serial.println(" 1h30 ");
for (int i = 0; i <= 2; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
digitalWrite(ledPin, LOW);
break;
case 0xFF22DD:
Serial.println(" 12h ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
digitalWrite(ledPin, LOW);
break;
case 0xFF02FD:
Serial.println(" TOGGLE RELAY OFF ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(250); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(250);
}
digitalWrite(RELAY, LOW);
digitalWrite(ledPin, LOW);
break;
default:
Serial.println(" other button ");
}
delay(500);
Serial.println(PHOTO);
} //END translateIR
Do you think that you should update currentMillis somewhere in the program ?
for (int i = 0; i <= 1; i++)
What is the purpose of this for loop ?
Use of millis() and switch/case is perfectly OK if done correctly
Hi there,
It is the make the LEDACT blink once
Then you don't need a for loop
What about currentMillis and, when in automatic mode with a 2 second delay in it, how is the LED going to turn on and off at 1000Hz as implied by the comment here
const unsigned long interval = 1; // 1000Hz
Please explain what the program is supposed to do in each state
Hi Bob,
Sorry for not getting back to you.
Essentially, I have an IR remote that communicates with an IR receiver. Each case switch statement has a function that enables to turn on the relay or off. The first mode enables to relay to be always on, the second is automatic, third for 1h30 before turning off and fourth for 12h before turning off.
For automatic, I want to be able to detect a certain voltage and then turn on the relay for 1h30.
How would I be able to add a 1h30 delay, 12h delay and so on?
I hope it helps more.
I wait your reply.
How would I be able to add a 1h30 delay, 12h delay and so on?
You could use a state like this
switch (someVariable)
{
case WAIT_A_WHILE:
if (currentTime - stateStartTime > statePeriod)
{
someVariable = someOtherState;
//set up initial for new state here
}
break;
}
Before entering the WAIT_A_WHILE state set up the initial values such as stateStartTime and statePeriod. If you need the WAIT_A_WHILE state to move on to different state depending on the waiting time then either set the target state appropriately by testing the statePeriod value or use a stateToMoveTo variable that you give a value to before entering the WAIT_A_WHILE state then do
someVariable = stateToMoveTo;
//set up initial for new state here
If you really must you could have different states for each waiting period but that would be wasteful
Is it not possible to put the if current millis after the case such as;
case 0xFFE21D:
Serial.println(" 1h30 ");
for (int i = 0; i <= 2; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
if(millis() - currentMillis >= interval1) //EDIT
{
digitalWrite(ledPin, LOW);
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
unsigned long presentMillis = millis();
}
Serial.println(" RELAY OFF");
break;
This doesn't seem to work.
You can compare the current value of millis() with a previously save value anywhere you like but unless you update currentMillis somewhere its initial value will not change. As it is the the code you posted you compare millis() with currentMillis then update presentMillis. That is not right
Your use of delay() is also a possible source of problems because it holds up the program whilst it executes. Probably not a problem with such long timing periods but it is wrong nevertheless
Hi Bob,
Yes I can see that now in my code. How would it look like for updating the millis()?
I don't really understand why the LED flashing at 1000Hz works fine outside the if and why the analog read works outside the if. It seems like millis() doesn't like working in the if's.
This is my code:
#include <IRremote.h>
int RELAY = 6; // Relay
int IR = 4; // pin 1 of IR receiver to Arduino digital pin 11
int LEDACT = 3; // LED activity
const int ledPin = 2;
int ledState = LOW;
int RECV_PIN = 4 ; // IR receive pin is 11
IRrecv irrecv(RECV_PIN);
long int decodedCode;
//#define ON 16753245 ;
//#define OFF 16736925 ;
//#define ONE_HOUR 16769565 ;
//#define TWELVE_HOURS 16720605 ;
//#define AUTO 16712445 ;
decode_results rcv;
/*--------- delays -----*/
const unsigned long delay_1h30 = 5400000; // 1h30 to ms is 5400000
const unsigned long delay_12h = 43200000; // 12h to ms is 43200000
const unsigned long interval = 1; // 1000Hz
const unsigned long interval1 = 1000; // read voltage every 1 second
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long currentMillis = millis();
void setup(){
pinMode(LEDACT, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, LOW);
digitalWrite(RELAY, LOW); // Relay is active low, so HIGH will turn it off at startup
Serial.begin(9600);
Serial.println("Snow detector");
irrecv.enableIRIn();
}
void loop(){
if(millis() - currentMillis >= interval) //EDIT
{
digitalWrite(ledPin, LOW);
delay(1); //wait here
digitalWrite(ledPin, HIGH);
unsigned long presentMillis = millis();
}
if(millis() - currentMillis >= interval1) //EDIT
{
// read the input on analog pin 0:
int PHOTO = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = PHOTO * (5.0 / 1023.0);
Serial.println(voltage);
}
if (irrecv.decode(&rcv)) {
decodedCode = rcv.value;
if(decodedCode == 16753245) {
Serial.println(" TOGGLE RELAY ON ");
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
digitalWrite(RELAY, HIGH);
digitalWrite(ledPin, LOW);
}
if(decodedCode == 16736925) {
Serial.println(" TOGGLE RELAY OFF ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(250); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(250);
}
digitalWrite(RELAY, LOW);
digitalWrite(ledPin, LOW);
}
if(decodedCode == 16712445) {
Serial.println(" Automatic mode ");
for (int i = 0; i <= 1; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
}
if(decodedCode == 16769565) {
Serial.println(" 1h30 ");
for (int i = 0; i <= 2; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
if(millis() - currentMillis >= interval1) //EDIT
{
digitalWrite(ledPin, LOW);
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
}
Serial.println(" RELAY OFF");
}
if(decodedCode == 16720605) {
Serial.println(" 12h ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
digitalWrite(ledPin, LOW);
}
irrecv.resume();
unsigned long presentMillis = millis();
}
}
How would it look like for updating the millis()?
You don't update millis(), rather you update the value that you are checking against millis()
This (and other tests like it) can never work
if (millis() - currentMillis >= interval) //EDIT
{
digitalWrite(ledPin, LOW);
delay(1); //wait here
digitalWrite(ledPin, HIGH);
unsigned long presentMillis = millis();
}
because you never update the value of currentMillis, which I believe I have pointed out several times. To make things worse the presentMillis variable in the above code segment will immediately go out of scope when the code block ends in the next line because it is a locally declared variable
Why have you got both currentMillis and presentMillis in your code ? What is the purpose of both of them ?
So essentially I need to change presentMillis to currentMillis?
I guess the unsigned long presentMillis = millis(); needs to be removed and added right at the end after the if's?
I guess I have both because I think they are somehow the same thing but in fact they are not.
if(decodedCode == 16769565) {
Serial.println(" 1h30 ");
for (int i = 0; i <= 2; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
if(millis() - currentMillis >= delay_1h30) //EDIT
{
digitalWrite(ledPin, LOW);
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
}
Serial.println(" RELAY OFF");
}
I do not understand why when I press the button for this IR code after it flashes it prints RELAY ON and RELAY OFF straight away. I want it to start from zero sending RELAY ON and then after 1h30 it turns RELAY OFF.
It would make sense to have one variable to hold the value of millis() at a point in time so that all time measurements within the program can reference it without the overhead of multiple calls to millis() or the chance the value of millis() changing between calls to it. As I am a bear of little brain I usually put something like this
unsigned long currentMillis = millis();
at the start of loop() as that seems to be a logical place to do it before carrying out the actions in the loop() function.
On the other hand, the saving of the time when an action takes place, such as the start of a new timing period, needs to happen only when relevant such as when an output state has been changed as in the BlinkWithoutDelay function. This needs to be given a sensible name and the value should be copied from the currentMillis variable to maintain timing consistency as in
lastStateChangeMillis = currentMillis;
Make those changes and let us know how you get on
That makes sense I will do the following changes and get back to you tomorrow morning.
Where would you put lastStateChangeMillis = currentMillis; ? Would you place it at the end of each if within the case switch to update the timings?
Where would you put lastStateChangeMillis = currentMillis; ?
I would put it in the code block that executes before a timing period starts, either because the previous period ended or perhaps because of input from a sensor or a user causes a timing period to start.
Okay I will give this a go tomorrow morning and I'll get back to you early morning. Europe time
Hi Bob,
So I have tried it and it doesn't seem to do what is said.
I guess I need to onyl apply multiple mills() but my code works with the on function, off function, 1h30 and 12h with delay but the automatic mode is not working.
I have a feeling that I am doing something wrong that is causing a block or something but I cannot seem to spot it.
#include "IRremote.h"
/*-----( Declare Constants )-----*/
int IR = 4; // pin 1 of IR receiver to Arduino digital pin 11
int LEDACT = 3; // LED activity
int RELAY = 6; // RELAY
const int ledPin = 2;// the number of the LED pin
int ledState = LOW;
//int voltage = 0.50 ;
// Flashing LED with photo
/*-----( Declare objects )-----*/
IRrecv irrecv(IR); // create instance of 'irrecv'
decode_results results; // create instance of 'decode_results'
/*--------- delays -----*/
const unsigned long delay_1h30 = 5400000; // 1h30 to ms is 5400000
const unsigned long delay_12h = 43200000; // 12h to ms is 43200000
const unsigned long interval = 1; // 1000Hz
const unsigned long interval1 = 10000; // read voltage every 1 second
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long currentMillis = millis();
unsigned long lastStateChangeMillis = currentMillis;
/* ------ PHOTO --------*/
//
int sensorValue = analogRead(A0);
float voltage = sensorValue * (5.0 / 1023.0);
void setup() /*----( SETUP: RUNS ONCE )----*/
{
Serial.begin(9600);
Serial.println("Snow detector");
irrecv.enableIRIn(); // Start the receiver
pinMode(LEDACT, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, LOW);
}/*--(end setup )---*/
void loop(){ /*----( LOOP: RUNS CONSTANTLY )----*/
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
// Turn on FLASH and PHOTO
if(currentMillis - previousMillis >= interval1) {
previousMillis = currentMillis ;
}
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
// unsigned long currentMillis = millis();
if (irrecv.decode(&results)) // have we received an IR signal?
{
// Serial.println(results.value, HEX); UN Comment to see raw values
translateIR();
irrecv.resume(); // receive the next value
}
}/* --(end main loop )-- */
/*-----( Declare User-written Functions )-----*/
void translateIR() // takes action based on IR code received
{
switch(results.value)
{
case 0xFFA25D:
Serial.println(" TOGGLE RELAY ON ");
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
digitalWrite(RELAY, HIGH);
digitalWrite(ledPin, LOW);
break;
case 0xFF629D:
Serial.println(" Automatic mode ");
for (int i = 0; i <= 1; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
if (voltage > 0.50) {
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
delay(10000);
} else {
Serial.println(" RELAY OFF");
digitalWrite(RELAY, LOW);
}
}
break;
case 0xFFE21D:
Serial.println(" 1h30 ");
for (int i = 0; i <= 2; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
digitalWrite(ledPin, LOW);
}
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
delay(5400000); //1h30
Serial.println(" RELAY OFF");
digitalWrite(RELAY, LOW);
break;
case 0xFF22DD:
Serial.println(" 12h ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(1000);
digitalWrite(ledPin, LOW);
}
digitalWrite(RELAY, HIGH);
Serial.println(" RELAY ON");
delay(10000); //12 hour
Serial.println(" RELAY OFF");
digitalWrite(RELAY, LOW);
break;
case 0xFF02FD:
Serial.println(" TOGGLE RELAY OFF ");
for (int i = 0; i <= 3; i++) {
digitalWrite(LEDACT, HIGH); // turn the LED on (HIGH is the voltage level)
delay(250); // wait for a second
digitalWrite(LEDACT, LOW); // turn the LED off by making the voltage LOW
delay(250);
}
digitalWrite(RELAY, LOW);
digitalWrite(ledPin, LOW);
break;
default:
Serial.println(" other button ");
}
} //END translateIR
but the automatic mode is not working.
What do you mean exactly ?
Does it not enter the state ?
Does it not stay in the state ?
Something else ?
A suggestion. Print a text label and the value of results.value before the switch statement. Is the value what you expect ?
Why have you got a silly for loop in the automatic state code ?
Have you tried printing the value of i inside the for loop ?
Is it what you expect ?
I am think of starting all over again.
Creating a milli for each purpose such as flashing LED, LED activity, voltage read, timers for 1h30 relay and 12h relay.
Do you think it is a reasonable idea?
Is it possible to create a function for each millis()?
Such as, LEDACTmillis() which flashes on and off every 1 second before turning on the relay?
So far I have this and seems to make good sense.
// CONSTANTS
const int FLASH = 2 ;
const int LEDACT = 3 ;
const int IR = 4 ;
const int RELAY = 6 ;
// STATES
int FLASHSTATE = LOW ;
int LEDACTSTATE = LOW ;
int IRSTATE = LOW ;
int RELAYSTATE = LOW ;
// PREVIOUS MILLIS
unsigned long previousMillis0 = 0 ; // for FLASH
unsigned long previousMillis1 = 0 ; // for LED ACTIVITY
unsigned long previousMillis2 = 0 ; // for RELAY
unsigned long previousMillis3 = 0 ; // for timer?
// INTERVALS MILLIS
long interval0 = 1 ; // for FLASH
long interval1 = 1000 ; // for LED ACTIVITY
long interval2 = 5400000 ; // for 1H30
long interval3 = 43200000 ; // for 12H
// FUNCTIONS
void LEDACTmillis() {
unsigned long currentMillis = millis() ;
if((LEDACTSTATE == HIGH) && (currentMillis - previousMillis1 >= interval1))
{
LEDACTSTATE = LOW ; // Turn it off
previousMillis1 = currentMillis ; // Remember the time
digitalWrite(LEDACT, LEDACTSTATE) ; // Update the actual LED
}
else if ((LEDACTSTATE == LOW) && (currentMillis - previousMillis1 >= interval1))
{
LEDACTSTATE = HIGH ; // turn it on
previousMillis1 = currentMillis ; // Remember the time
digitalWrite(LEDACT, LEDACTSTATE) ; // Update the actual LED
}
}
void setup() {
pinMode(LEDACT, OUTPUT) ;
}
void loop() {
LEDACTmillis() ;
}
Does this look well structured?