PWM in microcontrollers

What is PWM? Why do we need it?

Well those of you who know about principles of communication PWM stands for pulse width modulation. Now modulation refers to change in output signal in proportion to the input signal. Now in communication systems in order to transmit data over antenna  we modulate the signal and translate it to a higher frequency. But how does PWM help in microcontrollers? Lets consider an LED which is connected to the port pin of your microcontroller. Suppose the high logic level corresponds to 3 Volts and low logic level corresponds to 0 Volt. So when you make the port pin ON the LED will get 3Volts. But suppose the LED is too bright for your application you want to change the brightness somehow. One way is to use a potentiometer to vary the voltage. But that would require an external hardware as well as manpower(you have to manually adjust the pot value). Suppose that you want to use the software and the timer hardware inbuilt in your microcontroller to change this voltage, then what would you do? The answer my friend is PWM. We give pules of varying duty cycle at the output of port pin. This in turn will give us varying average DC values.

How varying voltage is obtained using PWM?

261120131291

Thus we can vary the duty cycle and in turn vary the dc voltage available at the port pin. When we vary the duty cycle we are in turn varying the pulse width and doing pulse width modulation. This PWM can be used to vary the speed of DC motors without using a DAC(if you don’t want precise speed control you can use this.) Now about the frequency of pulses. The time delay should be small enough that there are no jerks in the motor. One other application is dimming effect in LED’s. So if you want to make LED ON in an expensive way(I’ll tell expensive why very soon) i.e by making a subtle transition from the OFF state to ON state you use PWM. Just change the duty cycle of the pulses gradually from 0 to 100%. This will give you the elegant transition. Now coming to the expensive part. Suppose you own a car and there is this interior light system which uses a proximity sensor or any other sensor to detect your presence and stars the lights. What would look more elegant to you the lights abruptly turning ON or the slow and smooth transition? Well I would like the cool effect. Now this will raise the cost of that system drastically. So these are two applications of this PWM concept.

Persistence of vision and dimming effect

Well you might know about the persistence of vision concept. If the change is taking place in less than tenth of a second then human eye is unable to distinguish the change. This concept is used in motion pictures. Now suppose your PWM frequency is 1Hz i.e 1 cycle per second. You will clearly see the LED’s turning on and OFF. So the trick is to make the LED’s toggle at a rate or frequency that gives the human eyes the illusion that LED is  continuously ON . So that is the small part that one needs to take care while using PWM for the dimming effect. But lower the frequency lower the power dissipated, so use a frequency that is just enough to make the LED’s not seem flickering.

Timer A and PWM

Well now we have a background knowledge of PWM, so let’s learn how to achieve PWM using Timer A of msp430. I had covered how to use Timer A in up mode. So we’ll learn how to obtain PWM in up mode and most importantly get the output on a port pin and know which pin it is.

Well for Timer A initializing please refer my earlier post. Now we’ll focus on OUT modes.

out_modes

Well the description given is clear enough. But still one example will aid to the understanding of the modes.

example_out_mode_in_up_mode

The Output modes are explained in terms of Timer A up mode. We’ll be using the TA0CCR0 and TA0CCR1 register for this particular experiment. Since we are using TA0CCR1 we have to see the output at the OUT1 of Timer A0. Now since this is a special output, we have to select the port special function mode. This is given in the data sheet.

port_functions

Look at the P1.2 functions. We are interested in TA0.1. So we need to make the port pin as output and then select the function 2 i.e set the P1SEL BIT2. With that we cover the PWM and its generation.

Code

/*
* main.c
* Created on    : 26-Nov-2013 1:52:12 AM
* Author        : Manpreet Singh Minhas
* Website       : https://learningmsp430.wordpress.com
*/

// Aim : To create dimming effect using PWM.

#include "msp430g2553.h";
void main(void) {
WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

P1DIR |= BIT2;               // Initialize port for Output signal
P1SEL |= BIT2;
P1SEL2 &= ~BIT2;
TA0CCR0 = 0xFF;              // Give the time delay small enough to avoid visible flickering
TA0CCR1 = 0xFF;              // Give initial duty cycle 0
TA0CCTL1 = OUTMOD_2;
TA0CTL |= TASSEL_1|ID_0|MC_1;
int i;
int j;
for(;;)
{
for(j=0;j<0xFE;j++){
for(i =0;i<3000;i++){}
--TA0CCR1;                   // Increase the duty cycle slowly
}
for(j=0;j<0xFE;j++)

{
for(i =0;i<3000;i++){}
++TA0CCR1;                   // Decrease the duty cycle slowly
}
TA0CCR1=0xFF; // Give initial count again
}
}

Alternate which involves LPM and interrupt

/*
* main.c
* Created on     : 27-Nov-2013 3:52:12 PM
* Author         : Manpreet Singh Minhas
* Website        : https://learningmsp430.wordpress.com
*/
#include <msp430g2553.h>
int i=1;
void main(void) {
WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

P1OUT = BIT0;
P1DIR |= BIT0|BIT6|BIT2;
P1SEL |= BIT2;
P1SEL2 &= ~BIT2;
TA0CCR0 = 0x7FF;
TA0CCR1 = 0x7FF;
TA0CCTL1 = OUTMOD_2;
TA0CTL |= TASSEL_2|ID_0|MC_1|TAIE;
_BIS_SR(LPM0_bits|GIE);
}

#pragma vector=TIMER0_A1_VECTOR
__interrupt void TimerA(void)
{
switch(i){
case 1:
--TA0CCR1;
if(TA0CCR1==0)
{
i=2;
}
break;
case 2:
++TA0CCR1;
if(TA0CCR1==0x7FF){i=1;TA0CCR1 = 0x7FF;}
break;
}
P1OUT ^= BIT0|BIT6;
TA0CTL &= ~TAIFG;

}

Alternate version

/*
* main.c
* Created on     : 26-Nov-2013 1:52:12 AM
* Author         : Manpreet Singh Minhas
* Website        : https://learningmsp430.wordpress.com
* Aim            : Well this is nothing but the same program written differently.
*                       In this the dimming effect will take place once when you push
*                       the button connected to P1.1.
*/
#include <msp430g2553.h>
int i;
int j;
void main(void) {
WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer

P1OUT = BIT0;
P1DIR |= BIT0|BIT6|BIT2;
P1IE |= BIT1;
P1DIR &= ~BIT1;
P1REN |= BIT1;
P1OUT |= BIT1;
P1IES |= BIT1;
P1SEL |= BIT2;
P1SEL2 &= ~BIT2;
TA0CCR0 = 0xFF;
TA0CCR1 = 0xFF;
TA0CCTL1 = OUTMOD_2;
//TA0CTL |= TASSEL_2|ID_0|MC_1|TAIE;
TA0CTL |= TASSEL_2|ID_0|MC_1;
_BIS_SR(LPM0_bits|GIE);
}
#pragma vector=PORT1_VECTOR
__interrupt void Port1(void){
P1OUT ^= BIT0|BIT6;
for(j=0;j<0xFE;j++){
for(i =0;i<3000;i++){}

--TA0CCR1;
}
for(j=0;j<0xFE;j++){
for(i =0;i<3000;i++){}
++TA0CCR1;
}
TA0CCR1=0xFF;
P1IFG &= ~BIT1;
}

Effect Video

You can see the effect in this video.

Advertisements

5 thoughts on “PWM in microcontrollers

    • It’s a formatting error. The line is #include “filename”
      This instructs css to look for the file in the project directory. So you will have to include that file in the directory. The content has been rectified.

  1. try this source code:

    #include

    int i=1;
    void main(void) {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    //P1OUT = BIT0;
    P1DIR |= BIT6;
    P1SEL |= BIT6;

    TA1CTL |= TASSEL_2|ID_3|MC_1|TAIE;
    TA0CCR0 = 125;
    TA0CCR1 = 0;
    TA0CCTL1 = OUTMOD_7;
    TA0CTL |= TASSEL_2|ID_3|MC_1|TAIE;
    __enable_interrupt();
    _BIS_SR(LPM0_bits|GIE);
    }
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TimerA0(void){
    P1OUT ^= BIT0;

    }

    #pragma vector=TIMER0_A1_VECTOR
    __interrupt void TimerA(void)
    {
    switch(i){
    case 1:
    TA0CCR1+=1;
    __delay_cycles(40000);

    //TA1CCR0=5000;
    if(TA0CCR1==125)
    {
    i=2;
    }
    break;
    case 2:
    TA0CCR1-=1;
    __delay_cycles(40000);

    //TA1CCR0=5000;
    if(TA0CCR1==0)
    {
    i=1;
    TA0CCR1 =0 ;
    }
    break;
    }
    P1OUT ^=BIT6;
    //__delay_cycles(10000);
    TA0CTL &= ~TAIFG;

    }
    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void TimerA1(void)
    {

    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s