FAST PWM (Pulse Width Modulation) Mode

In the Pulse Width Modulation (PWM) mode the duty cycle of a square wave can be varied. This will vary the avarage DC voltage of the waveform. When the waveforn is filtered by an RC circuit, this will create a Digital to Analog Convertor (DAC). For example a LED brightness or a DC motor can be controlled by the PWM waveform.

 

TIMER 1 provides a built-in method to create a pulse width modulator. The TIMER 1 function can be changed to PWM mode. During PWM operation it counts from zero up to a top value and then it counts down back to zero. The top value is determined by the resolution which can be set as 8-bit, 9-bit and 10-bit resolution by the Waveform Generation Mode (WGM) selected bits in the TCCR1A register. It will also effect the frequency of the PWM waveform. See the table below how the select the resolution in the TCCR1A register.

PWM select bits PWM resolution Timer Top Value
 WGM11   WGM10   
0 0  PWM disabled
0 1  8-bit  255
1 0  9-bit 511
1 1  10-bit 1023

The PWM frequency for the output can be calculated by the following equation:

fPWM = fsystem clock /prescaler (1 * top count). 

In the example code we set the prescaler to 8, as the system clock is 16Mhz this will result in a PWM frequency of:

16Mhz / 8 * ( 1 + 255) = 7,813 kHz 

The output of the PWM channnel is OC1A(PORTB1) which is connected to a LED. See the schematic below. 

 

The circuit can be build on a breadboard.

 

In the program code the duty cycle changes from 0 to 100% back and forth.

 

// program name: TIMER1_FAST_PWM_MODE 
// date: 08.09.2015
// author: www.avrprojects.net
// target device: atmega328
// harware: ATMEGA328 board PWM mode, LED
// software: WinAVR-20100110 compiler

#include <avr/io.h>
#include <util/delay.h>

enum {UP, DOWN};

void PWM_init(void)
{
TCCR1A |= (1<<COM1A1) | (1<<WGM10);//set compare A for non-inv. PWM with 8 bit resolution
TCCR1B |= (1<<CS10);//set clock no prescaler
}

void PWM_bright(void)
 {
 unsigned int Duty = OCR1A;
 static unsigned char direction;
    switch(direction)
        {
        case UP:
        if (++Duty == 255)
        direction = DOWN;
        break;
        case DOWN:
        if (--Duty == 2)
        direction = UP;
        break;
        }
    OCR1A = Duty;     
 }

 int main(void)
{
PWM_init();

DDRB |= (1<<DDB1);//set OC1A as output PORTB1 pin15

    while(1)
    {
    PWM_bright();
     _delay_ms(5); // 5ms delay
    }
}

 

Below you see the wave output of the signal on PORTB1.