PWM stands for pulse width modulation and can be a way of simulating analog voltage outputs. The most common usage of this type of modulation is driving motors, LEDs, heaters or anything other that can be driven with varying analog values.
With the only two parameters ( frequency and duty cycle ) we can describe the entire modulation process and because of its simplicity this has a wide range of uses inside the embedded world.
Almost every microcontroller have a few built in timers that can be used for PWM, but in case you need more than one, for example, to drive multiple LEDs, than your MCU has PWM channels then the MikroElektronika's PWM click board could be solution for you.
PWM Description
As described before, this type of modulation can be constructed with just two words - duty cycle and frequency.
Duty cycle represents the ratio of one period taken by pulse width - so duty cycle can vary inside the range 0 - 100. Number of periods inside the one second represents the Frequency.
When the duty cycle is 50% ( ratio 0.5 - pulse width taking half of period time ) the generated digital signal can be observed like as analog signal 50% of the digital voltage. For example - if our digital signal voltage ( Vhigh ) is 5 volts and we are generating signal with a 50% duty cycle - this can be observed like a 2.5 volt analog output, or even more simplified - output voltage is equal to digital signal voltage multiplied by duty cycle ratio.
Example of usage could be if we want to create a smooth blinking LED - all we have to do is constant periodic changing of the duty cycle from 0 to 100 and back. PWM is great for driving the motors on low RPM and PWM is widely used in class D audio amplifiers.
PWM click
Not all MCUs have PWM channels but usually MCUs have at least two of them - larger MCUs can have more than four, but if we need more than four PWM channels for driving ten independent LEDs simultaneously then something like our PWM click is needed.
The PWM click caries the NXP's PCA9685PW chip that allows control of up to 16 independent PWM channels through an I2C bus connection. Each output has its own 12-bit resolution (4096 steps) fixed frequency individual PWM controller that operates at a programmable frequency from a typical of 24 Hz to 1526 Hz with a duty cycle that is adjustable from 0 % to 100 % and also each output can be OFF or ON.
Example
Example from video doesn't using library and can be found on our git repository or you can download packages for our compilers from Libstock. Usage of the library is even more simple than this example and here we are going to go through the basics of library and click usage.
https://github.com/MikroElektronika/Click_PWM_PCA9685PW
First step as always is installing and including the library header inside the our project.
After the preparation steps we can start implementation of the the initialization routines. According to the factory documentation a PWM click supports up to 1 MHz I2C bus speed but my opinion it is to work with standard bus speed and for I2C ( 400 kHz ).
Declaration of PWM_EN_PIN is needed to successfully initialize the library because library inside it self uses this pin to power up the click board. Small delays after each initialization are not a must, that is just time for MCU to stabilize the voltages on particular pins.
Final initialization step is calling of the library init function and providing the click I2C hardware address as an argument. Default I2C address is 0x40 but depends on position of jumpers at the click-board's upper side. If you change the position of the jumpers check the datasheet provided along with this library and initialize the library with the proper address.
#include "pwm_hw.h" /* Variables *************/ sbit PWM_EN_PIN at GPIOC_ODR.B2; /* Prototypes **************/ void system_init( void ); /* Functions *************/ void system_init() { GPIO_Digital_Output( &GPIOC_BASE, _GPIO_PINMASK_2 ); Delay_ms( 200 ); I2C1_Init_Advanced( 400000, &_GPIO_MODULE_I2C1_PB67 ); Delay_ms( 200 ); } void main() { system_init(); pwm_init( 0x40 ); }
If project is compiled without errors our click board is now initialized with default settings.
Now let's try to set 50 percent duty cycle on all channels. If you take a closer look to the documentation provided, you will notice that there are two possible ways to do that. First solution is to provide the raw value pwm_set_all_raw and the second solution is to provide the percentage of period taken by duty cycle pwm_set_all . In case of providing raw values, the duty cycle is 12 bit value and can be in range 0 ~ 4095. With this function you can get better precision if needed.
void main() { system_init(); pwm_init( 0x40 ); pwm_set_all( 50 ); }
void main() { system_init(); pwm_init( 0x40 ); pwm_set_all_raw( 2048 ); }
Both solutions functions example giving the same result.
Now lets try to set channel by channel separately. We are going to increment the offset by 25% for the first four channels ( duty will be the same for all channels ) and finally channel 5 will be set to off state.
void main() { system_init(); pwm_init( 0x40 ); pwm_set_channel( 0, 0, 50 ); pwm_set_channel( 1, 25, 50 ); pwm_set_channel( 2, 50, 50 ); pwm_set_channel( 3, 75, 50 ); pwm_set_channel( 4, 100, 50 ); pwm_channel_state( 5, false ); }
And the result is like we excepted.
Finally lets try the different duty cycles on this channels.
void main() { system_init(); pwm_init( 0x40 ); pwm_set_channel( 0, 0, 20 ); pwm_set_channel( 1, 0, 40 ); pwm_set_channel( 2, 0, 60 ); pwm_set_channel( 3, 0, 80 ); pwm_set_channel( 4, 0, 100 ); }
As you can see channel haven't exactly 100% duty cycle, and that small deviation exists because of calculation inside the library, so if you need real precision you should use pwm_set_channel_raw .
Summary
The PWM click can be an easily understandable component even if you don't fully comprehend a tremendous amount about the embedded world. Simple types of modulation can be your start point in generating custom analog-like signals in your project. PWM is widely used inside the embedded world because of it's simplicity and easy software implementation. If you haven't worked with it yet - now is the time to give it try - also inside the Library Manager of our compilers and documentation can help you jump start to the new beginning of exploring into this new frontier.