Hi, I'm new to Arduino and just playing around to get a feel for it all.
I made a sample sketch to change the blink pattern of an LED when the selector switch is toggled. I have it working in tinkercad, but right now the sketch will only switch between loops after the current running loop has completed.
How can I make it switch modes as soon as the switch is toggled?
Here's my current code:
// Sketch for testing switch between loops for LED patterns
int buzzerPin = 9;
int pinSwitch = 2;
void setup()
{
pinMode(9, OUTPUT);
pinMode(pinSwitch, INPUT_PULLUP);
// initialize serial communication:
Serial.begin(9600);
}
void loop()
{
if (digitalRead(pinSwitch) == HIGH) {
Serial.println("Mode 1");
loop1();
}
else {
Serial.println("Mode 2");
loop2();
}
}
// primer loop
void loop1() {
digitalWrite(9,HIGH);
delay(500);
digitalWrite(9,LOW);
delay(500);
digitalWrite(9,HIGH);
delay(500);
digitalWrite(9,LOW);
delay(500);
digitalWrite(9,HIGH);
delay(500);
}
//effector loop
void loop2() {
digitalWrite(9,HIGH);
delay(1000);
digitalWrite(9,LOW);
delay(500);
digitalWrite(9,HIGH);
delay(1000);
digitalWrite(9,LOW);
delay(500);
digitalWrite(9,HIGH);
delay(1000);
}
Avoid the ussage of the delay() function. This function blocks the execution of the sketch.
Take a view into the IDE example BlinkWithOutDelay example to get rid of it.
Thanks! This works exactly as I wanted, but now I want to go a little more advanced...
Let's say for mode 1 I want to increase the on time of the LED by 100 ms (M1OnIncrement) for each cycle up to a maximum of 1000 ms (M1MaxOn), and for mode 2 I want to increase the on time of the LED by 1000 ms (M2OnIncrement) for each cycle up to a max of 5000 ms (M2MaxOn), using a default off cycle time of 500 ms for both modes.
It would be even more versatile if I could have a custom default off cycle time for each mode (M1DefaultOff & M2DefauiltOff), but I don't want to ask for too much if that gets really complex.
This was my attempt which seems to work for the most part, but not nearly as neat as what you cooked up and no debounce detection.
// These variables store the flash pattern
// and the current state of the LED
int ledPin = 9; // the number of the LED pin
int pinSwitch = 2;
int ledState = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was updated
long Mode1OnTime = 500; // milliseconds of on-time
int Mode1OnIncrement = 100; // increment on time in milliseconds
int M1OnTimeMax = 1000 - Mode1OnIncrement; // Mode 1 max on time before cycling back to start
long Mode2OnTime = 1000; // milliseconds of on-time
long Mode2OnIncrement = 1000; // increment on time in milliseconds
int M2OnTimeMax = 5000 - Mode2OnIncrement; // Mode 2 max on time before cycling back to start
long DefaultOffTime = 500; // milliseconds of off-time
long M1OnTimeCurr = Mode1OnTime;; // initialize variable for Mode 1 current OnTime incrementing
long M2OnTimeCurr = Mode2OnTime;; // initialize variable for Mode 2 current OnTime incrementing
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(pinSwitch, INPUT_PULLUP);
// initialize serial communication:
Serial.begin(9600);
}
void loop()
{
if (digitalRead(pinSwitch) == HIGH) {
// Serial.println("Mode 1");
mode1();
}
else {
// Serial.println("Mode 2");
mode2();
}
}
void mode1() {
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= M1OnTimeCurr))
{
ledState = LOW; // Turn it off
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
// increment on time up to Max
if((M1OnTimeCurr <= M1OnTimeMax)) {
M1OnTimeCurr = M1OnTimeCurr + Mode1OnIncrement;
}
else
M1OnTimeCurr = Mode1OnTime; // after Max cycle set back to preset
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= DefaultOffTime))
{
ledState = HIGH; // turn it on
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
void mode2() {
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= M2OnTimeCurr))
{
ledState = LOW; // Turn it off
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
// increment on time up to Max
if((M2OnTimeCurr <= M2OnTimeMax)) {
M2OnTimeCurr = M2OnTimeCurr + Mode2OnIncrement;
}
else
M2OnTimeCurr = Mode2OnTime; // after Max cycle set back to preset
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= DefaultOffTime))
{
ledState = HIGH; // turn it on
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
Ok I think I figured out how to make it work with incremental on cycles, based on the code you shared. Here's what I came up with, let me know if I botched anything.
// Sketch for testing switch between loops for LED patterns
unsigned long lastMilli = 0;
int intervalDelay = 500;
byte mode = 0;
unsigned long lastCheck = 0;
int intervalDebounce = 50;
int ledPin = 9; // the number of the LED pin
int pinSwitch = 2;
int ledState = LOW; // ledState used to set the LED
long Mode1OnTime = 500; // milliseconds of on-time
int Mode1OnIncrement = 100; // increment on time in milliseconds
int M1OnTimeMax = 1000 - Mode1OnIncrement; // Mode 1 max on time before cycling back to start
long Mode2OnTime = 1000; // milliseconds of on-time
long Mode2OnIncrement = 1000; // increment on time in milliseconds
int M2OnTimeMax = 5000 - Mode2OnIncrement; // Mode 2 max on time before cycling back to start
long DefaultOffTime = 500; // milliseconds of off-time
long M1OnTimeCurr = Mode1OnTime; // initialize variable for Mode 1 current OnTime incrementing
long M2OnTimeCurr = Mode2OnTime; // initialize variable for Mode 2 current OnTime incrementing
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(pinSwitch, INPUT_PULLUP);
// initialize serial communication:
Serial.begin(9600);
}
void loop()
{
if (millis() - lastCheck >= intervalDebounce) {
lastCheck = millis();
if (digitalRead(pinSwitch) == HIGH) {
if (mode != 1) {
Serial.println("Mode 1");
mode = 1;
}
intervalDelay = 500;
}
else {
if (mode != 2) {
Serial.println("Mode 2");
mode = 2;
}
}
}
switch (mode) {
case 1: mode1(); break;
case 2: mode2(); break;
}
}
// mode 1 pattern
void mode1() {
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (millis() - lastMilli >= M1OnTimeCurr))
{
ledState = LOW; // Turn it off
lastMilli = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
// increment on time up to Max
if((M1OnTimeCurr <= M1OnTimeMax)) {
M1OnTimeCurr = M1OnTimeCurr + Mode1OnIncrement;
}
else
M1OnTimeCurr = Mode1OnTime; // after Max cycle set back to preset
}
else if ((ledState == LOW) && (currentMillis - lastMilli >= DefaultOffTime))
{
ledState = HIGH; // turn it on
lastMilli = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
// mode 2 pattern
void mode2() {
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (currentMillis - lastMilli >= M2OnTimeCurr))
{
ledState = LOW; // Turn it off
lastMilli = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
// increment on time up to Max
if((M2OnTimeCurr <= M2OnTimeMax)) {
M2OnTimeCurr = M2OnTimeCurr + Mode2OnIncrement;
}
else
M2OnTimeCurr = Mode2OnTime; // after Max cycle set back to preset
}
else if ((ledState == LOW) && (currentMillis - lastMilli >= DefaultOffTime))
{
ledState = HIGH; // turn it on
lastMilli = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
toggle mode based on button press, not button state
just made mode2 blink LED quickly
// Sketch for testing switch between loops for LED patterns
unsigned long lastMilli = 0;
int intervalDelay = 500;
byte mode = 0;
unsigned long lastCheck = 0;
unsigned long intervalDebounce = 50;
int ledPin = 9; // the number of the LED pin
int pinSwitch = 2;
int ledState = LOW; // ledState used to set the LED
unsigned long Mode1OnTime = 500; // milliseconds of on-time
unsigned long Mode1OnIncrement = 100; // increment on time in milliseconds
unsigned long M1OnTimeMax = 1000 - Mode1OnIncrement; // Mode 1 max on time before cycling back to start
unsigned long Mode2OnTime = 100; // milliseconds of on-time
unsigned long M1OnTimeCurr = Mode1OnTime; // initialize variable for Mode 1 current OnTime incrementing
unsigned long M2OnTimeCurr = Mode2OnTime; // initialize variable for Mode 2 current OnTime incrementing
unsigned long currentMillis;
byte butLst;
// -----------------------------------------------------------------------------
void loop ()
{
currentMillis = millis ();
byte but = digitalRead(pinSwitch);
if (butLst != but) {
butLst = but;
delay (20); // debunce
if (LOW == but)
mode = !mode;
}
if (mode)
mode1 ();
else
mode2 ();
}
// -----------------------------------------------------------------------------
void mode1 ()
{
if (currentMillis - lastMilli >= M1OnTimeCurr) {
lastMilli = currentMillis;
if (ledState == HIGH) {
ledState = LOW; // Turn it off
// increment on time up to Max
if ((M1OnTimeCurr <= M1OnTimeMax))
M1OnTimeCurr = M1OnTimeCurr + Mode1OnIncrement;
else
M1OnTimeCurr = Mode1OnTime;
}
else
ledState = HIGH; // turn it on
digitalWrite (ledPin, ledState); // Update the actual LED
Serial.print ("mode1: ");
Serial.println (M1OnTimeCurr);
}
}
// -----------------------------------------------------------------------------
void mode2 ()
{
if (currentMillis - lastMilli >= M2OnTimeCurr) {
lastMilli = currentMillis;
digitalWrite (ledPin, ! digitalRead (ledPin));
}
}
// -----------------------------------------------------------------------------
void setup ()
{
pinMode (ledPin, OUTPUT);
pinMode (pinSwitch, INPUT_PULLUP);
butLst = digitalRead (pinSwitch);
Serial.begin (9600);
}
I had a feeling there was a bit of unnecessary redundancy in that code. That's much cleaner, thank you!
You said to toggle mode based on button press rather than state. That's perfect for a momentary push button, but what would you change if using a toggle switch instead?
I want to attach a blue LED to SW pin 1 and tie to 5V rail with a resistor to indicate Mode 1 is active with the SW in the off position and a green LED on SW pin 3 to indicate Mode 2 active. I'm guessing the changes would be very minimal.
For the off duration in both mode 1 and 2 I want to use the intervalDelay var. How would I implement this in the code you provided?
Finally, this code remembers the incremental state each mode was last in, so when the button is pressed it continues from the last known interval. What would need to be changed so that the loop starts over from ModeXOnTime ms?
Here's what I have so far using momentary push button to switch modes: SwitchLed Patterns v3
// Sketch for testing switch between loops for LED patterns v3 (remembers mode state)
unsigned long lastMilli = 0;
int intervalDelay = 500;
byte mode = 1;
unsigned long lastCheck = 0;
int ledPin = 9; // the number of the LED pin
int pinSwitch = 2; // pin to button to GND (use internal pullup)
int ledState = LOW; // ledState used to set the LED
unsigned long M1InitOnTime = 500; // milliseconds of on-time
unsigned long M1OnIncrement = 100; // increment on time in milliseconds
unsigned long M1OnTimeMax = 1000 - M1OnIncrement; // Mode 1 max on time before cycling back to start
unsigned long M2InitOnTime = 1000; // milliseconds of on-time
unsigned long M2OnIncrement = 1000; // increment on time in milliseconds
unsigned long M2OnTimeMax = 5000 - M2OnIncrement; // Mode 2 max on time before cycling back to start
unsigned long M1OnTimeCurr = M1InitOnTime; // initialize variable for Mode 1 current On Time incrementing
unsigned long M2OnTimeCurr = M2InitOnTime; // initialize variable for Mode 2 current On Time incrementing
unsigned long currentMillis;
byte butLst; // last button state
// -----------------------------------------------------------------------------
void loop ()
{
currentMillis = millis ();
byte but = digitalRead(pinSwitch);
if (butLst != but) {
butLst = but;
delay (20); // debounce
if (LOW == but)
mode = !mode;
}
if (mode)
mode1 ();
else
mode2 ();
}
// -----------------------------------------------------------------------------
void mode1 ()
{
if (currentMillis - lastMilli >= M1OnTimeCurr) {
lastMilli = currentMillis; // Remember the time
if (ledState == HIGH) {
ledState = LOW; // Turn it off
// increment on time up to Max
if ((M1OnTimeCurr <= M1OnTimeMax))
M1OnTimeCurr = M1OnTimeCurr + M1OnIncrement;
else
M1OnTimeCurr = M1InitOnTime;
}
else
ledState = HIGH; // turn it on
digitalWrite (ledPin, ledState); // Update the actual LED
Serial.print ("mode1: ");
Serial.println (M1OnTimeCurr);
}
}
// -----------------------------------------------------------------------------
void mode2 ()
{
if (currentMillis - lastMilli >= M2OnTimeCurr) {
lastMilli = currentMillis; // Remember the time
if (ledState == HIGH) {
ledState = LOW; // Turn it off
// increment on time up to Max
if ((M2OnTimeCurr <= M2OnTimeMax))
M2OnTimeCurr = M2OnTimeCurr + M2OnIncrement;
else
M2OnTimeCurr = M2InitOnTime;
}
else
ledState = HIGH; // turn it on
digitalWrite (ledPin, ledState); // Update the actual LED
Serial.print ("mode2: ");
Serial.println (M2OnTimeCurr);
}
}
// -----------------------------------------------------------------------------
void setup ()
{
pinMode (ledPin, OUTPUT);
pinMode (pinSwitch, INPUT_PULLUP);
butLst = digitalRead (pinSwitch);
Serial.begin (9600);
}
if (HIGH == digitalRead(pinSwitch))
mode1 ();
else
mode2 ();
wouldn't intervalDelay be the same as your M1OnTimeCurr?
the only difference between you modes are the min/max times and the increment. couldn't they be variables set by the switch setting and there only be on timer loop?
where are you going with this? what are you trying to learn?
wouldn't intervalDelay be the same as your M1OnTimeCurr ?
Rather than intervalDelay, a more descriptive var would be LEDoffTime.
the only difference between you modes are the min/max times and the increment. couldn't they be variables set by the switch setting and there only be on timer loop?
Yes, I'm sure it could be reduced to that. I'm not skilled enough yet to know how, but the code is very understandable. I used to play with assembly lang and C when I was younger, just got the urge to get back into coding after digging out an old Ardunio.
This is just a little learning project idea I came up with. It's for a game I'm working on where the modes are used to signal team mates as to what activity you're working on.
I really appreciate all the help. What a great community you guys have here!
Yes in that last code that I tried to adapt from what you shared, but in my v2 it's working as I described. Just a lot of unnecessary code as you've shown.
I cleaned up the code a bit and added some serial output: v2 simulation
The code you provided doesn't seem to work as expected. It starts in mode 2 instead of mode 1, with the SW in the off or left position and it doesn't increment the on time. See here: Switch LED Patterns v4