User Tools

Site Tools


oak:tutorials:advanced-leds

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
oak:tutorials:advanced-leds [2016/03/22 18:00]
jwhendy created
oak:tutorials:advanced-leds [2016/03/23 21:19]
jwhendy mistake on pin number
Line 1: Line 1:
-In progress! 
- 
 ===== Oak: Advanced LEDs ===== ===== Oak: Advanced LEDs =====
  
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds.png|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds.png?​400}}]]
  
------+In this lesson, we will build on the [[oak:​tutorials:​blink|blink]] and [[oak:​tutorials:​leds|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.
  
 +
 +===== Components used =====
 +
 +^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.
 +
 +===== Concepts =====
 +
 +=== for() loops ===
 +
 +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:
 +
 +<​code>​
 +for(int i = 0; i < 5; i = i + 1)
 +{
 +
 +  Serial.println(i);​
 +  ​
 +}
 +</​code>​
 +
 +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.
 +
 +<​code>​
 +loop()
 +{
 +
 +  for(int i = 0; i < 5; i++)
 +  {
 +    Serial.print(i);​
 +  }
 +
 +}
 +</​code>​
 +
 +=== map() ===
 +
 +The ''​map()''​ function takes arguments for a variable, the variable'​s range, and the output range:
 +
 +<​code>​map(var,​ var_min, var_max, out_min, out_max)</​code>​
 +
 +The function creates a linear mapping, just like converting from, say, Fahrenheit to Celsius. We would use map() to do so like this:
 +
 +<​code>​map(temp,​ 32, 212, 0, 100)</​code>​
 +
 +Some temperature in F is stored in ''​temp'',​ and we feed it into ''​map()''​ which understands the linear relationship between F and C based on the two pairs of min/max values we gave it. One other way to think of map is with two number lines:
 +
 +<​code>​
 +                   var
 +                    |
 +|var_min|-----------|-----------------|var_max|
 +|out_min|-----------|-----------------|out_max|
 +</​code>​
 +
 +We know how the two endpoints of the input and output scales match up since we've told ''​map()''​ the min/max of each. Thus, for some value on the variable'​s scale, ''​map()''​ can translate it to the output scale.
 + 
 +=== constrain() ===
 +
 +What the ''​map()''​ function will //not// do is constrain the value. In fact, if you look at the code for ''​map()''​ (shown at the end of the [[https://​www.arduino.cc/​en/​Reference/​Map|function definition]]),​ you may realize that ''​map()''​ uses these min/max pairs to create the formula for a line! With the temperature example above, we could actually feed in 0 F (even though it's less than the min value, 32, we provided) and receive the output in degrees C.
 +
 +This is where ''​constrain()''​ comes in. It's a pretty simple function: ''​constrain(x,​ min, max)''​. If ''​x''​ is less than ''​min'',​ the function returns ''​min''​. If ''​x''​ is bigger than ''​max'',​ ''​max''​ is returned. We will use this below to set up a constrained output from 0-1023, the min/max used by ''​analogWrite()''​.
 +
 +===== Circuit =====
 +
 +We will connect this circuit, which is three copies of the [[oak:​tutorials:​leds|basic LED]] circuit.
 +
 +[[oak:​tutorials:​oak-3-leds.png|{{oak:​tutorials:​oak-3-leds.png?​500}}]]
 +
 +Steps:
 +
 +  * Insert the 3 LEDs into the breadboard with enough space for their respective resistors as shown below
 +  * Insert the three resistors so that one lead is in the same row as the //long// lead of the LED, and the other end is in a row by itself
 +  * Connect a jumper from pins 6, 7, and 8 of the Oak to each of the rows containing both the LED and resistor leads
 +  * Connect a jumper from the //short// leg of each LED to the ground strip on your breadboard (or to the same row)
 +  * Connect a jumper from a ground pin on the Oak to the ground strip of the breadboard (or the row containing jumpers from each LED's short lead)
 +
 +Here is an example of this setup in real life:
 +
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-back.jpg|{{ http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-back.jpg?​250}}]]
 +
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-side.jpg|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-side.jpg?​236 }}]]
 +
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-front.jpg|{{ http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-leds-front.jpg?​254 }}]]
 +
 +
 +===== Code =====
  
 === Code: for() loop === === Code: for() loop ===
  
-You can also define the delays using variables ​and loops to make things more interesting:+We will begin by controlling 1 led, changing it's on and off time using a ''​for()''​ loop:
  
 <​code>​ <​code>​
-// now we've added two variables ​to hold our +// create ​two integers ​to hold the on and off delay times
-// on and off time delays +
-// the "​int"​ variable is able to hold integer values+
 int on_time; int on_time;
 int off_time; int off_time;
Line 21: Line 129:
 {                ​ {                ​
  
-  pinMode(1, OUTPUT); ​//LED on Oak+  ​// set pin 6 to an OUTPUT 
 +  ​pinMode(6, OUTPUT);
  
 } }
Line 30: Line 139:
   // the for() loop will initialize a new temporary variable, i   // the for() loop will initialize a new temporary variable, i
   // it runs until i >= 500, adding 50 each time   // it runs until i >= 500, adding 50 each time
-  for(int i = 0; i < 500; i = i+50)+  for(int i = 50; i < 500; i = i+50)
   {   {
  
-    // the on time will equal i (0, 50, 100, ...)+    // the on time will equal i (50, 100, 150 ...)
     on_time = i;     on_time = i;
     ​     ​
-    // the off time will equal 500 - i (500, 450, 400, ...)+    // the off time will equal 500 - i (450, 400, 350 ...)
     off_time = 500 - i;     off_time = 500 - i;
  
-    digitalWrite(1, HIGH);+    digitalWrite(6, HIGH);
     delay(on_time);​     delay(on_time);​
   ​   ​
-    digitalWrite(1, LOW);+    digitalWrite(6, LOW);
     delay(off_time);​     delay(off_time);​
   ​   ​
   }   }
 +  ​
 +  delay(1000);​
   ​   ​
 } }
Line 52: Line 163:
 Here is what happens each time the loop runs: Here is what happens each time the loop runs:
  
-^time through loop ^i ^on_time ^off_time| +^time through loop ^i ^on_time ^off_time^ 
-|1|0|0|500+|1|50|50|450
-|2|50|50|450+|2|100|100|400
-|3|100|100|300|+|3|150|150|350|
 |.|.|.|.| |.|.|.|.|
 |.|.|.|.| |.|.|.|.|
 |10|450|450|50| |10|450|450|50|
  
-When the ''​for()''​ loop above runs, ''​i''​ is equal to 0. It calculatesIf ​you upload ​this code, you will see this (click for enlarged view in new tab):+When you upload this code, you will see this (other LEDs shown removed for simplicity; we'll use them next!): 
 + 
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-led-changing-on-time.gif|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-led-changing-on-time.gif?​400}}]] 
 + 
 +=== Code: a pulsing sequence === 
 + 
 +This next example will use all three LEDs, pulsing them from 0 to bright, and then back down... to accomplish this, we will use a ''​for()''​ loop, ''​map()''​, and ''​constrain()''​. Here is the code: 
 + 
 +<​code>​ 
 +// these values will store the brightness for each of our LEDs 
 +int led_1_bright = 0; 
 +int led_2_bright = 0; 
 +int led_3_bright = 0; 
 + 
 +void setup()  
 +{                 
 + 
 +  // set all LED pins to OUTPUT 
 +  pinMode(6, OUTPUT); 
 +  pinMode(7, OUTPUT); 
 +  pinMode(8, OUTPUT); 
 + 
 +
 + 
 +void loop() 
 +
 + 
 +  // this first loop will run from i = until i = 2000 
 +  for(int i = 0; i <= 2000; i++) 
 +  { 
 + 
 +    // these lines map the value of i to the desired brightness range, 0-1023 
 +    // because we've "​offset"​ the min/max of i, we need to constrain 
 +    // the output to make sure it's between 0-1023 
 +    // Can you figure out why the input min/​max'​s are not the same? 
 +    led_1_bright = constrain(map(i,​ 0, 1000, 0, 1023), 0, 1023); 
 +    led_2_bright = constrain(map(i,​ 500, 1500, 0, 1023), 0, 1023); 
 +    led_3_bright = constrain(map(i,​ 1000, 2000, 0, 1023), 0, 1023); 
 + 
 +    // each time through the loop, we write each brightness 
 +    // value to it's corresponding LED 
 +    analogWrite(6,​ led_1_bright);​ 
 +    analogWrite(7,​ led_2_bright);​ 
 +    analogWrite(8,​ led_3_bright);​ 
 + 
 +    // we delay for 1 millisecond,​ otherwise ​this runs at 
 +    // lightning speed! 
 +    delay(1); 
 + 
 +  } 
 + 
 +  // now we repeat the same cycle of i from 0-2000, but with a twist! 
 +  for(int i = 0; i < 2000; i++) 
 +  { 
 + 
 +    // this is the same code except that our output range in map() 
 +    // is reversed! When i is 0led_1_bright ​will be 1023; 
 +    // when i is 1000, it will be 0. This let's us dim the LEDs 
 +    led_1_bright = constrain(map(i,​ 0, 1000, 1023, 0), 0, 1023); 
 +    led_2_bright = constrain(map(i,​ 500, 1500, 1023, 0), 0, 1023); 
 +    led_3_bright = constrain(map(i,​ 1000, 2000, 1023, 0), 0, 1023); 
 + 
 +    analogWrite(6,​ led_1_bright);​ 
 +    analogWrite(7,​ led_2_bright);​ 
 +    analogWrite(8,​ led_3_bright);​ 
 + 
 +    delay(1); 
 +     
 +  } 
 +   
 +
 +</​code>​ 
 + 
 +They key portion of this code are the two loops and the ''​constrain(map(...))''​ lines. Did you figure out why each LED has a different input range for ''​i''?​ It allows us to offset the behavior of each LED.  
 + 
 + 
 +^i range   ^ LED 1  ^ LED 2  ^ LED 3 ^ 
 +|0-500| ramping to half|off|off| 
 +|500-1000|ramping to full|ramping to half|off| 
 +|1000-1500|full on|ramping to full|ramping to half| 
 +|1500-2000|full on|full on|ramping to full| 
 + 
 +The loop then re-runs, but reverses the mappings so that each LED gradually turns off slightly staggered from one another. Upload the code, and see this! 
 + 
 +[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-led-pulse.gif|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​oak-3-led-pulse.gif?​400}}]] 
 +===== Conclusion =====
  
-[[http://digistump.com/​wiki/​_media/​oak/​tutorials/​loop-changing-blink.gif|{{oak:tutorials:​loop-changing-blink.gif?​300}}]]+Congratulations for finishing another tutorial! You've completed a more complex circuit and learned some great tools for future use''​for()'',​ ''​map()'',​ and ''​constrain()''​These are extremely useful functions, and often used to match an input range to an output. We used a loop variable, ''​i'',​ however this would enable you to do something like this:
  
 +  * map the brightness of an LED to the value of a [[http://​digistump.com/​wiki/​oak/​tutorials/​photocell|photocell]]
 +  * map the resistance of a potentiometer to the angle of a servo motor
 +  * map the color of an RGB LED to the output of a [[http://​digistump.com/​wiki/​oak/​tutorials/​onewiretemp|temperature sensor]]
oak/tutorials/advanced-leds.txt · Last modified: 2016/03/23 21:19 by jwhendy