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

Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (54) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (46) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (66) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (2) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (30) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)