basic - Pulse Width Modulation (PWM)

Post here to teach people how to do something.

Moderators: Chuckt, Garth, bitfogav

Post Reply [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
User avatar
sdudley
Moderator
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)

Post by sdudley » Mon Jun 07, 2010 11:12 am

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.

Image

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).

Image

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.

Image

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.

Image

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).

Image

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).

Image

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).

Image

Image

Image



VIDEO LINK:
http://www.youtube.com/watch?v=GxhJhvxI0wI
Attachments
new-variables.gif
new-variables.gif (11.56 KiB) Viewed 12353 times
25_percent.jpg
25_percent.jpg (89.46 KiB) Viewed 12381 times
50_percent.jpg
50_percent.jpg (90.92 KiB) Viewed 12381 times
75_percent.jpg
75_percent.jpg (92.29 KiB) Viewed 12382 times
basic_PWM.zip
(3.53 KiB) Downloaded 737 times
TMR1_prescale_change.gif
TMR1_prescale_change.gif (14.21 KiB) Viewed 12394 times
setup_load.gif
setup_load.gif (15.41 KiB) Viewed 12394 times
no_LED_routine.gif
no_LED_routine.gif (18.39 KiB) Viewed 12394 times
interrupt_TMR1_values.gif
interrupt_TMR1_values.gif (13.2 KiB) Viewed 12394 times
PWM_0_1_2.gif
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.

User avatar
brad
Site Admin
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

Post by brad » Mon Jun 07, 2010 10:45 pm

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. :lol:

User avatar
sdudley
Moderator
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

Post by sdudley » Mon Jun 07, 2010 11:54 pm

brad wrote:...instead of only 8 colours, I could bump it up to 16, 256 or more!!!
Oh thanks for the reminder... I forgot to note my reference.

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

User avatar
bitfogav
Moderator
Moderator
Posts: 915
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Tue Jun 08, 2010 3:06 am

Thats an amazin tutorial :) thats helped me understand how to implement PWM with microchips :D

So am I right in saying then that you dont need to make any setups to the PWM register CCPR1L or CCPR1H??

User avatar
sdudley
Moderator
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

Post by sdudley » Tue Jun 08, 2010 3:25 am

I noticed I forgot one of the images. I will have to add that when I get home.

EDIT*Done. I added the image showing the new variables.
Any time you deviate from sequential consistency, you increase the complexity of the problem by orders of magnitude.

User avatar
sdudley
Moderator
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

Post by sdudley » Wed Jun 16, 2010 10:11 pm

bitfogav wrote:...am I right in saying then that you dont need to make any setups to the PWM register CCPR1L or CCPR1H??
bitfogav,

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.

Post Reply
[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
[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

Who is online

Users browsing this forum: No registered users and 1 guest