Release 2016.10.2 / Update 2017.12.27

Reproducing Knight Rider LED with Arduino.

“Knight Rider” is a drama which I was looking keen in old days. In this article, I am going to imitate illuminations of the lamp on “Knight 2000”, with arduino.

To make movement of the round trip on the LED

Wiring

kngiht_rider_1_breadboard

Connect Arduino pins to LED. Write a sketch to set the LED on and off in order. Basically, this is all you need. But, this way is too meaningless to be a article. So, I’m going to mention to efficient sketching.

Using ‘For’

knight_rider_motion_anim

Knight 2000 LED light flow lined, has repeatedly come repetitive motion that back and go to the end. So, you can do that with simple method by ‘HIGH’ and ‘LOW’ in ‘digitalWrite’.

digitalWrite(3, HIGH);
delay(100);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
delay(100);
digitalWrite(4, LOW....

This method is troublesome. The repetitive work is simplified by using ‘For’.

It will be simple by ‘array’ and ‘define’ pin number.

#define LED_SIZE 6
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};

Now, you can repeat the work.

#define LED_SIZE 6
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};


void setup() {
  // set pin to OUTPUT & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
}


void loop() {
  // Left to right
  for (byte repeat = 0 ; repeat < (LED_SIZE - 1) ; repeat++) {
    digitalWrite(leds[repeat], HIGH);
    delay(100);
    digitalWrite(leds[repeat], LOW);
  }

  // Right to left
  for (byte repeat = (LED_SIZE - 1) ; repeat > 0 ; repeat--) {
    digitalWrite(leds[repeat], HIGH);
    delay(100);
    digitalWrite(leds[repeat], LOW);
  }
}

“LED_SIZE – 1” is needed for stopping repeat before motion reaches to the end.

knight_rider_led_pin_01

And it will be more simple by combine each repeat once.

Ten times repeat is needed for total 6 LED motion. In short,

Repeat times = ( LED_SIZE-1 ) * 2

“Starting from zero” makes me confused always. Anyway, it will be a circulation following.

pin_circle_02

And if you get to the halfway point, count value need to be ‘decreased’. So I make new argument ‘count’ for that task.

#define LED_SIZE 6
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};


void setup() {
  // set pin & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
}


void loop() {

  for (byte repeat = 0 ; repeat < ((LED_SIZE - 1) * 2) ; repeat++) {
    byte count = 0;

    if (repeat < LED_SIZE)
    {
      count = repeat ;
    } else {
      count = (LED_SIZE - 1) * 2 - repeat ;
    }

    digitalWrite(leds[count], HIGH);
    delay(100);
    digitalWrite(leds[count], LOW);
  }
}

You can separate ‘decrease’ task from ‘increase’ using ‘if’ like this.

By the way, syntax of ‘if’ is omissible.

=(Judgment formula)? value ‘TRUE’ : value ‘FALSE’;

Watch out for colon in the middle, not semicolon. It makes the sketch more simple.

#define LED_SIZE 6
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};


void setup() {
  // set pin & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
}


void loop() {

  for (byte repeat = 0 ; repeat < ((LED_SIZE - 1) * 2) ; repeat++) {

    byte count = (repeat < LED_SIZE) ? repeat : (LED_SIZE - 1) * 2 - repeat ;

    digitalWrite(leds[count], HIGH);
    delay(100);
    digitalWrite(leds[count], LOW);
  }
}

Sketch:motion of LED

summary, so far.

#define LED_SIZE    6
#define LOOP_SIZE (LED_SIZE - 1) * 2
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};


void setup() {
  // set pin to OUTPUT & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
}


void loop() {

  for (byte repeat = 0 ; repeat < LOOP_SIZE ; repeat++) {

    byte count = (repeat < LED_SIZE) ? repeat : LOOP_SIZE - repeat ;

    digitalWrite(leds[count], HIGH);
    delay(100);
    digitalWrite(leds[count], LOW);
  }
}

It is more simple to define total repeat time as “LOOP_SIZE”.

Variable speed

Sketch of LED motion finished. But probably you say it slow. You can change speed by value of delay, of course.

Well, why don’t you make it variable speed?

Wiring

kngiht_rider_2_breadboard

Simply connect a variable resistance to A0.

Reading a variable resistance.

Description of the analog input here will be omitted. For more information is here.

So, I will make a function of returning reasonable number of seconds (20 ms~200ms) by reading of the variable resistor.

int VOL_READ() {
  static int vol_val = 0;
  vol_val = vol_val * 0.9 + analogRead(A0) * 0.1;
  return map(vol_val, 0, 1013, 20, 200);
}

Sketch:Variable speed by a variable resistance

And set the function to the argument.

#define LED_SIZE    6
#define LOOP_SIZE (LED_SIZE - 1) * 2
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};


void setup() {
  // set pin to OUTPUT & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
  pinMode(A0, INPUT);  // set Variable resistor
}


int VOL_READ() {
  static int vol_val = 0;
  vol_val = vol_val * 0.9 + analogRead(A0) * 0.1;
  return map(vol_val, 0, 1013, 20, 200);
}


void loop() {

  for (byte repeat = 0 ; repeat < LOOP_SIZE ; repeat++) {

    byte count = (repeat < LED_SIZE) ? repeat : LOOP_SIZE - repeat ;

    digitalWrite(leds[count], HIGH);
    delay(VOL_READ());
    digitalWrite(leds[count], LOW);
  }
}

Afterimages

Not enough? Yes, there are no afterimages on motion. We have to reproduce the afterimages.

Sketch:LED motion with the afterimages.

There is no difficult to make afterimages if you use ‘analogWrite’.

#define VOL       A0
#define LED_SIZE  6
#define LOOP_SIZE (LED_SIZE - 1) * 2
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};
byte  led_luma [LED_SIZE];


void setup() {
  // set pin to OUTPUT & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
  pinMode(VOL, INPUT);  // set variable resistor
}


int VOL_READ() {
  static int vol_val = 0;
  vol_val = vol_val * 0.9 + analogRead(VOL) * 0.1;
  return map(vol_val, 0, 1013, 20, 200);
}


void loop() {

  for (byte repeat = 0 ; repeat < LOOP_SIZE ; repeat++)
  {
    byte led_now = (repeat < LED_SIZE) ? repeat : LOOP_SIZE - repeat;

    // reduce led luma value
    for (byte i = 0 ; i < LED_SIZE ; i++) led_luma[i] /= 3;
    // set current led luma max
    led_luma[led_now]  = 255;

    for (byte i = 0 ; i < LED_SIZE ; i++)  analogWrite(leds[i], led_luma[i]);

    delay(VOL_READ());
  }
}

Here is a trick. It becomes simple by making array of luma value for each LED. Keeping divide anyway goes to 0 in the end. And give it max value just to leads one. You can change times of afterimage by divide number.

part_previous

Surveillance mode

In the drama, LED can be stopped by surveillance mode button. So, let it make.

Wiring

kngiht_rider_3_breadboard

Check here, if you want to know about “switch function without chattering”.

To memorize on or off, make ‘surveillance_mode’ variable. And modify function ‘VOL_READ’ as ‘EXT_CONTROL’, which contains switch reading.

#define SW 13
#define PUSH_SHORT 700
boolean surveillance_mode = 0;
pinMode(SW, INPUT_PULLUP);

int EXT_CONTROL() {
  long button = 0;
  while(!digitalRead(SW)) button++;
  if(button > PUSH_SHORT) surveillance_mode = !surveillance_mode;

  static int vol_val = 0;
  vol_val = vol_val * 0.9 + analogRead(VOL) * 0.1;
  return map(vol_val, 0, 1013, 20, 200);
}

Sketch:Knight Rider LED

#define VOL        A0
#define SW         13
#define PUSH_SHORT 700
#define LED_SIZE   6
#define LOOP_SIZE  (LED_SIZE - 1) * 2
byte  leds [LED_SIZE] = {3, 5, 6, 9, 10, 11};
byte  led_luma [LED_SIZE];
boolean surveillance_mode = 0;


void setup() {
  // set pin to OUTPUT & LED off
  for (byte i = 0 ; i < LED_SIZE ; i++) {
    pinMode(leds[i], OUTPUT);
    digitalWrite(leds[i], LOW);
  }
  pinMode(VOL, INPUT);  // set variable resistor
  pinMode(SW, INPUT_PULLUP);  // set surveillance switch
}


int EXT_CONTROL() {
  // surveillance button function
  long button = 0;
  while (!digitalRead(SW)) button++;
  if (button > PUSH_SHORT) surveillance_mode = !surveillance_mode;

  // speed read
  static int vol_val = 0;
  vol_val = vol_val * 0.9 + analogRead(VOL) * 0.1;
  return map(vol_val, 0, 1013, 20, 200);
}


void loop() {

  EXT_CONTROL();

  for (byte repeat = 0 ; repeat < LOOP_SIZE ; repeat++)
  {
    if (surveillance_mode)
    {
      byte led_now = (repeat < LED_SIZE) ? repeat : LOOP_SIZE - repeat;

      // reduce led luma value
      for (byte i = 0 ; i < LED_SIZE ; i++) led_luma[i] /= 3;
      // set current led luma max
      led_luma[led_now]  = 255;

      for (byte i = 0 ; i < LED_SIZE ; i++) analogWrite(leds[i], led_luma[i]);
      delay(EXT_CONTROL());
    } else {
      // all led reset and off
      for (byte i = 0 ; i < LED_SIZE ; i++)
      {
        led_luma[i] = 0;
        analogWrite(leds[i], led_luma[i]);
      }
    }
  }
}

This is so simple sketch, isn’t it?

In the end

There are only six pins for PWM on Arduino UNO. So this article is modeled after the spec. But you can control more PWM pins in some other machines. Like ‘Arduino DUE’, ‘Arduino MEGA’ and ‘M0’.

In that case, you can easily expand the function. All you need is change to two arguments. For example, if you want to use 8 pin on ‘Arduino DUE’,

#define LED_SIZE   8
byte  leds [LED_SIZE] = {3, 4, 5, 6, 7, 8, 9, 10};

Max current is 20mA on Arduino. But using transistors lets you use huge LED.

I hope you will try and enjoy it.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


This site uses Akismet to reduce spam. Learn how your comment data is processed.