I've read over the forum looking for an answer to my question but because I'm a beginner I suspect I won't even know when I run across it.
I have a nano, I'm using Arduino 2.3.4 on Mac and I've managed to find a sketch that blinks an LED when a button is pressed, then shuts off the LED when it's pressed again and so forth, which is what I want (thanks to UKHeliBob). All I had to do was change line 36 to LOW so the LED was off until the button was pressed.
Ultimately, what I'd like to do is have the LED flash when the button is pressed, shut off when the button is pressed again, and if the button isn't pressed the 2nd time, the LED will just flash for a set amount of time, say 2 hours then return to the off state.
If it helps, what I'm making is a flashing LED for my mailbox that's down the road (rural area) so I know when the mailman has been by. I have it set up now using components like a 555 timer, etc. It's triggered by opening the mailbox door which touches a switch. The led flashes letting me know he's been by and when I open the door again, it stops the flashing. If I'm gone, it simply flashes for 2 hours after he triggers it then shuts off. It works great but I think it'd make a neat project for me to learn Arduino.
I hope this posts correctly:
const byte buttonPin = 2;
const byte ledPin = 5;
boolean flashing = false;
byte currentButtonState = HIGH;
byte previousButtonState = HIGH;
unsigned long currentTime;
unsigned long onoffStarted;
long flashPeriod = 1000;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
currentButtonState = digitalRead(buttonPin);
if (currentButtonState != previousButtonState && currentButtonState == LOW) //button has become pressed
{
flashing = !flashing;
}
previousButtonState = currentButtonState; //save the button state for the next check
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) //if the flash period ended ?
{
digitalWrite(ledPin, !digitalRead(ledPin)); //flip the state of the LED
onoffStarted = currentTime; //save the time when it occured
}
}
else
{
digitalWrite(ledPin, LOW); //force the LED off if not flashing
}
}
Bashed out in 5 minutes on New Year's Eve: no warranty is expressed or implied. Enjoy. Could be much simpler with a button library that handled the debouncing, but as I said, bashed out in 5 minutes.
So far so good! It flashes with the button states. I'm not sure about the timer because I haven't let it run for 2 hours but thanks to you I can "dissect" the sketch you provided to learn what the functions are which will kickstart my journey into Arduino.
Baby step 1: I'm going to go through and see if I can adjust the time so I can check that it shuts off.
your sketch was on the right way, just a few things had to be changed:
/*
Forum: https://forum.arduino.cc/t/help-beginner-with-led-flash-for-specified-time/1337748
Wokwi: https://wokwi.com/projects/418890592487643137
*/
const byte buttonPin = 2;
const byte ledPin = 5;
boolean flashing = false;
byte currentButtonState = HIGH;
byte previousButtonState = HIGH;
unsigned long currentTime;
unsigned long onoffStarted;
long flashPeriod = 1000;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
currentButtonState = digitalRead(buttonPin);
if (currentButtonState != previousButtonState) //buttonstate has changed
{
delay(30); // Poor man's debouncing ... ;-)
previousButtonState = currentButtonState; //save the button state for the next check
if (currentButtonState == LOW) { // Change the flash state only if the change was from HIGH to LOW
flashing = !flashing;
if (!flashing) { // We only need to do this once when going to "not flashing"
digitalWrite(ledPin, LOW); //force the LED off if not flashing
}
}
}
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) //if the flash period ended ?
{
digitalWrite(ledPin, !digitalRead(ledPin)); //flip the state of the LED
onoffStarted = currentTime; //save the time when it occured
}
}
}
I use a very simple way of "debouncing" with a delay(30) everytime the button state changes. Think that's ok for a small sketch with no further time critical functions.
The led can be switched off once when flashing goes to not flashing, no need to do this again and again in loop().
@xfpd Yikes! I had no idea. I'm definitely not bombing my mailman. I actually like the guy! Lol! I did tell him about my mailbox project and since there is no light pollution where we live and we often get our mail after dark, I even put a little SMD "dome light" in the box for him. It also comes on when he opens the door.
@ec2021 Thanks for the information/sketch! I will give that a try, too, and check out your link.
Looking through the sketch that Van_Der_Decken posted, I see the 2UL 60UL 60UL 1000UL line. I read that that is the timer so those are the adjustments I need to make to change the runtime. I just started reading about it so I'm not sure if I need to change all the numbers or just the 2UL. I suspect just the 2UL because I feel like maybe all the other numbers are needed for the program to understand the 2UL.
Edit to add: I went to the Wokwi link. That's really cool! You can see it in action! With your sketch, @ec2021 , I had to change line 8 to "true" so it'd flash. Is that correct? Also, how would I change the timer duration? Again, I barely have any idea what I'm looking at so I certainly could have missed the numbers for it
I looked at @ec2021's project to see how the turning off after two hours was handled and found it missing.
So I added it. I also moved a few things, and put in timed delay-less logic for the button handling. I have no (zero) problem with "poor man's" debouncing but thought you might like to see how to avoid even a usually harmless delay() call.
Wokwi won't let me save the project copy I worked on, dunno why sometimes I can but not always. Here's the code which can be substituted for the original in the simulation.
/*
Forum: https://forum.arduino.cc/t/help-beginner-with-led-flash-for-specified-time/1337748
Wokwi: https://wokwi.com/projects/418890592487643137
*/
const byte buttonPin = 2;
const byte ledPin = 5;
boolean flashing = false;
byte currentButtonState = HIGH;
byte previousButtonState = HIGH;
unsigned long currentTime;
unsigned long onoffStarted;
unsigned long flashPeriod = 777; // half-blink period
unsigned long howLongToFlash = 13000; // shut off after a time (13 seconds here for testing)
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
static unsigned long lastTurnedOn;
static unsigned long lastButtonTime; // for debouncing
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) // if the flash period ended ?
{
digitalWrite(ledPin, digitalRead(ledPin) == LOW ? HIGH : LOW); // flip the state of the LED
onoffStarted = currentTime; // save the time when it occured
}
}
if (flashing && millis() - lastTurnedOn > howLongToFlash) {
flashing = false;
digitalWrite(ledPin, LOW);
}
if (millis() - lastButtonTime < 30) return; // we done. too soon to look at the button again.
currentButtonState = digitalRead(buttonPin);
if (currentButtonState != previousButtonState) // buttonstate has changed
{
previousButtonState = currentButtonState; // save the button state for the next check
lastButtonTime = millis(); // and don't look until the debounce period is elapsed...
if (currentButtonState == LOW) { // Change the flash state only if the change was from HIGH to LOW
flashing = !flashing;
if (!flashing) { // We only need to do this once when going to "not flashing"
digitalWrite(ledPin, LOW); // force the LED off if not flashing
}
else lastTurnedOn = millis();
}
}
}
Tested, works good. For a challenge, modify the part that times out after a long period so it will not chop short the on period of theLED...
The wokwi did have an issue (which seems to be back in some form) around the problem I saw. Oddly even copying and pasting files into a new anonymous project carries something along, I dunno it doesn't work the way it once did.
I don't even remember how to log in, so on the machines I have available just now I'm just another "Anonymous Maker" or whatever.
/*
Forum: https://forum.arduino.cc/t/help-beginner-with-led-flash-for-specified-time/1337748
Wokwi: https://wokwi.com/projects/418894200161797121
Now with a timed reset function ;-)
ec2021
*/
#define TEST
const byte buttonPin = 2;
const byte ledPin = 5;
#ifdef TEST
const unsigned long autoResetAfter {10000UL}; // 10000 ms = 10 sec
#else
const unsigned long autoResetAfter {120 * 60000UL}; // 120 x 60000 ms = 2h (with 60 x 1000 ms = 1 min)
#endif
boolean flashing = false;
byte currentButtonState = HIGH;
byte previousButtonState = HIGH;
unsigned long currentTime;
unsigned long onoffStarted;
unsigned long flashPeriod = 1000;
unsigned long lastFlashStartTime = 0;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
currentButtonState = digitalRead(buttonPin);
if (currentButtonState != previousButtonState) //buttonstate has changed
{
delay(30); // Poor man's debouncing ... ;-)
previousButtonState = currentButtonState; //save the button state for the next check
if (currentButtonState == LOW) { // Change the flash state only if the change was from HIGH to LOW
flashing = !flashing;
if (!flashing) { // We only need to do this once when going to "not flashing"
digitalWrite(ledPin, LOW); //force the LED off if not flashing
} else {
lastFlashStartTime = millis();
}
}
}
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) //if the flash period ended ?
{
digitalWrite(ledPin, !digitalRead(ledPin)); //flip the state of the LED
onoffStarted = currentTime; //save the time when it occured
}
if (millis() - lastFlashStartTime >= autoResetAfter) {
flashing = false;
digitalWrite(ledPin, LOW); //force the LED off if not flashing
}
}
}
@rushl : Just comment the line "#define TEST" out or remove it so that the line
const unsigned long autoResetAfter {120 * 60000UL}; // 120 x 60000 ms = 2h (with 60 x 1000 ms = 1 min)
is used by the compiler. (The UL behind 60000 tells the compiler to use the data type unsigned long for the calculation)
Wow! Thanks again, guys! The Wokwi thing makes this so interesting!
This, coming from someone who was dazzled when I made an led blink yesterday. Lol!
Honestly, though, it is very helpful to see if the changes made do something & I can't wait to tinker around with it! I really appreciate all of you taking the time to help me along.
Click a link on wokwi and wokwi sends an email with a sign-on link.
You do not need to be signed-on to name and save a file with a sharable link. I use one computer not signed-on (to wokwi) and one signed-on. Develop on the not-signed-on and save the good stuff on the signed-on.
One more question. I'd like to add an additional LED that doesn't flash (the domelight in the mailbox). I'd like it to function the same as the flashing LED, minus the flashing. That is to say, I'd like it to come on when the button is pressed, off when pressed again and if no second press, on for the timer duration.
Is this possible or is it considered too many "operations" at once?
This is the sketch I'm using:
const byte buttonPin = 2;
const byte ledPin = 5;
boolean flashing = false;
byte currentButtonState = HIGH;
byte previousButtonState = HIGH;
unsigned long currentTime;
unsigned long onoffStarted;
unsigned long flashPeriod = 777; // half-blink period
unsigned long howLongToFlash = 7200000; // shut off after a time (2 hours hopefully)
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
static unsigned long lastTurnedOn;
static unsigned long lastButtonTime; // for debouncing
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) // if the flash period ended ?
{
digitalWrite(ledPin, digitalRead(ledPin) == LOW ? HIGH : LOW); // flip the state of the LED
onoffStarted = currentTime; // save the time when it occured
}
}
if (flashing && millis() - lastTurnedOn > howLongToFlash) {
flashing = false;
digitalWrite(ledPin, LOW);
}
if (millis() - lastButtonTime < 30) return; // we done. too soon to look at the button again.
currentButtonState = digitalRead(buttonPin);
if (currentButtonState != previousButtonState) // buttonstate has changed
{
previousButtonState = currentButtonState; // save the button state for the next check
lastButtonTime = millis(); // and don't look until the debounce period is elapsed...
if (currentButtonState == LOW) { // Change the flash state only if the change was from HIGH to LOW
flashing = !flashing;
if (!flashing) { // We only need to do this once when going to "not flashing"
digitalWrite(ledPin, LOW); // force the LED off if not flashing
}
else lastTurnedOn = millis();
}
}
}
You'll need another LED and series current limiting resistor (we tend to omit them in the simulator as the LEDs there cannot be burned out).
Placed on another pin that is an OUTPUT.
I hope that much is obvious.
Now… read the code and see every place flashing is turned on or off, and just turn on or off the extra LED at the same time.
Leave the LED that should just be on out of the logic that makes the flashing LED flash.
Alternately, you could just make the new LED follow the variabke which is flashing… probably simpler and clearer, as it would just be another if statement like the three or four that are in the loop at this time.
In case you haven't noticed, you can read code just like reading anything, and reading code you didn't write and figuring out how it works is part of learning.
I have often said no good writer of any kind of writing is not also widely read.
Yes. I note that you placed it inside the exist test for flashing, and it gave me the idea to inhibit terminating the flashing during a flash on period:
if (flashing)
{
currentTime = millis();
if (currentTime - onoffStarted > flashPeriod) //if the flash period ended ?
{
digitalWrite(ledPin, !digitalRead(ledPin)); //flip the state of the LED
onoffStarted = currentTime; //save the time when it occured
}
if (millis() - lastFlashStartTime >= autoResetAfter && digitalRead(ledPin) == LOW ) {
flashing = false;
}
}
There are still a few surprises, a perfectionist or someone coding for NASA would ferret out all the things that just happen the way they do and fix them to do something intentional.
Try making the flash period 4000 milliseconds, e.g. And it still chops off a flash if you stop with the pushbutton, but I can call this a Good Thing as it provides immedaite feedback you've pressed the button.
Ppl make careers out of this kind of stuff. I'm sure we all have a few devices around the house that have quirky behaviour - too little attention to detail during development.
There are actually a number of issues that are not exactly implemented in the online simulator.
Even if you don't connect GND and VCC of certain components to the board the sketch will still work.
Button "bouncing" is simulated but can be switched off (clicking on a button symbol while the Wokwi sketch is not running opens a menu where you can switch "Bounce" on/off
Creating a voltage divider by resistors does not give the expected output:
If I am lazy, I just use a bounce-free button and get on with whatever I am up to, lnowing that if I realize the project it will have to be dealt with.
Also handy are times when I am testing other ppl's code and they have either neglected to debounce the button(s) they are using, or I don't like the look of how they did handle it.
If I turn off the bouncing and the sketch starts to work, or works differently, I know I was right to be suspicious.