Pulse width modulation (PWM) on AVR Studio
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);
}
}
No, this is not the way how you should do a PWM. For example, how do you set a PWM rate of, for example, 42% with it? Also, the code size is big, it can be done in a much more efficient way. Also, you waste a 16 bit timer to do 8 bit operations. You have 2x 8 bit timers (Timer/Counter 0 and 2), and one 16 bit timer, Timer/Counter 1
.
It's also a bad idea to set unused portpins to output. All portpins which are not connected to anything, should be left as inputs.
The ATmega8 has a built-in PWM generator on timers 1 and 2, there is no need in simulating it through software. You don't even have to set your ports manually (you only have to set the corresponding portpin to output)
You don't even need any interrupt.
#define fillrate OCR2A
//...
// main()
PORTB=0x00;
DDRB=0x08; //We use PORTB.3 as output, for OC2A, see the atmega8 reference manual
// Mode: Phase correct PWM top=0xFF
// OC2A output: Non-Inverted PWM
TCCR2A=0x81;
// Set the speed here, it will depend on your clock rate.
TCCR2B=0x02;
// for example, this will alternate between 75% and 42% PWM
while(1)
{
fillrate = 191; // ca. 75% PWM
delay_ms(2000);
fillrate = 107; // ca. 42% PWM
delay_ms(2000);
}
Note that you can use another LED with another PWM, by using the same timer and setting OCR2B instead of OCR2A. Don't forget to set TCCR2A to enable OCR2B as output for your PWM, as in this example only OCR2A is allowed.