• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ATMega328P timer interrupt simulation problem

Status
Not open for further replies.

Cantafford

Member
Hello,

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.

Here is the proteus schematic:
 

Jon Wilder

Active Member
You're using the timer 0 compare interrupt vector. You need to use the overflow vector instead.
Code:
ISR(TIMER0_OVF_vect){
    // interrupt  code
}
Further, timer 0 free running and prescaled at 1:1024 overflows once every 13 milliseconds. Loading your counter with 77 will get you 1 second.
 
Last edited:

Jon Wilder

Active Member
Code:
#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.
 
Last edited:

Cantafford

Member
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 :D(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.
 

Cantafford

Member
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
    }   
   
}
 

Jon Wilder

Active Member
Show your calculations cause that's way off.

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.
 
Last edited:

Cantafford

Member
Show your calculations cause that's way off.

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.
Ok then I'm guess I'm doing something wrong in my calculations. This is how I calculated everything:

8 Mhz oscillator => Fosc = 1/8Mhz = 0.000125 ms per instruction
Tmr0 overflow = 256 * Fosc = 0,032 ms

S0: Tmr0 overflow * 32 = 1 second.
Isn't this correct?

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.
 

Jon Wilder

Active Member
It's in your units.

8MHz = 8,000,000Hz

1 / 8MHz = 125nS (nanoseconds), or 0.125uS (microseconds) or 0.000000125 seconds

125nS x 256 = 32uS (microseconds)

With no prescaler you'd overflow every 32uS...nowhere near your calculations.

Now let's plug in the 1:1024 prescaler -

125nS x 1024 = 128uS

128uS x 256 = 32.768mS or 0.032768 seconds

32.768mS x 31 = 1.016 seconds
 

Cantafford

Member
It's in your units.

8MHz = 8,000,000Hz

1 / 8MHz = 125nS (nanoseconds), or 0.125uS (microseconds) or 0.000000125 seconds

125nS x 256 = 32uS (microseconds)

With no prescaler you'd overflow every 32uS...nowhere near your calculations.

Now let's plug in the 1:1024 prescaler -

125nS x 1024 = 128uS

128uS x 256 = 32.768mS or 0.032768 seconds

32.768mS x 31 = 1.016 seconds
Ok thanks man. Gotta be more carefull with the math :D
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top