1

Table of contents:

  1. What I want to achieve
  2. Problem I'm facing
  3. What I've tried
  4. Possible Hypotheses

What I want to achieve

Hi guys, I’m working on a DIY LED Light project to install on my bicycle, where I want to re-create how the actual LED bicycle lights work:

[Stage 1] Press button once: LED lights up forever until button is pressed again [Stage 2] Press button twice: LED blinks forever until button is pressed again [Stage 3] Press button thrice: LED turns off (goes back to original state)

Problem I’m facing

After a bit of research, I know how to work out the code for [Stage 1] (by tracking the current and previous button states.) But I’m unable to make [Stage 2] happen.

What I’ve tried

I’ve tried to instead of tracking the previous and current button states, why not use a counter, i.e:

Counter = 0 (initial) When button is pressed once, Counter = 1 (LED lights up forever until button is pressed again)

When button is pressed one more time, Counter = 2 (LED blinks forever until button is pressed again)

When button is pressed one more time, Counter = 3 (LED switches off, goes back to original LOW state) Counter resets to = 0 again

This is my code below:

const int ledPin = 8;
const int buttonPin = 7;

int buttonState;
int ledState;
int counter = 0;
int newcounter;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    newcounter = counter + 1;
    delay(500);
    if (newcounter != counter) {
      switch (newcounter) {
        case 1: 
            digitalWrite(ledPin, LOW);
            counter = newcounter;
            break;
        case 2: 
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            break;
        case 3: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;
        default: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;       
      }
    }
  }   
}

Possible Hypotheses (Please criticise/correct me if I’m wrong)

A) There is a problem with my code (my programming logic etc)

B) Maybe its not a code/program problem? It could be due to the design of the electric circuit (because I’ve seen videos on YouTube where LEDs can be made to blink using capacitors and transistors. But how does the sequence from Stages 1 to 3 happen in a bicycle LED light? (https://www.youtube.com/watch?v=cXCExzIBNsA)

I’ll be eternally grateful if anyone will be able to help! Thank you!!

7
  • 1
    So what is the question? Does the code "not work" and you are asking "why it does not work"? If it does not work, what does it do then and how do you expect it to work?
    – Justme
    Commented Feb 28, 2022 at 13:23
  • 4
    First of all, you need to get rid of all those calls to delay() and implement it in a non-blocking way (look at BlinkWithoutDelay.ino).
    – Sim Son
    Commented Feb 28, 2022 at 13:37
  • 1
    @SimSon, you can make that an answer :)
    – DamienD
    Commented Feb 28, 2022 at 13:43
  • 1
    does loop() actually "loop"?
    – glen_geek
    Commented Feb 28, 2022 at 13:46
  • 5
    Your problem is that your LED control code is all tangled up with your button press and counter code. Separate them out into completely independent code blocks. One that just increments the counter using a button, and one that displays different things depending on the current counter value.
    – Majenko
    Commented Feb 28, 2022 at 14:04

2 Answers 2

1

you are not stating what results you are getting.

I do see you are not presetting your state variables.
This is always good practice to avoid random startup conditions.

you have logic that will only run when the button is held your if (newcounter != counter) and switch statement only run while the button is pressed. move them outside of the button state check and look to change things ONLY if the button changed.

try this; it will only act on button change not continiously so changes only happen on each press

i will leave you to play with the switch conditions

const int ledPin = 8;
const int buttonPin = 7;

int buttonState, chngButtonState = 0;
int ledState;
int counter = 0;
int newcounter;

void setup() {
  chngButtonState = buttonState; 
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
      buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH && !buttonState == chngButtonState ) {     // read once only if changed button state changed not on every loop
        newcounter = counter + 1;
        delay(500);
        chngButtonState = buttonState;      // mae them equal again
        }                // NOTE I moved 1 of the } from the bottom
        
        if (newcounter != counter) {
          switch (newcounter) {
            case 1: 
                digitalWrite(ledPin, LOW);
                counter = newcounter;
                break;
            case 2: 
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                break;
            case 3: 
                digitalWrite(ledPin, HIGH);
                counter = 0;
                break;
            default: 
                digitalWrite(ledPin, HIGH);
                counter = 0;
                break;       
          }
        }
    }

now just play with the Switch statements to get your results.

pinMode(buttonPin, INPUT);

your button wiring is not clear.

Likely, you have the button connected to VCC and pin 7. You still should have a pulldown resistor from the arduino pin7 to GND to get reliable states.

However; if the button is from a pin7 to GND and no pullup the state will also not change.

If so; change pinMode(buttonPin, INPUT); to pinMode(buttonPin, INPUT_PULLUP); and no external pullup resistor is needed.

0

Think of the "stages" you identified as states or modes of operation, and the button presses cycle between the stages.

Then for "stage 2", you re-write it as a function that doesn't mostly block and idle for 3.5 seconds, but that immediately returns control back to the loop() so you can check for more button presses quickly:

// this function is patterned after the example in
// https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
void stage2(void){
  const unsigned long interval = 500;
  static unsigned long last = 0;
  if(millis() - last >= interval){
    last += interval;
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

and then you switch on stage in the event loop:

      switch (stage) {
        case 0: // idle
            break;
        case 1: // on
            digitalWrite(ledPin, LOW);
            counter = newcounter;
            break;
        case 2: // blinking
            stage2();
            break;
        case 3: // turn off
            digitalWrite(ledPin, HIGH);
            stage = 0;
            break;
        default: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;       
      }
      ...

This switch-case takes almost no time, and returns control to the event loop, so the user interface can respond quickly to other button presses, or check for other tasks.

I didn't re-write the rest of your code, but these are the key differences between your code and what's running in a bike light:

  1. Use state variables and state machines to change the mode of operation.

  2. Avoid trapping the processor in "blocking" code that uses delays(), for(;;), while();, etc... Depend instead on the event loop (loop() in the Arduino), to return control to your functions.

There is a simulation of a Bike Light using these coding patterns on Wokwi at https://wokwi.com/arduino/projects/325075981102482003

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.