Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.
more >> Pulse Width Modulation or PWM is a term you hear a lot if you are interested in controlling power output using a microcontroller. It has many applications, although one of the most popular amongst hobbyists is controlling the brightness of LEDs. In this tutorial we will cover the basic principles behind PWM and how it can be used for LED brightness control including fading out LEDs rather than just turning them on and off. This article will focus on some of the more specific details of the PIC18F range of microcontrollers; however the techniques and principles are the same for all other microcontroller products. Some microcontrollers include PWM modules which perform all of the hard work for you; however this article focuses on the more universal (and scalable) technique of using interrupts.
Contents
1 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
1 Video Tutorial 2 Introduction 3 Duty-Cycle 4 PWM Resolution 5 Timing the Interrupt 6 Fading the LED 7 Conclusions 8 Files for Download
Video Tutorial
This tutorial is primarily designed as a video tutorial. You can watch the full video on YouTube, please use 780p or 1080p for clearer diagrams:
2 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
Introduction
To control the brightness of an LED you can vary the power which is sent to the LED, for example using a potentiometer (variable resistor), the more power the LED receives the brighter it is, the less power it receives the dimmer it is. Microcontrollers are digital, meaning they only have two power states, on and off. Although it is possible to supply a varying power from a microcontroller (using a Digital to Analogue Convertor (DAC)) this usually requires an additional chip. PWM provides the ability to simulate varying levels of power by oscillating the output from the microcontroller. If, over a short duration of time, we turn the LED on for 50% and off for 50%, the LED will appear half as bright since the total light output over the time duration is only half as much as 100% on. The important factor here is the duration, if we turn the light on and off too slowly the viewer will see the flashing of the LED not a constant light output which appears dimmer. The pulsing width (in this case 50%) is the important factor here. By varying (or modulating) the pulsing width we can effectively control the light output from the LED, hence the term PWM or Pulse Width Modulation.
3 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
When using PWM its important to consider how slowly we can flash the LED so that the viewer does not perceive the oscillation. The eyes inability to see rapid oscillations of light is caused by our persistence of vision which means, in very simple terms, we see the light as on even after it has turned off. This technique is how televisions display a seemingly moving picture which is actually made up of a number of different still frames displayed one after the other very rapidly. The minimum speed of an LED oscillating which can be seen by the human eye varies from person to person. However, for the purposes of this article, we will use a minimum speed of 50Hz, or 50 times per second (the same speed as used by European televisions).
Duty-Cycle
When using PWM there are certain terms which you will come across again and again. The most important term is duty-cycle. The duty-cycle refers to the total amount of time a pulse is on over the duration of the cycle, so at 50% brightness the duty-cycle of the LED is 50%. The cycle itself is measured (usually) in Hertz which gives us the cycles-per-second. So at 50Hz our cycle is 1 second divided by 50 cycles, which is 0.02 seconds. Since we are using such small time measurements its more useful to use microseconds (there are 1,000,000 microseconds in a second), this gives us a cycle duration of 20,000 microseconds which is 50 cycles per second or 50Hz. During the 20,000 microseconds we have to turn the LED either on or off depending on the required duty-cycle so, for example, a 75% duty-cycle requires the pulse to be on for 15,000 microseconds and then off for 5,000 microseconds.
4 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
PWM Resolution
The accuracy with which we can control the duty-cycle is known as the PWM resolution. The higher our PWM resolution is, the more levels of brightness we can display. However, since the duty-cycle is fixed at 50Hz more resolution requires finer timing from the microcontroller. The faster the microcontroller, the smaller durations it can time. Another limiting factor is the code execution, the microcontroller must not only time the interrupt which causes the pulse generation, but also run the code which controls the LED output, which must complete before the next interrupt is called. In addition, you probably want your microcontroller to be performing tasks other than LED PWM brightness control, so there has to be some spare execution time between interrupts to do all of the other more general processing tasks. With PWM control of LEDs the primary advantage of higher PWM resolutions is that it results in a smaller difference between off and the lowest possible brightness from the LED. For example if our duty-cycle is 20,000 microseconds (50Hz) and our resolution is only 10,000 microseconds, the difference between off and the lowest possible brightness will be 50% of the total possible brightness. At a resolution of 2,000 microseconds the difference would be 10% and so on. Overall the PWM resolution dictates the number of brightness levels we can support between completely off (0%) and completely on (100%). Again, the higher the resolution, the more timing accuracy and processing overhead is required.
5 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
For your application the required resolution and overall duty-cycle may vary. Simple displays require very little precision control (and sometimes a little flickering is not the end of the world), for more advanced displays the ability to control levels of brightness might be critical (think of the issue of mixing colours using a RGB LED for example). The trade-off is simple, more control and accuracy requires more and more microcontroller resources. In this article we will focus on an example which supplies a resolution of 1,000 microseconds over a 20,000 microsecond duty-cycle (or 50Hz with steps of 5% giving us 20 levels of brightness). This level of control and accuracy is suitable for many purposes.
6 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
If the Fosc/4 rate is 12,000,000 this means 1 microsecond of time passes for every 12 processor cycles. This means that 1,000 microseconds is equivalent to 12,000 processor cycles. This is important because with a 1:1 prescaler the PICs timers update once every processor cycle (although this is referred to as a 1:1 prescale, it really means no prescale at all). The timers prescaler slows down the rate at which the timers counter updates, with a 1:2 prescaler it updates once every 2 processor cycles, with a 1:4 prescaler it updates once every 4 processor cycles and so on. To use an 8-bit timer (you can use a 16-bit timer also if you like) the maximum period the timer can measure is 256 counts (0-255). Therefore we have to pick a prescaler value which allows us to time 12,000 processor cycles in less than 256 timer ticks. If we use a 1:64 prescaler we require 187.5 timer ticks to measure 1,000 microseconds: 12 processor cycles per microsecond, so 12 * 1000 = 12,000 processor cycles per 1,000 microseconds: 12,000 cycles / 64 (prescale) = 187.5 timer ticks Since we cannot count a half we simply round the figure down to the nearest integer (this means are resulting PWM will not be totally accurate, but for the purpose of controlling LED brightness this is not very critical). The higher prescale value we use, the less accurate the timing becomes. This can be corrected by using a 16-bit timer which allows us to count far more ticks and therefore use a lower prescale value. For a PIC18F4550 this will result in code similar to the following excerpt where the timer0 module is configured, enabled and set to generate a low-priority interrupt:
// Enable interrupts with priority IPEN = 1; // Set up timer0 TMR0IP = 0; TMR0IF = 0; TMR0L = 255 - 187; T0CON = 0b11000101; TMR0IE = 1; // Enable interrupts GIEH = 1; GIEL = 1;
// Set timer0 interrupt to low priority // Clear the timer0 interrupt flag // Reset the timer0 counter // Timer0 on, 8-bit and 1:64 prescaler // Enable the timer0 interrupt
// Global enable all high priority interrupts // Global enable all low priority interrupts
Once the timer is configured and running we need some interrupt code to decide if the LED should be on or off for the interrupt. Since we have 20 possible brightness levels (and therefore 20 steps of resolution in our PWM generation) we can simply use a counter which counts from 0-19 and is updated once every interrupt. If the brightness of the LED is represented using a number from 0-19 we simply have to check if the PWM counter is higher or lower than the brightness number to see if the LED should be on or off.
// Globals for PWM unsigned char pwmCounter = 0; unsigned char ledBrightness = 0; // Low priority interrupt procedure void interrupt low_priority lpHandler(void) {
7 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
// Is this timer0 interrupting? if (TMR0IF) { if (ledBrightness > pwmCounter) LED0 = 1; else LED0 = 0; pwmCounter++; if (pwmCounter > 19) pwmCounter = 0; // Get ready for the next interrupt TMR0L = 255 - 187; // Reset the timer0 counter TMR0IF = 0; // Clear the timer0 interrupt flag } }
8 of 9
9/19/2011 6:13 PM
http://www.waitingforfriday.com/index.php/Controlling_LED_brightness_using_PWM
pwmCounter++; if (pwmCounter > 19) pwmCounter = 0; // Perform fading control if (ledTargetBrightness >= ledActualBrightness) ledActualBrightness = ledTargetBrightness; else { fadeCounter++; if (fadeCounter == 24) { ledActualBrightness--; fadeCounter = 0; } } // Get ready for the next interrupt // Reset the timer0 counter TMR0L = 255 - 187; TMR0IF = 0; // Clear the timer0 interrupt flag } }
Conclusions
Whilst it is perfectly possible to get PWM controls to work with LEDs using pure guess work, calculating the desired optimum values makes more efficient use of the available processor resources allowing you to both do more with the microcontroller and/or control more LEDs simultaneously from the same chip. The same techniques shown here for LEDs can also be used to control motors, analogue meter displays, incandescent light bulbs, etc.
9 of 9
9/19/2011 6:13 PM