I'm trying to use the timer0 interrupt of ATMega328P MCU to flash an LED every second.
I have used this calculator and concluded that for a 20Mhz crystal 195 timer ticks will give an interrupt at every 0.01 seconds. So I'm using a variable counter up to 100 to flash the LED when it reaches 100(so one second has elapsed).
I have written this code:
Code:
/*
* AVRGCC1.c
*
* Created: 10/19/2016 5:20:34 PM
* Author: Paul
*/
#include <avr/io.h>
#include <avr/interrupt.h> // quick way to include interrupts in the code
int extraTime = 0;
int main(void)
{
DDRB = 0x01; // setting the LED as an output
TCCR0A = (1 << WGM01); // Set CTC Bit
OCR0A = 195; // number of ticks we need for our specific time
TIMSK0 = (1 << OCIE0A);
TCCR0B = (1 << CS02) | (1 << CS00); // use 1024 prescaler
sei(); // setting the interrupt???(setting the i bit)
while(1)
{
//TODO:: Please write your application code
}
}
ISR(TIMER0_COMPA_vect) // the interrupt service routine(see list of vectors for all interrupt sources!!!!
{
extraTime++;
if(extraTime > 100)
{
PORTB ^= (1<<PORTB0); // toggle LED
extraTime = 0;
}
}
Now when I simulate this my led flashes every 30 seconds instead of every second. Now I can increase it's frequency by just reducing the number of ticks but that's just playing around with it no precision at all.
The code above is from a tutorial and in that tutorial the LED flashes exactly at one second interval. The code is basically identical. However I'm simulating the application in proteus whereas that guy who made that tutorial is implementing it in hardware. Can this be an issue from Proteus simulator? I've been told in the past that it has some problems when it comes to modelling the oscillators(or something like that). And if is indeed a proteus problem any way I can fix it so the oscillator and the program are synced? Thank you for reading.
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t extratime = 0;
int main(void){
TCCR0A = 0b00000000; // timer 0 normal mode
TCCR0B = 0b00000101; // 1:1024 prescale
TIMSK0 = 0b00000001; // timer 0 overflow interrupt enable
SREG |= 0b10000000; // global interrupt enable
PORTB &= ~_BV(PB0); // PB0 low
DDRB |= _BV(PB0); // PB0 output for LED
while(1); // loop forever
return 0;
}
ISR(TIMER0_OVF_vect){ // timer 0 overflow interrupt vector
extratime++; // advance post scaler
if(extratime > 77){ // if post scaler > 77
PORTB ^= _BV(PB0); // toggle state of PB0
extratime = 0; // reset post scaler
}
}
This init code will set timer 0 up with 1:1024 prescale. Load your post scale counter with 77 to get a 1 second timer. Then use ISR(TIMER0_OVF_vect) for your interrupt handler.
Another question. I just started with AVR MCU's and I'm trying to calibrate my internal oscillator as 8Mhz. Now I have to program the fuse low bite. For example I tried clearing the "prescale oscillator by 1/8" factory setting by doing: CKDIV8 = 1(unprogrammed). But if I try to run that in code I get an error the compiler won't recognize CKDIV8.
My question is kinda silly but I can't figure this out. What is the fuse name? For example when you are working with PICs you have registers names(e.g: OSCCON) that you can access for example OSCCON |= (1<<7) to set bit 7. But in my case how can I set the bits of the fuses? What is the fuses name? I'm not sure if you understand what I mean (yeah I'm guessing it sounds stupid).
Also I know there are fuses calculators online I just want to know how can I do this manually. Then I'll use those. Thanks.
I calibrated my microcontroller via AVR Studio's fuse programming to use a 8Mhz oscillator internal oscillator(at least I think I did).
I have selected no prescale option.
So my timer0 beiing a 8 bit timer should give an overflow every 0.0318 ms. So I used a counter variable and when that reaches 31 I toggle an LED. So by my calculations the LED should flash every second but instead it flashes 4 times per 0.9 seconds....am I missing something?
This is the code:
Code:
/*
* AVRGCC1.c
*
* Created: 10/19/2016 5:20:34 PM
* Author: Paul
*/
#define F_CPU 8000000L
#include <avr/io.h>
#include <avr/interrupt.h> // quick way to include interrupts in the code
#include <avr/delay.h>
int extraTime = 0;
int main(void)
{
DDRB = 0x01; // setting the LED as an output
TIMSK0 |= (1<<0); // enable TIMER0 overflow
TCCR0B |= (1<<0); // set bit0(clk/1 no prescaling)
TCNT0=0x00; // timer0=0
sei(); // enable interrupts
while(1)
{
}
}
ISR(TIMER0_OVF_vect)
{
extraTime++;
if(extraTime == 31)
{
PORTB ^= (1 << PORTB0); // toggle LED
extraTime = 0; // and reset counter
}
}
When I do Proteus simulations, I always include a Nop(); which generates a single nop.. This tells me the speed when I single step... I then know the frequency of the oscillator block is correct!!
I gave you example code above. Why are you against using a prescaler?
Timer math is really simple. AVRs run at one instruction per clock cycle so long as the DIV8 fuse is unprogrammed and the system clock prescaler is 1:1. The timer math then becomes -
Time = ((1/Fosc) x Timer Prescale Value) x 256
So at 8MHz and a 1:1 timer prescale, you overflow every 320uS. With a 1:1024 prescale, you overflow every 32.768mS. So you need a 1:1024 prescale to get a 1 second timer with a counter value of 31.
I gave you example code above. Why are you against using a prescaler?
Timer math is really simple. AVRs run at one instruction per clock cycle so long as the DIV8 fuse is unprogrammed and the system clock prescaler is 1:1. The timer math then becomes -
Time = ((1/Fosc) x Timer Prescale Value) x 256
So at 8MHz and a 1:1 timer prescale, you overflow every 320uS. With a 1:1024 prescale, you overflow every 32.768mS. So you need a 1:1024 prescale to get a 1 second timer with a counter value of 31.
Also I have not anything against using a prescaler I just don't think I need it in my case and I want to see where my mistake was. Thanks for answering.