Difference between revisions of "Tutorials/Arduino Projects/Mobile Robotics/BoeBot/How to Dim an LED"

From ROBOTC API Guide
Jump to: navigation, search
(What is PWM)
(What is PWM)
Line 4: Line 4:
 
=== What is PWM ===
 
=== What is PWM ===
 
{{Main|Tutorials/Arduino_Projects/Additional_Info/PWM}}
 
{{Main|Tutorials/Arduino_Projects/Additional_Info/PWM}}
 +
 
PWM works by turning the circuit on and off very rapidly. By adjusting the ratio of the time on and the time off, it is possible to adjust the brightness of the LED. This ratio is called the Duty-Cycle and is the percentage of time the output is high with respect to the time of one cycle (when the output goes high then low then back to high). If the Duty-Cycle is 100% then the output is high all the time and thus the LED would be a full brightness. If the Duty-Cycle is 0%, the output is off all the time, so the LED would just be off. Now if the Duty-Cycle is set to 50%, the output is on 50% of the time and off the other 50%. In this setup, the LED would appear be at 50% of its full brightness, an thus appears to be dimmed. This works by basically averaging the time on with the time off.
 
PWM works by turning the circuit on and off very rapidly. By adjusting the ratio of the time on and the time off, it is possible to adjust the brightness of the LED. This ratio is called the Duty-Cycle and is the percentage of time the output is high with respect to the time of one cycle (when the output goes high then low then back to high). If the Duty-Cycle is 100% then the output is high all the time and thus the LED would be a full brightness. If the Duty-Cycle is 0%, the output is off all the time, so the LED would just be off. Now if the Duty-Cycle is set to 50%, the output is on 50% of the time and off the other 50%. In this setup, the LED would appear be at 50% of its full brightness, an thus appears to be dimmed. This works by basically averaging the time on with the time off.
 
PWM has several other interesting properties that will be discussed in later sections.
 
PWM has several other interesting properties that will be discussed in later sections.

Revision as of 14:09, 7 June 2012

How to Adjust the Brightness

While being able to turn LEDs on and off is great, there are times when it might be desirable to have various levels of brightness. This could be achieved using multiple pins and resistors with various resistances and thus adjust the current and voltage flowing through the LED. However, this method requires additional components and thus would cost more money. This method would also make the circuit more complex and would limit you to preset levels. Since these are problems that we want to avoid, you may be asking if there is another way to dim LEDs. Fortunately there is. The method is called Pulse-Width Modulation, or PWM for short.

What is PWM

PWM works by turning the circuit on and off very rapidly. By adjusting the ratio of the time on and the time off, it is possible to adjust the brightness of the LED. This ratio is called the Duty-Cycle and is the percentage of time the output is high with respect to the time of one cycle (when the output goes high then low then back to high). If the Duty-Cycle is 100% then the output is high all the time and thus the LED would be a full brightness. If the Duty-Cycle is 0%, the output is off all the time, so the LED would just be off. Now if the Duty-Cycle is set to 50%, the output is on 50% of the time and off the other 50%. In this setup, the LED would appear be at 50% of its full brightness, an thus appears to be dimmed. This works by basically averaging the time on with the time off. PWM has several other interesting properties that will be discussed in later sections.

PWM on a Microcontroller

Due to the high frequency that PWM operates at, to get an accurate signal using code would basically prevent you from doing anything else with the chip. To eliminate this problem, chip manufacturers included hardware to generate the PWM signal. However not every I/O pin supports PWM output. For the Arduino UNO, only digital pins 3, 5, 6, 9, 10, and 11, support it. luckily, ROBOTC has a tab in the Motors and Sensors Setup window that lists the pins that can me used. ROBOTC also handles all of the complex options that need to be set for the hardware PWM to work.

Programming

In this code, we want the LEDs to dim in and out over 10 seconds.

Configure ROBOTC

Again we need to start with a new source code file, and to tell ROBOTC which Arduino board we are using. Now we need to configure the pins by going into the Motors and Sensors Setup. First we will tell ROBOTC that we have the Parallax Boe Bot Shield attached. Up to this point everything is the same as for the flashing LED configurations. In order to be able to set PWM output we need to configure pins 5 and 6 each as a Variable Intensity LED. To do this we go into the Motors tab, not the Digital 0-13 tab. We want to configure motor_5 and motor_6, which map to digital pins 5 and 6 respectively. Give motor_5 the name "led1" and motor_6 the name "led2". Now set the type of both to Variable Intensity LED and click OK.

Pins 5 and 6 configured for LED PWM

The file should have the following code at the top.

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldParallaxBoeBot)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Motor,  motor_5,         led1,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl5, None)
#pragma config(Motor,  motor_6,         led2,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl6, None)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

Programming task main()

First let us add task main() to the code. now it is time to program the desired behaviors.

To tell the Arduino what Duty-Cycle to output to led1 for example,

motor[led1] = level;

is used with level being the Duty-Cycle from 0 to 127, with 0 mapping to 0% and 127 mapping to 100%. To make the dim in and out, we will have the code slowly step the values up and down over time. For demonstration purposes we will increase or decrease the Duty-Cycle by 10% (level value: 12.7) every 500ms. Doing the math, we get the following values.

Time (ms) led1 value led2 value
0 127 0
500 114 13
1000 102 25
1500 89 38
2000 76 51
2500 64 64
3000 51 76
3500 38 89
4000 25 102
4500 13 114
5000 0 127
5500 13 114
6000 25 102
6500 38 89
7000 51 76
7500 64 64
8000 76 51
8500 89 38
9000 102 25
9500 114 13

Combining the times and values, with the commands to set the outputs and the pauses and you get

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldParallaxBoeBot)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Motor,  motor_5,         led1,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl5, None)
#pragma config(Motor,  motor_6,         led2,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl6, None)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
 
task main()
{
  while(true) //repeat indefinitely
  {
    motor[led1] = 127;
    motor[led2] = 0;
    wait1Msec(500);
 
    motor[led1] = 114;
    motor[led2] = 13;
    wait1Msec(500);
 
    motor[led1] = 102;
    motor[led2] = 25;
    wait1Msec(500);
 
    motor[led1] = 89;
    motor[led2] = 38;
    wait1Msec(500);
 
    motor[led1] = 76;
    motor[led2] = 51;
    wait1Msec(500);
 
    motor[led1] = 64;
    motor[led2] = 64;
    wait1Msec(500);
 
    motor[led1] = 51;
    motor[led2] = 76;
    wait1Msec(500);
 
    motor[led1] = 38;
    motor[led2] = 89;
    wait1Msec(500);
 
    motor[led1] = 25;
    motor[led2] = 102;
    wait1Msec(500);
 
    motor[led1] = 13;
    motor[led2] = 114;
    wait1Msec(500);
 
    motor[led1] = 0;
    motor[led2] = 127;
    wait1Msec(500);
 
    motor[led1] = 13;
    motor[led2] = 114;
    wait1Msec(500);
 
    motor[led1] = 25;
    motor[led2] = 102;
    wait1Msec(500);
 
    motor[led1] = 38;
    motor[led2] = 89;
    wait1Msec(500);
 
    motor[led1] = 51;
    motor[led2] = 76;
    wait1Msec(500);
 
    motor[led1] = 64;
    motor[led2] = 64;
    wait1Msec(500);
 
    motor[led1] = 76;
    motor[led2] = 51;
    wait1Msec(500);
 
    motor[led1] = 89;
    motor[led2] = 38;
    wait1Msec(500);
 
    motor[led1] = 102;
    motor[led2] = 25;
    wait1Msec(500);
 
    motor[led1] = 114;
    motor[led2] = 13;
    wait1Msec(500);
  }
}

Incrementing using a For Loop

You may be thinking that it seems a little silly to write all that code to increment the LED brightness. Fortunately, it is possible to use a for loop to make the code shorter more consise, and some may even say simpler.

#pragma config(CircuitBoardType, typeCktBoardUNO)
#pragma config(PluginCircuitBoard, typeShieldParallaxBoeBot)
#pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0)
#pragma config(Motor,  motor_5,         led1,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl5, None)
#pragma config(Motor,  motor_6,         led2,          tmotorVariableIntensityLED, openLoop, reversed, IOPins, dgtl6, None)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
 
task main()
{
  while(true) //repeat indefinitely
  {
    for(int i=0; i < 10; i++) {
      motor[led1] = 127 - (127 * i / 10);
      motor[led2] = (127 * i / 10);
      wait1Msec(500);
    }
 
    for(int i=0; i < 10; i++) {
      motor[led1] = (127 * i / 10);
      motor[led2] = 127 - (127 * i / 10);
      wait1Msec(500);
    }
  }
}