This is an old revision of the document!
In progress!
In this lesson, we will build on the blink and basic LED tutorials. We will connect three LEDs to the Oak and control them independently using analogWrite(). The use of a for() loop will also be introduced to show you how to cycle through a range of variables, in this case the brightness and blinking speed of the LEDs.
| Part | Quantity | Identification |
|---|---|---|
| Oak with soldered headers | 1 | |
| Breadboard | 1 | |
| Jumper wires | 7 | |
| 220 ohm resistor | 3 | Red-Red-Brown |
| LEDs, 5mm | 3 | Any color |
Notes: resistors ranging from 100-1,000 ohms are all in a good range. Lower resistance will be brighter, while 1k ohms will produce a slightly dimmer LED.
Any size LED is acceptable; 5mm is simply a recommendation.
A for() loop is a core function commonly used in microcontrollers, as well as programming in general. In layman's terms, the for() loop creates a temporary variable (often an integer, i, is used) with a starting value, a condition in order to know whether or not to keep running, and a way to modify that variable with each pass. Lastly, code is contained within the for() loop, typically based on the temporary variable's current value.
That might seem abstract, so here is a concrete example:
for(int i = 0; i < 5; i = i + 1)
{
Serial.println(i);
}
The format of the for() line is always the same, with it having three parts:
int i = 0: the first part defines a new temporary integer variable called i and sets it's starting value to 0.i < 5: the next part tells the for() loop how to know if it should continue running. This is usually a condition that needs to be TRUE; in our case we're using “less than” (<) 5.i = i + 1: the last part tells the loop how to change i with each pass. In this case, we are defining the new value of i as the old value + 1. This is commonly written as i++, which does the same thing. You could also use i = i - 1, i = i + 10, i = i * 5 or any other equation you choose.
What does this loop do? It prints the value of i each time through the loop until the condition i < 5 is no longer met. Here is a table showing what will occur:
| Time through loop | Value of i | Value printed |
|---|---|---|
| 1 | 0 | 0 |
| 2 | 1 | 1 |
| 3 | 2 | 2 |
| 4 | 3 | 3 |
| 5 | 4 | 4 |
The last time through, i contains the value 4, the code is run (printing out 4 via serial), and then 1 is added to i, making it 5. When the loop goes back to the top i < 5 will be false and the loop will exit. Keep in mind that a for() loop is often contained within the loop() section, so once the for() loop exits, it will go back to the top of loop() and start over. This will begin the for() loop all over again with i reset to 0. Using the above in a loop() section would would print 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0 … again and again.
loop()
{
for(int i = 0; i < 5; i++)
{
Serial.print(i);
}
}
In this lesson, we will introduce the concept of using a timer to decide when to do some action. This has typically been accomplished with delay() in the previous lessons. This is fine for simple code, however when delay() is used the Oak is not able to do anything else for that amount of time. This become a problem when you want to control, say, 3 LEDs independently or especially if you want to read a sensor continuously while doing something else. If you delay(500) in your code, your sensor will not be read during that half-second.
Think of millis() as checking the clock on the Oak periodically to decide if it's time to do something. This let's the Oak multi-task. The millis() function returns the current time in milliseconds, and if we store this in a variable we can check if enough milliseconds have elapsed since the last time. Here's the basic idea:
// define a variable called "now" and store the current time
long now = millis();
loop()
{
// check if it's been less than 1 second since we stored the time
// if so, run the contained code, setting pin 2 to HIGH
if(millis() - now < 1000)
{
digitalWrite(2, HIGH);
}
// if it's been more than a second, turn the LED off
else
{
digitalWrite(2, LOW);
// if it's been more than 2 seconds, reset the time to right now
if(millis() - now > 2000)
{
now = millis();
}
}
}
If you imagine looking at a stopwatch, imagine pressing the start button, which begins counting milliseconds from 0 (current time vs. the time you started the counter). That's what millis() - now is doing: how long has it been since we set now to the current time. If the stopwatch is less than 1000 (1 second), keep the LED on. Once it's bigger than 1000, keep it off. When you hit 2 seconds, reset the stopwatch.
This is the blink sketch using millis() instead of delay().
We will connect this circuit, which is three copies of the basic LED circuit.
Steps:
Here is an example of this setup in real life:
We will begin by controlling 1 led, changing it's on and off time using a for() loop:
// create two integers to hold the on and off delay times
int on_time;
int off_time;
void setup()
{
// set pin 6 to an OUTPUT
pinMode(6, OUTPUT);
}
void loop()
{
// the for() loop will initialize a new temporary variable, i
// it runs until i >= 500, adding 50 each time
for(int i = 50; i < 500; i = i+50)
{
// the on time will equal i (50, 100, 150 ...)
on_time = i;
// the off time will equal 500 - i (450, 400, 350 ...)
off_time = 500 - i;
digitalWrite(6, HIGH);
delay(on_time);
digitalWrite(6, LOW);
delay(off_time);
}
delay(1000);
}
Here is what happens each time the loop runs:
| time through loop | i | on_time | off_time |
|---|---|---|---|
| 1 | 50 | 50 | 450 |
| 2 | 100 | 100 | 400 |
| 3 | 150 | 150 | 350 |
| . | . | . | . |
| . | . | . | . |
| 10 | 450 | 450 | 50 |
When you upload this code, you will see this (other LEDs shown removed for simplicity; we'll use them next!):
This next example will use all three LEDs, pulsing them from 0 to bright, and then back down… with a twist! We'll use the millis() function to “offset” them from each other by a half second. Don't worry about how complex it looks, as we'll walk through it step by step.