Coding help for Arduino Light Sequence

Hi,

I have a small circuit that uses a Nano and I need to program a light up sequence. What I want to happen is when a button is in the on position, it lights up an led but I want it to flash on and off before it stays illuminated (its meant to mimic an engine turning on).

I have written some code so the sequencing is already sorted but the issue I have is that it just starts doing the loop over and over without pushing the button. It stays illuminated like I want after holding the button but I just cant get it stay off when the button isnt pressed.

Here is the code I have:

void setup()
{
  pinMode(2, INPUT); // button
  pinMode(13, OUTPUT); // LED
  digitalWrite(13, LOW);
  
}

int pinState = LOW;

void loop()
{
  int newState = digitalRead(2);
  if (newState != pinState) // button state differs from last recorded state?
  {
    pinState = newState;
    if (pinState == HIGH) // button newly pressed?
     delay(1000);
    digitalWrite(13, pinState);
    delay(50);
    digitalWrite(13, LOW);
    delay(50);
    digitalWrite(13, HIGH);
    delay(50);
    digitalWrite(13, LOW);
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(300);
    digitalWrite(13, pinState);
    delay(500);
  }
}

I am not experienced with coding so please be gentle. I realise this is probably pretty ugly code but....yeah.

Thanks for your help!

how is the button wired ? does it bounce ?

The one I have is just a simple push button like this one.

The plan is to actually use a DPST switch that self-latches like this one.

OK they do bounce.

have you read tutorials on buttons?

I'd suggest you use one of the numerous button library such as OneButton or Toggle or EasyButton or Bounce2, ... to make your coding easier.

also from a code structure perspective you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

look this over
corrected

const byte PinBut  = 2;
const byte PinLed  = LED_BUILTIN;       // 13

byte butState;

bool Run;

unsigned long msecPeriod;
unsigned long msec0;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();
    if (Run)  {
        if (msec - msec0 >= msecPeriod)  {
            msec0      += msecPeriod;
            msecPeriod  = 0.85 * msecPeriod;
            digitalWrite (PinLed, ! digitalRead (PinLed));
        }
    }

    int but = digitalRead (PinBut);
    if (butState != but)  { // state change
        butState  = but;    
        delay (20);         // debounce
        if (LOW == but)     // pressed
            Run = ! Run;
        if (Run)  {
            msecPeriod = 500;
            Serial.println (msecPeriod);
        }
    }
}


void setup ()
{
    Serial.begin (9600);

    pinMode (PinBut, INPUT_PULLUP); // enable pullup, but wired to ground
    butState = digitalRead (PinBut);

    pinMode (PinLed, OUTPUT);
    digitalWrite (PinLed, LOW);
}

Sorry, I'm probably missing something but I cant see whats changed. Still does the same thing

updated

After trying a few unreliable ways to poll a bushbutton, this is what I learned to use... It also calls a function to read the button, so I only need to insert the function call into the main sketch.

byte buttonPin = 2;
bool currentButtonState, lastButtonRead; // "is pressed" and "was pressed"
unsigned long timer; // debounce start time
unsigned long timeout = 50; // debounce length
unsigned long buttonCounter;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP); // pin to button (N.O.) to GND
}

void loop() {
  readButton();
}

void readButton() {
  bool currentButtonRead = digitalRead(buttonPin);             // read button pin

  if (currentButtonRead != lastButtonRead) {                    // if button pin changes...
    timer = millis();                                           // ...start a timer
    lastButtonRead = currentButtonRead;                         // ... and store current state
  }
  
  if ((millis() - timer) > timeout) {                           // if button change was longer than debounce timeout
    if (currentButtonState == HIGH && lastButtonRead == LOW) {  // ... and State is "NOT pressed" while Button "IS PRESSED"
      //==================================================
      digitalWrite(LED_BUILTIN, HIGH);                          // The button was pressed...
      showButton(buttonPin, ++buttonCounter);;                  // Put actions or function calls here
      digitalWrite(LED_BUILTIN, LOW);
      //==================================================
    }
    currentButtonState = currentButtonRead;                     // update button state
  }
}

void showButton(int pin, int count) {
  Serial.print("pin ");
  Serial.print(pin);
  Serial.print(" count ");
  Serial.println(count);
}

a simple delay of 20 msec works for me, unless you having a higher performance real-time application

why bother reading the button before checking if the time has expired

I do not understand what you are seeing. Comments are on the right.

I have made some changes to your code (button wiring, missing pair of brackets). Tried not to change it too much. Only a button press is needed now.

Take a look if this is what you wanted:

There's room for improvements.

there's nothing to do until the timer expires

byte buttonPin  = A1;
byte buttonPin2 = A2;
bool lastButtonRead;
bool but2state;

unsigned long timer;
unsigned long Timeout = 50;
unsigned long buttonCounter;
unsigned long msec;

void readButTmr ()
{
    if (timer && (msec - timer) < Timeout)
        return;                         // nothing to do until timer expires

    timer = 0;                          // disable timer
    bool but = digitalRead(buttonPin);
    if (lastButtonRead != but) {
        lastButtonRead = but;

        if (LOW == but)
            showButton(buttonPin, ++buttonCounter);

        timer = msec ? msec : 1;          // not zero
    }
}

void readButDly ()
{
    bool but = digitalRead (buttonPin2);
    if (but2state != but) {            // state change
        but2state = but;
        delay (Timeout);                    // debounce

        if (LOW == but)                     // pressed
            showButton(buttonPin, ++buttonCounter);
    }
}

void showButton(int pin, int count) {
    Serial.print("pin ");
    Serial.print(pin);
    Serial.print(" count ");
    Serial.println(count);
}

void loop()
{
    msec = millis ();

    readButTmr ();
    readButDly ();
}

void setup() {
    Serial.begin(115200);

    pinMode(buttonPin,  INPUT_PULLUP);
    lastButtonRead = digitalRead (buttonPin);

    pinMode(buttonPin2, INPUT_PULLUP);
    but2state = digitalRead (buttonPin2);
}

THX for the two way to do it demo. Please see the edits to one your functions below.

I don't understand a need to "turn off" the timer. Not doing would eliminate the need to test that it is "on". And no need to use the ternary operator to ensure proper function of the timing mechanism. As far as I can think it through, you have that just so you can use zero as a flag value meaning the timer is "off".

The result is more than needs to be thought about. The function with changes appears to perform identically. I may be testing inadequately or maybe not waiting 49.7 days (or whatever it is) to see that the millis() rollover is handled correctly. Or something.

Aside from style differences, the algorithm is the one I use alla time for buttons. If there is some good reason to do what you did I need to know it. If not, why not switch to less code and fewer things anyone needs to figure out when reading it?

Besides the general advice to not overload the function of a variable. You wanna turn on and off something, use a variable that is the state of the timer.

void readButTmr ()
{
//    if (timer && (msec - timer) < Timeout)
    if (msec - timer < Timeout)
        return;                         // nothing to do until timer expires

//    timer = 0;                          // disable timer
    bool but = digitalRead(buttonPin);
    if (lastButtonRead != but) {
        lastButtonRead = but;

        if (LOW == but)
            showButton(buttonPin, ++buttonCounter);


        timer = msec; // ? msec : 1;          // not zero
    }
}

TIA

a7

Hi everyone,

Did some tinkering, even had some help from AI and this is what I came up with. DOes exactly what I wanted, even managed to add a dimm when I release the button.

const int buttonPin = 2;  // Pin connected to the button
const int ledPin = 9;     // Pin connected to the flashing LED (PWM-capable pin)
const int alwaysOnLedPin = 8; // Pin connected to the always-on LED

bool buttonState = false;    // Current state of the button
bool lastButtonState = false; // Last state of the button
bool ledFlashingDone = false; // Flag to track if flashing is completed
bool dimming = false;         // Flag to track if dimming is in progress
unsigned long releaseTime = 0; // To store the time when the button was released
unsigned long dimmingStartTime = 0; // To store the time when dimming should start
unsigned long flashStartTime = 0; // To store the time when the flashing starts

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);    // Set button pin as input with internal pull-up resistor
  pinMode(ledPin, OUTPUT);             // Set flashing LED pin as output
  pinMode(alwaysOnLedPin, OUTPUT);     // Set always-on LED pin as output
  
  digitalWrite(alwaysOnLedPin, HIGH);  // Turn on the always-on LED
  digitalWrite(ledPin, LOW);           // Ensure flashing LED is off at the start
}

void loop() {
  buttonState = digitalRead(buttonPin); // Read the current state of the button

  if (buttonState == LOW) { // Button is pressed
    if (!ledFlashingDone) {
      flashStartTime = millis();
      ledFlashingDone = true;
      dimming = false; // Reset dimming flag
    }

    unsigned long elapsedTime = millis() - flashStartTime;

    // Execute the flashing sequence based on timing
    if (elapsedTime < 1000) {
      // Wait for 1 second before flashing starts
      digitalWrite(ledPin, LOW);
    } else if (elapsedTime < 1050) {
      digitalWrite(ledPin, HIGH); // LED on for 50 ms
    } else if (elapsedTime < 1100) {
      digitalWrite(ledPin, LOW);  // LED off for 50 ms
    } else if (elapsedTime < 1150) {
      digitalWrite(ledPin, HIGH); // LED on for 50 ms
    } else if (elapsedTime < 1250) {
      digitalWrite(ledPin, LOW);  // LED off for 100 ms
    } else if (elapsedTime < 1350) {
      digitalWrite(ledPin, HIGH); // LED on for 100 ms
    } else if (elapsedTime < 1650) {
      digitalWrite(ledPin, LOW);  // LED off for 300 ms
    } else if (elapsedTime < 2150) {
      digitalWrite(ledPin, HIGH); // LED on for 500 ms
    }
  } else if (ledFlashingDone && !dimming) {
    // Button was just released and flashing is done
    if (millis() - releaseTime > 2000) { // Check if 2 seconds have passed
      // Wait 2 seconds before starting dimming
      dimmingStartTime = millis(); // Record when dimming should start
      dimming = true;
    } else {
      releaseTime = millis(); // Update release time to track when button was released
    }
  }

  if (dimming) {
    // Gradually dim the LED over 1 second after the delay
    unsigned long elapsedTime = millis() - dimmingStartTime;
    if (elapsedTime < 1000) {
      int brightness = map(elapsedTime, 0, 1000, 255, 0);
      analogWrite(ledPin, brightness);
    } else {
      // After dimming, keep LED off and reset flags
      analogWrite(ledPin, 0);
      ledFlashingDone = false;
      dimming = false;
    }
  }

  lastButtonState = buttonState; // Update last button state
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.