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
oak:tutorials:advanced-leds [2016/03/23 12:19]
jwhendy
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 =====
  
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(8, 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