widthavrpulseatmega

Pulse width modulation (PWM) on AVR Studio


I'm trying to use PWM for an LED on an ATmega8, any pin of port B. Setting up timers has been a annoying, and I don't know what to do with my OCR1A. Here's my code, and I'd love some feedback.

I'm just trying to figure out how use PWM. I know the concept, and OCR1A is supposed to be the fraction of the whole counter time I want the pulse on.

#define F_CPU 1000000  // 1 MHz

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

int main(void){

    TCCR1A |= (1 << CS10) | (1 << CS12) | (1 << CS11);
    OCR1A = 0x0000;
    TCCR1A |= ( 0 << WGM11 ) | ( 1 << WGM10 ) | (WGM12 << 1) | (WGM13 << 0);
    TCCR1A |= ( 1 << COM1A0 ) | ( 0 << COM1A1 );
    TIMSK |= (1 << TOIE1); // Enable timer interrupt
    DDRB = 0xFF;
    sei(); // Enable global interrupts
    PORTB = 0b00000000;

    while(1)
    {
        OCR1A = 0x00FF; //I'm trying to get the timer to alternate being on for 100% of the time,
        _delay_ms(200);
        OCR1A = 0x0066; // Then 50%
        _delay_ms(200);
        OCR1A = 0x0000; // Then 0%
        _delay_ms(200);
    }
}

ISR (TIMER1_COMA_vect)  // timer0 overflow interrupt
{
    PORTB =~ PORTB;
}

Solution

  • You need to initialize your OCR1A with these two lines:

    TCCR1A = (1 << WGM10) | (1 << COM1A1);
    TCCR1B = (1 << CS10) | (1 << WGM12);
    

    And then use this:

    OCR1A = in
    

    And know that the range is 0-255. Count your percentages, and there you have it!

    #define F_CPU 1000000  // 1 MHz
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    
    int main(void){
        TCCR1A = (1 << WGM10) | (1 << COM1A1);
        TCCR1B = (1 << CS10) | (1 << WGM12);
        DDRB = 0xFF;
        sei(); // Enable global interrupts
        PORTB = 0b00000000;
    
        while(1)
        {
            OCR1A = 255;
            _delay_ms(200);
            OCR1A = 125;
            _delay_ms(200);
            OCR1A = 0;
            _delay_ms(200);
        }
    }