1

I am just getting hands on to my Arduino Uno.

I am have finished the blinking light tutorial, managed to read a potentiometer, build a running light with delays and as well a binary counter.

Now I build a small project with 5 LEDs and a potentiometer to configure a running light and change the speed of the running light with the potentiometer.

The LEDs are connected to the pins 13 to 9 and the potentiometer is connected A0 and 5V.

I also managed to program it without a delay function, but I think it is rather ugly.

Is there a better way of doing this like I did it?

int led1 = 13;
int led2 = 12;
int led3 = 11;
int led4 = 10;
int led5 = 9;
//the delay
int pause = 1500;
//count to decide which LEDs are HIGH and which are LOW
int count = 0;
// will store last time LED was updated
unsigned long previousMillis = 0;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(led5, OUTPUT);

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {

  unsigned long currentMillis = millis();

  // read the input on analog pin 0:
  pause = analogRead(A0);
  float voltage = pause * (5.0 / 1023.0);

  // print out the value and teh corresponding voltage you read:
  //Serial.println("Value: %d and Voltage: %f", pause, voltage);
  Serial.print("Value: ");
  Serial.println(pause);
  Serial.print("Volts: ");
  Serial.println(voltage);

  if (currentMillis - previousMillis >= pause) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    if (count == 0) {
      digitalWrite(led1, HIGH);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      digitalWrite(led5, LOW);
    } 
    else if (count == 1){
      digitalWrite(led2, HIGH);
    } 
    else if (count == 2) {
      digitalWrite(led1, LOW);
      digitalWrite(led3, HIGH);
    } 
    else if (count == 3) {
      digitalWrite(led2, LOW);
      digitalWrite(led4, HIGH);
    } 
    else if (count == 4) {
      digitalWrite(led3, LOW);
      digitalWrite(led5, HIGH);
    } 
    else if (count == 5) {
      digitalWrite(led4, LOW);
    } 
    else if (count == 6) {
      digitalWrite(led4, HIGH);
    } 
    else if (count == 7) {
      digitalWrite(led5, LOW);
      digitalWrite(led3, HIGH);
    } 
    else if (count == 8) {
      digitalWrite(led4, LOW);
      digitalWrite(led2, HIGH);
    } 
    else if (count == 9) {
      digitalWrite(led3, LOW);
      digitalWrite(led1, HIGH);
    } 
    else if (count == 10) {
      digitalWrite(led2, LOW);
      digitalWrite(led1, HIGH);
      count = -1;
    }
    count++;
  }
}
  • The 'uglyness' of those repeated if/else statements can be replaced by using a switch statement. – CharlieHanson Jan 15 '16 at 20:24
  • Yes, that would be an idea, but nevertheless, it will be still a very large of code. – LStrike Jan 15 '16 at 20:28
1

You can put the LED pin numbers into an array. After each delay period, turn off the current LED, increment the count, and turn on that LED. For example:

// Sketch re: http://arduino.stackexchange.com/questions/19605/running-light-without-delay-and-a-potentiometer

// Set constants for pins with LEDs
enum { led1 = 13, led2 = 12, led3 = 11, led4 = 10, led5 = 9};

// Make an array with the LED pin numbers
byte ledPins[] = { led1, led2, led3, led4, led5 };

// # of entries in ledPins:
enum { numLeds = sizeof(ledPins) / sizeof ledPins[0]};

//count to track which LEDs are HIGH and which are LOW
int count = numLeds-1;      // Will roll over to 0

// To store last time LED was updated
unsigned long previousMillis = 0;

void setup() {
  // initialize digital pin outputs
  for (byte i=0; i<numLeds; ++i)
    pinMode(ledPins[i], OUTPUT);

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// loop() runs over and over again forever:
void loop() {
  unsigned long currentMillis = millis();
  // read input on analog pin 0:
  int deli = analogRead(A0);
  float voltage = deli * (5.0 / 1023.0);

  // Print out the value and corresponding voltage you read:
  // Serial.println("Value: %d and Voltage: %f", pause, voltage);
  Serial.print("Value: ");
  Serial.println(deli);
  Serial.print("Volts: ");
  Serial.println(voltage);

  if (currentMillis - previousMillis >= deli) {
    // Save the last time we blinked the LED
    previousMillis = currentMillis;

    // Turn off current LED, turn on next one
    digitalWrite(ledPins[count], LOW);
    count = (count+1) % numLeds;
    digitalWrite(ledPins[count], HIGH);
  }
}
  • That is realy a nice piece of code. THX a lot. I will try to midify it a little bit, so that the running light will run from "left to right" and then back from "right to left" – LStrike Jan 15 '16 at 20:18
  • done, awesome, that was fun. – LStrike Jan 15 '16 at 20:57
1

Your Serial.print()s will print on every iteration of loop() even if that iteration doesn't operate on the LEDs. You'll be swamped with output on the terminal.

One improvement I'd make would be to get rid of the counter and the if/else if/.../else if segment. Rotate a bit through a byte variable for as many bit-positions as you have LEDs. Then call a function with that byte, that will set each LED on or off according to the state of its respective bit.

One more improvement can be had if you rotate the bits through bit positions 1 to 5 (in this case) of your byte variable, because you made the fortunate or perhaps intentional assignment of LED's to digital I/Os that are adjacent bits in PORT-B! One single PORTB = [your byte]; statement could set all 5 LEDS simultaneously.

Update: PORTB is a register in the UNO's Atmega328p MCU, one of three (PORTB, PORTC, and PORTD) that connect to all of the I/Os on the UNO (or any other '328 based MCU board). By setting the (up to) 8 bits in one port, a single assembly-language instruction can set that many I/Os simultaneously. It is incredibly efficient. The downside of doing that instead of calling digitalWrite() is that the sketch is then tailored to that particular processor. digitalWrite() uses more program memory and execution time (by a lot, especially when setting multiple I/Os), but keeps your sketch processor independent; digitalWrite() knows which processor it was compiled for and how to translate a Digital I/O number to a physical external pin on that processor, so you don't have to.

For those interested in the low level details of the hardware, they are in the processor's datasheet.

  • The part with the "if/else if" is indeed very ugly. jwpat7 shows a solution wich looks what you have described. Could you please explain what ypu mean with "PORT-B"? – LStrike Jan 15 '16 at 20:19
0

Completed now.

@all: Thank you very much.

@JRobert: Thanks a lot for the very good explanation @jwpat7: Thanks for the code, it helped me a lot.

// Sketch re: http://arduino.stackexchange.com/questions/19605/running-light-without-delay-and-a-potentiometer

// Set constants for pins with LEDs
enum { 
  led1 = 13, led2 = 12, led3 = 11, led4 = 10, led5 = 9};

// Make an array with the LED pin numbers
byte ledPins[] = { 
  led1, led2, led3, led4, led5 };

// # of entries in ledPins:
enum { 
  numLeds = sizeof(ledPins) / sizeof ledPins[0]};

//count to track which LEDs are HIGH and which are LOW
int count = numLeds-1;      // Will roll over to 0

// To store last time LED was updated
unsigned long previousMillis = 0;

//direction forward
boolean forward = true;

void setup() {
  // initialize digital pin outputs
  for (byte i=0; i<numLeds; ++i)
    pinMode(ledPins[i], OUTPUT);

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// loop() runs over and over again forever:
void loop() {
  unsigned long currentMillis = millis();
  // read input on analog pin 0:
  int deli = analogRead(A0);
  float voltage = deli * (5.0 / 1023.0);

  // Print out the value and corresponding voltage you read:
  // Serial.println("Value: %d and Voltage: %f", pause, voltage);
  // Serial.print("Value: ");
  // Serial.println(deli);
  // Serial.print("Volts: ");
  // Serial.println(voltage);

  if (currentMillis - previousMillis >= deli) {
    // Save the last time we blinked the LED
    previousMillis = currentMillis;

    if(forward){
      // Turn off current LED, turn on next one
      digitalWrite(ledPins[count], LOW);
      count = (count+1) % numLeds;
      digitalWrite(ledPins[count], HIGH);

      if(count == numLeds-1 ){
        forward = false;
        count = 0;
      }
    }
    else {
      digitalWrite(ledPins[count + numLeds-1], LOW);
      count = (count - 1) % numLeds;
      digitalWrite(ledPins[count + numLeds-1], HIGH);

      if(count + numLeds-1 == 0){
        forward = true;
        count = 0;
      }
    }
  }
}

enter image description here

  • 1
    You might not realize, but your code still has a "delay" or well, the analogRead function. The function starts the ADC, waits for it to complete and then continues. (This is far below microseconds, but might be crucial) @NickGammon has made an very interesting post about it: gammon.com.au/adc But, you shouldn't care, unless you really want to go beyond the scope of Arduino. Also, you could use a timer + interrupt to change the LED's. Combine these two things, and your program is running at full efficiency, and you could even run other things at the same time, with a minimal delay. – Paul Jan 16 '16 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.