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

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
oak:tutorials:advanced-leds [2016/03/23 12:19]
jwhendy
oak:tutorials:advanced-leds [2016/03/23 16:55]
jwhendy
Line 1: Line 1:
-In progress! 
- 
 ===== Oak: Advanced LEDs ===== ===== Oak: Advanced LEDs =====
  
Line 7: Line 5:
 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. 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 ===== ===== Components used =====
Line 68: Line 65:
 </​code>​ </​code>​
  
-=== millis() ===+=== map() ===
  
-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 codehowever 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 codeyour sensor will not be read during that half-second.+The ''​map()'' ​function takes arguments ​for a variable, the variable's rangeand the output range:
  
 +<​code>​map(var,​ var_min, var_max, out_min, out_max)</​code>​
  
-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:+The function creates a linear mapping, just like converting from, say, Fahrenheit to Celsius. We would use map() to do so like this:
  
-<​code>​ +<​code>​map(temp, 32, 212, 0, 100)</​code>​
-// define a variable called "​now"​ and store the current time +
-long now = millis();+
  
-loop() +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:
-+
- +
-  // 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(); +
-    } +
-  }+
  
-}+<​code>​ 
 +                   var 
 +                    | 
 +|var_min|-----------|-----------------|var_max| 
 +|out_min|-----------|-----------------|out_max|
 </​code>​ </​code>​
  
-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 timeIf the stopwatch is less than 1000 (1 second), keep the LED onOnce it'​s ​bigger ​than 1000keep it off. When you hit 2 secondsreset the stopwatch.+We know how the two endpoints of the input and output scales match up since we've told ''​map()''​ the min/max of eachThus, 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 valueIn 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 value32we provided) and receive ​the output in degrees C.
  
-This is the blink sketch using ''​millis()'' ​instead of ''​delay()''​.+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 ===== ===== Circuit =====
Line 123: Line 107:
  
 Here is an example of this setup in real life: 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 =====
Line 186: Line 177:
 === Code: a pulsing sequence === === Code: a pulsing sequence ===
  
-This next example will use all three LEDs, pulsing them from 0 to bright, and then back down... ​with twist! We'll use the ''​millis()'' ​function ​to "​offset" ​them from each other by a half secondDon't worry about how complex ​it looksas we'll walk through it step by step.+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(7, OUTPUT); 
 + 
 +
 + 
 +void loop() 
 +
 + 
 +  // this first loop will run from i = 0 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 0, led_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 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 anotherUpload 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 ===== 
 + 
 +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