led chaser without using delay - Page 1
Forum section: electronics / beginners

author: plavelle2k20
author_rank: Newbie
timestamp: November 18, 2020, 08:13:34 pm
content: Hi,I'm trying to do an LED chaser sketch without using delay. I have 3 leds and want to light them from 1 to 3 sequentially with a 1 second delay between each transition. When the user presses a switch, I want to reverse the sequence of the LED's from 3 to 1I've tried this a number of ways, but the way I'm currently trying is giving me random results with the LED's. Sometimes led1 stays on for 3 seconds, then it goes from led1 to led3 then to led2. My sketch is below.I thought that I needed seperate variables for previousMillis (one for each transition of the LED's) but I've tried that and had no luck.Any help or advice appreciated.Code:#include <Arduino.h>/*Lights 3 LED's in a chasing pattern from 1 to 3. Pressing the switch causes theLED's to chase in the opposite direction.*/unsigned long previousMillis; // last the led was updated in millisecondsunsigned long currentMillis; // Current time the led was updated in milliseconds//unsigned long previousMillis2;//unsigned long previousMillis3;unsigned long changeInterval = 1000; // rate at which to change between led's in millisecondsunsigned long lastChangedTime; // time of the last led transitionclass Led {byte ledPin; //Pin of the ledbyte ledState; //current state of the led//constructorpublic:Led(byte ledpin){ledPin = ledpin;init(); //setup the pin for the led}void init(){// set up the input/output pinspinMode(ledPin, OUTPUT);off(); // start the led in a LOW state (off) by calling the off() method}void off(){//turn the led offdigitalWrite(ledPin, LOW);ledState = LOW;}void on(){//turn the led ondigitalWrite(ledPin, HIGH);ledState = HIGH;}byte GetState(){return(ledState);}};class Switch {byte switchPin; //Pin the switch is connected tobyte switchState; // current state of the switchbyte lastSwitchState; // last known state of the switchunsigned long debounceDelay; // Number of milliseconds to wait before considering a button press validunsigned long lastDebounceTime; // last time stored in the debounce timer in millisecondsunsigned long currentDebounceTime; //Current debounce time in millisecondspublic:Switch(byte pin, unsigned long debounceDelay){switchPin = pin;lastSwitchState = LOW;init(); // call init() to setup switch pin}void init(){pinMode(switchPin, INPUT);update(); // call update() method to get the state of the switch}void update(){// see if the button has been pressed and released and do the debouncing// read the state of the switch pin into a local variablebyte reading = digitalRead(switchPin);//get current time for debouncing timercurrentDebounceTime = millis();// check to see if the button was pressed (LOW to HIGH transition)// and we've waited long enough since the last press to avoid any noiseif(reading != lastSwitchState){//reset the debouncing timerlastDebounceTime = millis();}if ( (currentDebounceTime - lastDebounceTime) > debounceDelay){//whatever the reading is at, its been there longer than than the debounce delay//so this will be its actual state//if the button state has changedif(reading != switchState){switchState = reading;// Check if the switch is currently HIGH (i.e The button has been pressed)if(switchState == HIGH){// switch has been pressedswitchState = reading;}}}// save the switch reading. next time through the loop it will be the lastSwitchStatelastSwitchState = reading;}byte getState(){// get the state of the switchupdate();return switchState;}bool isPressed(){// check if the button has been pressedreturn(getState() == HIGH);}};// led objectsLed led1(5);Led led2(4);Led led3(15);//switch objectsSwitch switch1(16, 150);void setup() {// put your setup code here, to run once:}void loop() {currentMillis = millis(); // get current time/*Do it without the delay. This is the jist of what I wantled1.on();delay(1000);led1.off();led2.on();delay(1000);led2.off();led3.on();delay(1000);led3.off();*/if((currentMillis - previousMillis > changeInterval)) {previousMillis = currentMillis; // Save last time we changed the LEDif( led1.GetState() == LOW){led1.on();led2.off();led3.off();}}currentMillis = millis(); // get current timeif((currentMillis - previousMillis) > changeInterval){previousMillis = currentMillis;if(led1.GetState() == HIGH){led1.off();led2.on();led3.off();}}currentMillis = millis(); // get current timeif((currentMillis - previousMillis) > changeInterval){previousMillis = currentMillis;if(led2.GetState() == HIGH){led1.off();led2.off();led3.on();}}currentMillis = millis(); // get current timeif((currentMillis - previousMillis) > changeInterval){previousMillis = currentMillis;if(led3.GetState() == HIGH){led1.off();led2.off();led3.off();}}/*if(led2.GetState() == HIGH){led1.off();led2.off();led3.on();} *//*if(led1changed && currentMillisLed2 - previousMillisLed2 > changeInterval) {previousMillisLed2 = currentMillisLed2; // Save last time we changed the LEDled1.off(); // turn off led1led2.on(); // turn on led2led3.off(); // turn off led3led2changed = true;}if(led2changed && currentMillisLed3 - previousMillisLed3 > changeInterval) {previousMillisLed3 = currentMillisLed3; // Save last time we changed the LEDled1.off(); // turn off led1led2.off(); // turn on led2led3.on(); // turn off led3led2changed = true;}*/}

author: Benta
author_rank: Super Contributor
timestamp: November 18, 2020, 10:02:35 pm
content: I think this must be a record for the amount of code written for three LEDs!I suggest you go back and look at the problem from the start. If I understand correctly, this is what you want:100010001100010---user presses button:001010100001---Is that right?

author: Manul
author_rank: Super Contributor
timestamp: November 18, 2020, 11:09:25 pm
content: That is a lot of code. First, I have a slight suggestion to not write C++ for MCU, better write C (some people disagree and that is ok).I would also suggest to get more involved in defining an actual problem and a clear algorithm for the solution. I see sometimes, that people rush to write code without thinking in depth. We often forget, that problems which we consider as "programming problems" are actually math / logic problems. This pre-coding stage deserves some attention. It may save a lot of time and effort.As an example for inspiration, I just thought now that if I take millisecond counter, divide by 1000, divide result by 3, I will get remainders 0,1,2 changing every second. If I do bitwise XOR with 0,1 and 2 I will get logic false and true to drive LED's in a row. So I coded this idea in C.This is an example loop to drive 3 LED's in a row:Code:while (true) {digitalWrite(PIN_LED1, !(((millis() / 1000) % 3) ^ 0)); // XOR 0 is unnecessary, but added for clearness of ideadigitalWrite(PIN_LED2, !(((millis() / 1000) % 3) ^ 1));digitalWrite(PIN_LED3, !(((millis() / 1000) % 3) ^ 2));}

author: Benta
author_rank: Super Contributor
timestamp: November 18, 2020, 11:47:53 pm
content: +1 @Manul.Very well phrased and to the point. Define the basic problem before coding.

author: plavelle2k20
author_rank: Newbie
timestamp: November 20, 2020, 08:17:42 pm
content: Thank you for all your help and advice, I will aim to plan out the problem better next time. Managed to get it working.