Here is the .asm file:
http://www.bradsprojects.com/phpBB2/upl ... wm_181.zip
Description:
Basic_PWM... This tutorial is an extention of the "Timers and Interrupts" tutorial. It expands upon the code by adding two more blinking LED's to the circuit. All three LED's will be pulsed ON at the same time but will blink at different rates based upon the value of the OFF time. This "time on" verses "time off" is known as the Duty Cycle.
For instance, if the LED is on for 25% of the time and off for 75% of the time, it has a Duty Cycle of 25%. Maintaining the same pulse rate while varying the on/off time is known as Pulse Width Modulation (PWM).
How This Program Works:
During setup, three port pins are set high (which turns on three LED's simultaneously), and three count variables (DC0, DC1, DC2) are filled with values that represent the time each of the LED's will stay on.
An interrupt count variable (int_count) will be filled with a value that is decremented each time TMR1 causes an interrupt. After being decremented, the int_count variable is then compared to the DCx variables.
The "x" in the DCx variable stands for the corrosponding PORT pin that it represents.
DC0 corresponds to PORTB, 0 while DC1 corresponds to PORTB, 1 and DC2 corresponds to PORTB, 2.
Upon a match between the int_count variable and any of the DCx variables, the corrosponding PORT pin will be cleared (turning off the LED). This will continue until the int_count variable reaches zero at which point the PORT pins will be reset, the int_count variable will be refilled with it's respective value and the process will start over.
*NOTE* if the value in any of the DCx variables is larger than the value in the int_count variable, that PORT pin will never be cleared and the LED will stay on the entire time.
Purpose:
To show how to use a software interrupt to implement Pulse Width Modulation. The pulse rate chosen for this demonstration is such that it can be seen using blinking LED's and not have the need for expensive test equipment (I love LED's).
What you will need:
The same as in Brad's tutorial 2 (a simple LED flasher) with the addition of two LED's and resistors.
The Circuit:
Follow the instructions for connecting your LED and resistor exactly as you would in Brad's tutorial 2 (a simple LED flasher) and add two more resistors to PORTB pin 1 and PORTB pin 2.
The Program:
At this point it is expected that you have completed and understand both Brad's tutorial 2 – "a simple LED flasher" as well at the "Timers and Interrupts" tutorial I previously posted here:
http://www.bradsprojects.com/phpBB2/viewtopic.php?t=146
I will only be discussing the changes that were made to the "Timers and Interrupts" tutorial since all I did was expand on the code. The only change made to the circuit is the original LED was moved from PORTA pin 1 to PORTB pin 0 (to coincide with Brad's original circuit) and the addition of two LED's.
Lines 16-19 show that four more variables are added. The code is commented quite well to explain their purpose as they are also described above under the section "How This Program Works" so I don't feel the need to re-explain them.
Before getting involved with the code in the interrupt routine, lets jump down to the changes made in the setup and main program.
Take a look below at lines 127-128. They have been changed to turn off the prescaler (it was originally set to divide by 8 ). The timing values of the interrupt intervals have changed so that we need the prescaler to divide by 1 (no prescaler needed).
Below you will notice code was also added in the setup to load the count value for the int_count variable, set the PORT pins high, and load the Duty Cycle variables with values that represent a 25% Duty Cycle, a 50% Duty Cycle, and a 75% Duty Cycle.
The main program still does nothing as before but the subroutine to turn on and off the LED has been removed. We are no longer going to use that for this demonstration.
Now it's time to go back to the interrupt routine and see what changes were made:
Below you will see that there are new timer values. These values were chosen because they will cause TMR1 to time out every 10mS (setting the prescaler for 1:1).
Below that actually starts the new code and the beginning of the PWM cycle.
Lines 59-60 are the two lines of code that decrement the interrupt counter and determine whether or not it needs to be reloaded and the PORT pins need to be reset. If the int_count has reached zero it will skip to lines 63-69 and then leave the interrupt routine.
If the int_count has NOT reached zero then it will jump to PWM_0 (line 70) where it will begin to compare itself to the values stored in the Ducty Cycle registers (DC0, DC1, DC2).
Conclusion:
Well, that is about the best I can do to explain it! I hope everyone can understand it.
The code is well commented and should explain all that is necessary to understand what is happening line by line. Below are some photos and a link to a video to give a little "visual" as to what is going on at each PORT pin.
Enojy!
Stacy
PS> Play around with the values stored in the DC0, DC1, & DC2 registers (variables) and watch how the LED's blink at different rates. This is an excellent way to control motors and dim lights (among other useful applications).
VIDEO LINK:
http://www.youtube.com/watch?v=GxhJhvxI0wI
basic - Pulse Width Modulation (PWM)
Moderators: Chuckt, Garth, bitfogav
- sdudley
- Moderator
- Posts: 337
- Joined: Sun Mar 28, 2010 1:33 pm
- Location: Florida, U.S.A. [phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
basic - Pulse Width Modulation (PWM)
- Attachments
-
- new-variables.gif (11.56 KiB) Viewed 12353 times
-
- 25_percent.jpg (89.46 KiB) Viewed 12381 times
-
- 50_percent.jpg (90.92 KiB) Viewed 12381 times
-
- 75_percent.jpg (92.29 KiB) Viewed 12382 times
-
- basic_PWM.zip
- (3.53 KiB) Downloaded 737 times
-
- TMR1_prescale_change.gif (14.21 KiB) Viewed 12394 times
-
- setup_load.gif (15.41 KiB) Viewed 12394 times
-
- no_LED_routine.gif (18.39 KiB) Viewed 12394 times
-
- interrupt_TMR1_values.gif (13.2 KiB) Viewed 12394 times
-
- PWM_0_1_2.gif (14.21 KiB) Viewed 12394 times
Last edited by sdudley on Tue Jun 08, 2010 12:45 pm, edited 1 time in total.
Any time you deviate from sequential consistency, you increase the complexity of the problem by orders of magnitude.
- brad
- Site Admin
- Posts: 2578
- Joined: Fri Mar 26, 2010 10:30 pm [phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
I really enjoyed the tutorial. Another fantastic one - great job!
Now I did resize a few images just slightly so that while still in frames, you could read everything without side scrolling.
PWM would open up a whole new level to making games on the LEBDOY. instead of only 8 colours, I could bump it up to 16, 256 or more!!!
once again, great job - and here's flappy lips to help celebrate.
Now I did resize a few images just slightly so that while still in frames, you could read everything without side scrolling.
PWM would open up a whole new level to making games on the LEBDOY. instead of only 8 colours, I could bump it up to 16, 256 or more!!!
once again, great job - and here's flappy lips to help celebrate.
- sdudley
- Moderator
- Posts: 337
- Joined: Sun Mar 28, 2010 1:33 pm
- Location: Florida, U.S.A. [phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
Oh thanks for the reminder... I forgot to note my reference.brad wrote:...instead of only 8 colours, I could bump it up to 16, 256 or more!!!
I have done quite a bit of study on how to implement PWM but could not find something as simple as what I just posted.
I did find an application note on the Microchip site where I got my information from.
AN1074 - Software PWM Generation for LED Dimming and RGB Color Applications
http://www.microchip.com/stellent/idcpl ... e=en524189
I pretty much followed it to a "T" with a few exceptions:
1) The Microchip application note goes into great detail explaining what PWM is and gives some good math on how to determine the interrupt intervals, etc.
2) The Microchip application note also covers implementing the ADC for user input to change the pulse widths.
3) The Microchip application note uses relocatable code as opposed to absolute code so it makes it difficult to follow the program. You have to jump back and forth between files to figure out what is going on. One day I would like to add a tutorial on using relocatable code and the benefits of doing so.
4) The Microchip application note uses a 10ms time period as I do but instead they divide it by 32 where as I multiply it by 32.
So their interrupt cycle occurs every 320us and the period starts over every 10ms (LED’s get reset etc.).
The interrupt cycle in my application occurs every 10ms and the period starts over every 320ms.
The AN1074 program is designed to change the colors of an RGB and you don’t want to see the lights pulse, you want to see the different colors it can make.
I wanted to slow down the period so it is easy to see the difference between the Duty Cycles without the need of a measurement device (other than an LED of course).
Since this is such a great way to dim LED’s I figure it might be a cool way to add a little dimension to a project such as your POV.
Let’s say you draw several objects on the screen of the POV (I guess you would call it the screen). By making one of the objects dimmer than the others and slowly increase the brightness it might appear as if it is moving closer. This might help to add depth to a 2D image. I am not sure if that would really work, or even how difficult it would be to program but my guess is that it is not impossible and I wonder how cool the effect would be. You could draw a star field and make it look as if you are traveling though space.
Ok, maybe that is stupid but you get the idea!
Anyway, I do hope people will benefit from this in some way.
Stacy
- sdudley
- Moderator
- Posts: 337
- Joined: Sun Mar 28, 2010 1:33 pm
- Location: Florida, U.S.A. [phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
bitfogav,bitfogav wrote:...am I right in saying then that you dont need to make any setups to the PWM register CCPR1L or CCPR1H??
I was just reading back through this and noticed I never answered your question, SORRY!
So... yes you are correct in this case. Since the PIC16F648A has only one PWM module it is not capable of controlling multiple devices. This is one reason I learned to do it this way (manually I guess you could say).
If I only wanted to control one device using PWM, then I would most likely take advantage of the built in PWM.
Stacy
Any time you deviate from sequential consistency, you increase the complexity of the problem by orders of magnitude.
Who is online
Users browsing this forum: No registered users and 1 guest