LED + button + timer

Hi all, what I need bascially is to have 1 red led turned on by default. when I press the button the red led goes off while the green LED turns on for 5 seconds and then back off (and red on). I'm a bit confused about the millis(). If I press the button while the green is still on, the timer should be restarted.

the code below seems to work for the first few times I try it but then it goes wrong.

Thanks!

int button = 2;
int green = 8;
int red = 7;
boolean flag = false;
int timer = 0;

void setup()
{
  pinMode(green, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode (button, INPUT_PULLUP);
  digitalWrite(red, HIGH);
  Serial.begin(9600);
}

void loop()
{
  if (digitalRead(button) == HIGH){
      timer = millis();
      flag = true;
  }

  if(flag){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
  }else{
      digitalWrite(green, LOW);
      digitalWrite(red, HIGH);
  }

  if(millis() > timer+5000){
      flag = false;
  }
  
}
      timer = millis();

millis () returns a what sort of datatype?

milliseconds

leech:
milliseconds

That is NOT a data type.

got it! unsigned long..working..thanks!

Hi there, I'll bring this up as I have now added an RTC clock to the Arduino and I have another question.
Basically the previous code (without RTC, just usign millis()) is working fine. However I implemented the RTC module in order to display the time on an LCD screen. It works, except that for some reason it breaks the comparison millis() > timer that was working before. Here's my code, where the LED will stay green only while I keep the button pressed. Thanks!

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal.h>
 
char myBuffer[10];
 
RTC_DS1307 RTC;
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

int button = 10;
int green = 9;
int red = 8;
boolean flag = false;
unsigned long timer = 0;

DateTime myNow;
  
void setup()
{
  pinMode(green, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode (button, INPUT_PULLUP);
  digitalWrite(red, HIGH);
//  Serial.begin(9600);

  Wire.begin();
  RTC.begin();
  
  lcd.begin(16, 2);
  lcd.clear(); 
  lcd.setCursor(0,0);  
     
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }

 myNow = RTC.now();
}

void loop()
{
  
  if (digitalRead(button) == HIGH){
      timer = millis();
      flag = true;
      myNow = RTC.now();
  }

  if(flag){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
  }else{
      digitalWrite(green, LOW);
      digitalWrite(red, HIGH);
  }
  

//this was working without RTC code. Now it's not working anymore
  if(millis() > timer + 5000 ){
      flag = false;
  }

    
  sprintf(myBuffer,  "%02d/%02d/%d", myNow.day(), myNow.month(), myNow.year());
  lcd.setCursor(0,0);
  lcd.print( myBuffer );
 
  char myBuffer[10] = "";
 
  sprintf(myBuffer,  "%02d:%02d:%02d", myNow.hour(), myNow.minute(), myNow.second());
  lcd.setCursor(0,1);
  lcd.print( myBuffer );

}

small update..I got rid of the millis() and I was trying to use .unixtime() but it it doesn't work. The green LED will stay up only while I press the button and I don't understand why the condition is not evaluated correctly.

void loop()
{
  
  if (digitalRead(button) == HIGH){
      flag = true;
      now = rtc.now();
  }

  if(flag){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
  }else{
      digitalWrite(green, LOW);
      digitalWrite(red, HIGH);
  }


//this is broken
  if(rtc.now().unixtime() > (now.unixtime() + 5)){
    flag = false;
  }
    
  sprintf(myBuffer,  "%02d/%02d/%d", now.day(), now.month(), now.year());
  lcd.setCursor(0,0);
  lcd.print( myBuffer );
 
  char myBuffer[10] = "";
 
  sprintf(myBuffer,  "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  lcd.setCursor(0,1);
  lcd.print( myBuffer );

}

How many times will loop() iterate while you hold the switch down?

//this is broken
  if(rtc.now().unixtime() > (now.unixtime() + 5)){
    flag = false;
  }

No, it is not. Print the values of rtc.now().unixtime() and now.unixtime() to see for yourself that the values are correct, and that it is you logic that is wrong.

The time, in the past that the switch was pressed, is NOT now, so that is a dumb name.

  sprintf(myBuffer,  "%02d/%02d/%d", now.day(), now.month(), now.year());
  lcd.setCursor(0,0);
  lcd.print( myBuffer );
 
  char myBuffer[10] = "";

Write to myBuffer, and then define myBuffer. Your cart is on the wrong end of that horse. So, it appears that you now have two variables called myBuffer. Psst. That's stupid.

Hi! Thanks, I printed out the values in the if statement and yes, they are correct but then why the green LED won't stay green for 5 seconds? The same logic was used with millis() (the old code is in my older posts) and it was working fine..ok, I corrected the variable for the buffer but that's for the LCD and it's working..basically in my final working project I will need to have the green LED to turn on for 9 hours after the button is pressed, and then off (and red LED on)..thanks!

I printed out the values in the if statement and yes, they are correct

But, you didn't share the data.

sorry,

so here's my code

  if(rtc.now().unixtime() > (now.unixtime() + 5)){
    Serial.print(rtc.now().unixtime());
    Serial.print(" - ");
    Serial.println(now.unixtime() + 5);
    flag = false;
  }

and this is the result. When I press the button it will stop printing for 5 seconds

1478967508 - 1478967454
1478967508 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967509 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967510 - 1478967454
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967516 - 1478967515
1478967517 - 1478967515
1478967517 - 1478967515

I just realized there's something strange..if I print out the flag variable, which is a boolean, it will print out 3 (and it doesn't change when the button is pressed)....but it should just be 0 or 1 as it's a boolean...I'm really confused now..

  if(rtc.now().unixtime() > (now.unixtime() + 5)){
    Serial.print(rtc.now().unixtime());
    Serial.print(" - ");
    Serial.println(now.unixtime() + 5);
    flag = false;
  }

So, if the statement is true, print the times that determine if it should be true. You didn't learn much, did you?

if I print out the flag variable, which is a boolean, it will print out 3 (and it doesn't change when the button is pressed)

This suggests that you are printing the value in the wrong place, or the switch is not wired to match the code.

How IS the switch wired?

PaulS:
So, if the statement is true, print the times that determine if it should be true. You didn't learn much, did you?

sorry I don't understand what you are saying.

PaulS:
How IS the switch wired?

The switch is working fine, in fact when I press it it will print our "PRESSED". There's a resistor between the ground and the button.

if (digitalRead(button) == HIGH){
      flag = true;
      myNow = rtc.now();
      Serial.println("PRESSED");
  }

also..printing out the flag variable at different steps in the loop() it looks like the code for the LCD is messing it up..I've never seen anything like that...?!

void loop()
{
  Serial.print("STEP 1: ");
  Serial.println(flag); // here is 0

  if (digitalRead(button) == HIGH){
      flag = true;
      myNow = rtc.now();
      Serial.println("PRESSED");
  }

  Serial.print(" - STEP 2: ");
  Serial.println(flag); // here is 0

  if(flag){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
  }else{
      digitalWrite(green, LOW);
      digitalWrite(red, HIGH);
  }
  
  Serial.print(" - STEP 3: ");
  Serial.println(flag); // here is 0
  
  if(rtc.now().unixtime() > (myNow.unixtime() + 5)){
    flag = false;
  }

  Serial.print(" - STEP 4: ");
  Serial.println(flag); // here is 0
  
  sprintf(myBuffer,  "%02d/%02d/%d", myNow.day(), myNow.month(), myNow.year());
  lcd.setCursor(0,0);
  lcd.print( myBuffer );
 
  myBuffer[10] = "";
 
  sprintf(myBuffer,  "%02d:%02d:%02d", myNow.hour(), myNow.minute(), myNow.second());
  lcd.setCursor(0,1);
  lcd.print( myBuffer );

  Serial.print(" - STEP 5: ");
  Serial.println(flag); // here is 164

}

and this is the output I have (the variable is initialized as false)

STEP 1: 0
 - STEP 2: 0
 - STEP 3: 0
 - STEP 4: 0
 - STEP 5: 164
STEP 1: 164
 - STEP 2: 164
 - STEP 3: 164
 - STEP 4: 164
 - STEP 5: 164
STEP 1: 164
 - STEP 2: 164
 - STEP 3: 164
 - STEP 4: 164
 - STEP 5: 164

update: if I comment out all the sprintf code for the LCD, everything (except for the LCD of course) it's working fine.

It's definitely the lcd.print() that is breaking the flag variable. even by printing only one normal line it breaks it.

edit: for some strange reason if I put the lcd.print code in a separate function, everything is working as it should..so I guess I fixed it

edit 2: that's funny now it does not display the right minutes and seconds (it was doing it 2 minutes ago and I didn't touch anything). day, month, year and hour are correct. Minutes are 45 behind the real time and seconds are wrong as well.

void loop(){

  if (digitalRead(button) == HIGH){
      flag = true;
      myNow = rtc.now();
  }

  if(flag){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
  }else{
      digitalWrite(green, LOW);
      digitalWrite(red, HIGH);
  }
  
  if(rtc.now().unixtime() > (myNow.unixtime() + 5)){
    flag = false;
  }

  set_lcd(myNow);

}

void set_lcd(DateTime myNow){
  
 lcd.setCursor(0,0);
 lcd.print(myNow.day());
 lcd.print("/");
 lcd.print(myNow.month());
 lcd.print("/");
 lcd.print(myNow.year());

 lcd.setCursor(0,1);
 lcd.print(myNow.hour());
 lcd.print(":");
 lcd.print(myNow.minute());
 lcd.print(":");
 lcd.print(myNow.second());
 
}

sorry I don't understand what you are saying.

Usually, one would print the value before the if statement, to determine whether or not the if statement was structured correctly. Printing the data inside the body of the if statement doesn't tell you near as much.

  myBuffer[10] = "";

You have a 10 element array, with index values of 0 to 9. You just shit on memory you don't own. You can NOT be sure of ANYTHING that happens when you do this.

What you need to do is put a NULL in position 0, NOT an empty string in position 11 of a 10 element array.

   myBuffer[0] = '\0';
      myNow = rtc.now();

This is still as dumb as a box of rocks. What is wrong with using a name that makes sense. Something like switchPressed?

PaulS:
Usually, one would print the value before the if statement, to determine whether or not the if statement was structured correctly. Printing the data inside the body of the if statement doesn't tell you near as much.

ok, I see what you mean

PaulS:

  myBuffer[10] = "";

You have a 10 element array, with index values of 0 to 9. You just shit on memory you don't own. You can NOT be sure of ANYTHING that happens when you do this.

What you need to do is put a NULL in position 0, NOT an empty string in position 11 of a 10 element array.

   myBuffer[0] = '\0';

I totally removed this buffer :slight_smile:

PaulS:

      myNow = rtc.now();

This is still as dumb as a box of rocks. What is wrong with using a name that makes sense. Something like switchPressed?

it is not a switchPressed. It is a variable to hold the time and its value is stored when the switch is pressed and it makes more sense to me to have it with a time-related name.

However, if you read my latest post I had something strange going on: first, the lcd.print() code was breaking my flag variable for some reason. I moved it into a custom function (calling it in the loop()) and now the condition is working fine. However the minutes and seconds that I am taking from myNow are wrong and can't figure out why..

thanks!

it is not a switchPressed.

It IS the time that the switch was pressed.

it makes more sense to me to have it with a time-related name.

Fine. myNow just does NOT cut it.

I am still not convinced that your switch is wired properly. Add a Serial.print() statement in the if(digitalRead(button) == HIGH){ body, to print the time when the switch is pressed. Make SURE that the time is printed ONLY when you actually press the switch.

ok, here's the code

if (digitalRead(button) == HIGH){
      flag = true;
      myNow = rtc.now();
      Serial.print(myNow.hour());
      Serial.print(":");
      Serial.print(myNow.minute());
      Serial.print(":");
      Serial.println(myNow.second());
  }

It only prints when the button is pressed.
While I press the switch I get this:

21:4:51
21:4:51
21:4:51
21:4:51
21:4:51
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:4:58
21:5:11
21:5:11
21:5:11
21:5:12
21:5:12
21:5:12
21:5:12
21:5:12
21:5:12
21:5:12

which is roughly 45 minutes behind the actual time.
interesting enough, if I run the ds1307 example it will print out the hour wrong, 45 minutes behind.

here's a pic of the circuit (green wire is the arduino pin, orange is positive and white negative): https://1drv.ms/i/s!AqZ0V07JzdDymCaJ-DjNDIvqPI5E

edit: it turns out that the ds1307 wasn't connected to the I2C pins. now it's connected to them but it's still 2.46 minutes behind the real time

thanks

edit: it turns out that the ds1307 wasn't connected to the I2C pins. now it's connected to them but it's still 2.46 minutes behind the real time

Then fix what time the RTC thinks it is.

thanks!
being a very short difference from the real time (it doesn't really make difference for the kind of project I'm doing) I just added 166 seconds to the time before it's displayed.
There's still something weird going on as the seconds are going crazy sometimes (now I pressed the button and it displays 253 as seconds but if I press again it displays the right number). Do you have any idea of why is that?