Don't Copy-Paste: Master Arduino Arrays & Loops with Knight Rider

Don't Copy-Paste: Master Arduino Arrays & Loops with Knight Rider


📑Table of Contents
What You'll Need 5 items
Arduino Uno R3
Buy
Breadboard
Buy
5mm LED
Buy
220Ω Resistor
Buy
Jumper Wires
Buy

Affiliate links help support this site at no extra cost to you.

Welcome to Day 13. On Day 10, we built the “Knight Rider” scanner using hardware (the CD4017 chip). It was a mess of wires. It was rigid.

Today, we are going to build the exact same effect using Software. But we aren’t just going to blink lights. We are going to learn the Golden Rule of Programming: D.R.Y. Don’t Repeat Yourself.

If you find yourself copy-pasting code (like we did in the SOS challenge on Day 11), stop. There is a better way. We are going to master two powerful tools: The Array and The For Loop.

Pop Culture: KITT vs Cylon

This circuit is famous for two reasons.

  1. Knight Rider (1982): A car named K.I.T.T. had a red scanning eye. The producers used incandescent bulbs that faded in and out. It represented “Artificial Intelligence”.
  2. Battlestar Galactica (1978): The Cylons (evil robots) had a similar red eye. The Difference: K.I.T.T.’s eye had a “comet tail” (fading effect). The Cylons had a simpler bouncing dot. Today, we are building the Cylon version (Digital Bouncing). To build the true K.I.T.T. version, we need PWM (Pulse Width Modulation), which we cover in Day 15.

Hardware vs Software Intro Art

The Hardware Setup

We need a row of 6 LEDs to simulate the scanner.

  1. Arduino Uno.
  2. 6 Red LEDs.
  3. 6 Resistors (220Ω - 330Ω).
  4. Connect them to Pins 2, 3, 4, 5, 6, 7.

Why not Pin 0 and 1? Pro Tip: Avoid Pins 0 and 1. They are used for “Serial Communication” (talking to the computer). If you plug LEDs into them, you might block your code uploads. Start at Pin 2.

Breadboard Render of 6 LEDs

Schematic Diagram

The “Bad Code” Approach

Let’s try to write this using what we know (Variables and digitalWrite).

void setup() {
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH); delay(100); digitalWrite(2, LOW);
  digitalWrite(3, HIGH); delay(100); digitalWrite(3, LOW);
  digitalWrite(4, HIGH); delay(100); digitalWrite(4, LOW);
  // ... and so on ...
}

This works. But it is Terrible. Imagine if you had a strip of 100 LEDs. You would have to write 200 lines of setup code. If you wanted to change the speed, you would have to edit 100 delay() lines. We need a machine to do the heavy lifting.

Concept 1: The For Loop (The Drill Sergeant)

A For Loop is a block of code that repeats itself a specific number of times. It is perfect for patterns.

The Anatomy

for (int i = 2; i < 8; i++) {
  // Do something
}

It looks scary, but break it down:

  1. Initialization (int i = 2): “Start a counter variable called ‘i’ at 2.”
  2. Condition (i < 8): “Keep running as long as ‘i’ is less than 8.”
  3. Step (i++): “After each loop, increase ‘i’ by 1.”

So, this loop will run for i=2, i=3, i=4, i=5, i=6, i=7. When i hits 8, the condition (8 < 8) is FALSE, and the loop stops.

Improving Setup

We can replace those 6 lines of setup with 3 lines:

void setup() {
  for (int i = 2; i < 8; i++) {
    pinMode(i, OUTPUT);
  }
}

The Arduino runs this: “Set Pin 2 to Output. Set Pin 3 to Output… Set Pin 7 to Output.” Done.

Safety Note: The Total Current Limit

You might be tempted to turn on ALL the LEDs at once. digitalWrite make them all HIGH? Be Careful. Each pin can handle 20mA. Safe. But the ATMega328P Chip itself has a TOTAL limit of about 200mA. If you turn on 10 LEDs at 20mA each, you hit 200mA. You are at the red line. If you try to drive 20 LEDs? Pop. By scanning them one at a time (like we do in the Knight Rider), we only draw 20mA total. It is safe. It is efficient.

History: Why are C Arrays so dangerous?

You might notice that C++ doesn’t stop you from reading ledPins[100]. Python would scream “IndexError!”. C++ just shrugs and lets you look at memory address 100. Why? Speed. Checking bounds takes time. In 1972, when C was invented, computers were slow. Every machine cycle counted. So they removed the safety rails. It is like a table saw without a guard. It cuts faster, but it demands respect. This design philosophy lives on in Arduino.

For Loop Anatomy Infographic Loops are great if your pins are sequential (2, 3, 4, 5). But what if you wired your LEDs to Pins 2, 5, 9, 10, 11, and 13? The i++ logic fails because the numbers jump around.

Enter The Array. An array is a variable that can hold multiple values. Think of it like a row of mailboxes.

int ledPins[] = { 2, 5, 9, 10, 11, 13 };

The Index (The Address)

To get a value out, we use its Index number in square brackets []. WARNING: Computers start counting at ZERO.

  • ledPins[0] is 2 (The first item).
  • ledPins[1] is 5.
  • ledPins[5] is 13 (The last item).

If you ask for ledPins[6], you get a crash (Index Out of Bounds).

Deep Dive: Memory Safety (The Stack Smash)

In modern languages (Rust, Go), the compiler stops you from reading ledPins[6]. In C++, if you write to ledPins[100], the microcontroller obeys. It walks 100 steps down the memory lane and overwrites whatever is there. That might be:

  1. Another variable (your speed setting).
  2. The Return Address (where the code goes after a function). If you overwrite the Return Address, the CPU jumps to a random location and crashes. This is called Stack Smashing. It is how most computer viruses work. Arduino doesn’t have an Operating System to stop you. You have absolute power. Use it wisely.

Array Memory Mailboxes

Index 0 Warning Sign

Project: The Knight Rider (Clean Version)

Let’s combine Arrays and Loops to build the ultimate scanner. We will use pins 2-7.

// Day 13: Knight Rider
int ledPins[] = {2, 3, 4, 5, 6, 7}; // Our hardware map
int pinCount = 6;                   // How many LEDs?
int waitTime = 50;                  // Speed (ms)

void setup() {
  // Use a loop to set all pins to OUTPUT
  for (int i = 0; i < pinCount; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
}

void loop() {
  // 1. Scan Left to Right
  for (int i = 0; i < pinCount; i++) {
    digitalWrite(ledPins[i], HIGH); // Turn On
    delay(waitTime);
    digitalWrite(ledPins[i], LOW);  // Turn Off
  }

  // 2. Scan Right to Left
  // Start at the end (5), go down to start (0)
  for (int i = pinCount - 1; i >= 0; i--) {
    digitalWrite(ledPins[i], HIGH);
    delay(waitTime);
    digitalWrite(ledPins[i], LOW);
  }
}

Code Comparison UI

How it works

  1. Forward Loop: i goes 0 -> 5.
    • When i=0, it turns on ledPins[0] (Pin 2).
    • When i=1, it turns on ledPins[1] (Pin 3).
  2. Backward Loop: i starts at 5 and goes down (i--).
    • When i=5, it turns on ledPins[5] (Pin 7).

If we want to change the speed, we just change int waitTime = 50; to 20. One change updates the entire animation. This is Soft Coding.

Deep Dive: The Off-By-One Error

The most common bug you will write is this: for (int i = 0; i <= 6; i++) In our array of 6 items, the indices are 0, 1, 2, 3, 4, 5. The item at index 6 does not exist. But if you use inclusive <= 6, the loop tries to access ledPins[6]. The Arduino will read whatever random memory garbage is next to your array. It might blink a random pin. It might reset the chip. Rule: Always use < count for zero-indexed arrays. Never <=.

Index Crash Abstract Art

Advanced Challenge: The “Bounce” Logic

The code above has a small visual glitch. It hits the end (Pin 7) and then effectively hits it again immediately when the reverse loop starts. Pin 7 stays on for twice as long. Can you fix it? Hint: Adjust the start/end points of your loops.

  • Forward loop: 0 to 5.
  • Reverse loop: 4 to 1. (Skip the ends on the return trip).

Challenge: The “Code Golf”

Can you write the entire knight rider loop() in fewer than 10 lines? (Hint: You can put a for loop inside another for loop?) Try to make your code as small as possible. But remember: Readability is king. If your code is short but unreadable, you failed.

Advanced Academy: The Meteor Tail Effect

The Knight Rider scanner wasn’t just blinking dots. It had a “Trail”. It faded out. With digital pins (HIGH/LOW), we can’t do that. BUT… if you move your LEDs to PWM pins (3, 5, 6, 9, 10, 11), you can use analogWrite() to change brightness. Imagine an array not of pin numbers, but of Brightness Values. int brightness[] = {255, 128, 64, 32, 10, 0}; As you loop through the LEDs, you can shift these brightness values along the strip. This is complex coding (involving “Array Shifting”), but it creates a fluid, beautiful animation. This is how modern “Neopixel” LED strips work.

Deep Dive: Why does it start at Zero?

Zero-Indexing confuses everyone. Why is the first item “0”? It comes from CPU memory logic. An array is a block of memory. The variable ledPins points to the Start Address of that block. The Index is the Offset.

  • ledPins[0] = Start Address + 0 steps.
  • ledPins[1] = Start Address + 1 step. If we started at 1, the compiler would have to do subtraction (index - 1) every single time it accessed memory. Starting at 0 is faster for the machine. So, we humans simulate the machine.

Advanced Optimization: Loop Unrolling

Sometimes, loops are TOO slow. The computer spends time jumping back to the top of the loop. In extreme high-speed scenarios (like video generation), engineers do Loop Unrolling. Instead of:

for (int i=0; i<4; i++) { doThing(i); }

They write:

doThing(0);
doThing(1);
doThing(2);
doThing(3);

It takes more memory (code space), but runs faster because there is no logic checking i < 4 every time. For regular LEDs? Don’t do this. Use the loop. Readability > Nanoseconds.

Refactoring: The “Before and After”

Let’s appreciate how much cleaner your code is. Before (Day 11 Style): If you wanted to add 4 more LEDs, you would have to:

  1. add 4 pinMode lines.
  2. add 8 digitalWrite lines to the forward loop.
  3. add 8 digitalWrite lines to the backward loop. After (Day 13 Style):
  4. Add numbers to the ledPins array.
  5. Change int pinCount.
  6. Done. The loop logic handles the rest automatically. This is Scalable Code.

The Bill of Materials (BOM)

ComponentQuantityValueNotes
Arduino Uno1R3 or R4The Brain
LEDs6RedThe Scanner
Resistors6220Ω - 330ΩCurrent Limiting
Jumper Wires7M-M6 Signals + 1 GND
Breadboard1Half+Prototyping

Hardware vs Software: The Final Verdict

Let’s compare Day 10 (Hardware) and Day 13 (Software).

FeatureHardware (CD4017)Software (Arduino)
PartsChip, Cap, Resistor, PotJust LEDs
WiringSpaghetti Nightmareclean
FlexibilityRigidInfinite
SpeedAdjust with PotAdjust Variable
PatternLinear onlyAny pattern you can code
Cost$0.50$20.00

Software wins on flexibility. Hardware wins on cost. But for prototyping? Software is King.

Larson Scanner Effect

Troubleshooting

  1. Code won’t upload? You might have used Pin 0/1. Move your LEDs to 2-7.
  2. One LED stays bright? You might have blocked the loop. Check your braces {}.
  3. It blinks randomly? Check your array indices. Are you going out of bounds?

Common Mistakes (Debugging Guide)

Even pros make mistakes with loops. Here are the classics:

  1. The Infinite Loop: for (int i = 0; i > -1; i++) This loop will run forever because i (0, 1, 2…) will ALWAYS be greater than -1. Result: Your Arduino freezes.
  2. The Off-By-One Error: ledPins[6] Remember, if you have 6 items, the last one is [5]. Accessing [6] reads garbage memory. Result: Random behavior.
  3. The “Slow Motion” Bug: Using delay(1000) inside a loop that runs 10 times making the whole animation take 10 seconds. Result: Boring light show.
  4. Variable Scope: Declaring int i inside the loop for (int i...) means you cannot use i outside that loop. It is deleted when the loop finishes.

The Engineer’s Checklist

Before you upload, ask yourself:

  • Did I connect the LEDs to PWM pins if I wanted fading? (Not needed today, but soon).
  • Are my resistors on the Anode or Cathode? (Either works, but be consistent).
  • Did I start my loop at 0?
  • Did I end my loop at < count?
  • Did I remember the delay()? Without it, the LEDs blink so fast they look like they are all ON at once.

The Engineer’s Glossary (Day 13)

  • Array: A data structure that holds a list of items of the same type.
  • Index: The position number in an array (Starts at 0).
  • For Loop: A control structure for repeating code.
  • Iteration: One single pass through a loop.
  • D.R.Y.: Don’t Repeat Yourself. A core coding principle.
  • Increment (++): Add one to a variable.
  • Decrement (--): Subtract one from a variable.

Conclusion

You have leveled up. You are no longer writing instructions line-by-line. You are writing rules. “Do this to every pin in the list.” “Run this 50 times.” You are leveraging the computer’s ability to do boring tasks quickly.

Tomorrow, we add senses. We will learn about Analog Inputs. We will hook up a Potentiometer (a knob) to control the speed of our Knight Rider scanner real-time, just like we did in Day 10… but with code.

See you on Day 14.

Comments