728x90

728x90

Monday, May 25, 2020

Using output compare unit of timer/counter 0 to in ATMega32 to generate a fast PWM signal

Beside using timer/counter 0 of ATMega32 as a timer or as a counter, this module could generate a PWM waveform output at pin PB3/OC0. Its PWM could work in two modes:
  • fast PWM
  • and phase correct PWM
In this example, we use only the fast PWM.

With timer/counter 0 module, an 8-bit comparator is non-stop digital comparator, comparing the value of TCNT0 with the output compare register 0 (OCR0). OCR0 is an 8-bit read/write register with an initial value of 0x00. It must have a preset value.
  • Output compare register 0 (OCR0)
BIT 7





BIT 0
 D7D6D5D4D3D2D1D0

Using output compare unit of timer/counter 0 to in ATMega32 generate a fast PWM signal
A simplified PWM signal generator module

When TCNT0 equal to the preset OCR0 (matched), the output compare flag (OCF0) will be set.
At the matched condition, the waveform generator will produce a waveform output to pin PB3. The wave form mode must be select in the TCCR0 register.

To program the PWM we must take notes as follow:
  • The value of OCR0 effect the duty cycle of the PWM. A large loaded value of it increase the duty cycle (non inverting mode).
  • A large value of timer 0 prescaler decrease the frequency of the PWM.
PWM operating mode could be configured using TCCR0.
  • Timer/Counter Control Register 0 (TCCR0)
BIT 7





BIT 0
FOC0WGM00COM01COM00WGM01CS02CS01CS00

The waveform generation mode bit WGM0:1 set the two mode of PWM.

 WGM1WGM0 Description 
 1Phase correct PWM 
 1Fast PWM 

Fast PWM polarity could be configured with compare output mode bit COM0:1.

COM1COM0Description 
 1Clear OC0 pin when the compare is matched (non inverting) 
 1Set OC0 pin when the compare is matched (inverting)

As mention in the previous post, the prescaler of timer 0 could be set using CS02:00. To select a 1:1 prescaler, we assign CS00 to '1' and others to '0'.

The frequency of PWM signal generated by timer 0 is:


For example I use 4 MHz crystal with timer 0 prescaler 1:1. The PWM frequency could be:
Using output compare unit of timer/counter 0 to in ATMega32 to generate a fast PWM signal

The PWM period time is:
 Using output compare unit of timer/counter 0 to in ATMega32 to generate a fast PWM signal

Now let see this example, I use the calculation listed above and I set the value of OCR0 to 127 to make a 50% duty cycle PWM signal with the frequency of 15.625 kHz.

#include <avr/io.h>

int main(void)
{   
 //set the duty cycle to 50%
 OCR0=127;
 //set PB3 to output
 DDRB|=(1<<3);
 /*
 Set fast PWM mode with non 
 inverting output
 */
 TCCR0|=(1<<COM01)|(1<<WGM00)|(1<<WGM01);
 //select 1:1 prescaler
 TCCR0|=(1<<CS00);
    while (1) 
    {
    }
}

The simulation screen shot shows the PWM signal. Click here to download its source file.

Using output compare unit of timer/counter 0 to in ATMega32 generate a fast PWM signal
Simulation screen shot.
ATMega32 oscillates from a 4 MHz clock.
PB3/OC0 outputs a PWM signal with the
frequency of 15.625 kHz and 50% duty cycle.



 

Since OCR0 is readable and writable, we can modify it to change duty cycle of generated PWM. In the following example, I use three switches to increase, reset and decrease the duty cycle. But I change the prescaler of timer 0 to 1:8, reducing the frequency.


Using output compare unit of timer/counter 0 to in ATMega32 generate a fast PWM signal
Schematic diagram of new example.
Three switches are connected to PC0.2 to adjust duty cycle.
PB3/OC0 output the PWM signal.



C source code is here.


#include <avr/io.h>
#define F_CPU 4000000UL
#include <util/delay.h>
void adjustDutyCycles(void){
 static unsigned char temp=0;
 //increase duty cycle
 if ((PINC&0x01)==0)
 {
  _delay_ms(250);
  if(temp<90) temp+=10;
 }
 //set duty cycle to zero
 if ((PINC&0x02)==0)
 {
  _delay_ms(250);
  temp=0;
 }
 //decrease duty cycle
 if ((PINC&0x04)==0)
 {
  _delay_ms(250);
  if(temp>0) temp-=10;
 }
 OCR0=(0xFF*temp)/100;
}
int main(void)
{
 //PC0.2 inputs
 DDRC=0b11111000;
 //Turn PC0.2 High
 PORTC=0b0000111;
    //set the duty cycle to 50%
 OCR0=0;
 //set PB3 to output
 DDRB|=(1<<3);
 /*
 Set fast PWM mode with non 
 inverting output
 */
 TCCR0|=(1<<COM01)|(1<<WGM00)|(1<<WGM01);
 //select 1:8 prescaler
 TCCR0|=(1<<CS01);
    while (1) 
    {
  adjustDutyCycles();
    }
}

Click here to download its source file.

Back to main tutorial page ATMega32 tutorials in C with Atmel Studio 7.

No comments:

Post a Comment

320x50

Search This Blog

tyro-728x90