Hello,
I try to learn how to use interrupts and I use an Arduino Uno R3. I code in C.
I managed to use the INT0 and INT1 interrupt with buttons but I now want to use the timer interrupts.
The goal is to replicate the millis() function with the TIMER0.
Here is the first approach without an interrupt which works :
#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/interrupt.h>
unsigned long millis = 0;
int main () {
// Declare LED as output
DDRB |= (1 << PORTB3);
// Set timer0
// Set CTC mode
TCCR0A |= (1 << WGM01);
// 16 000 000 / (64 * 250) = 1000 Hz
// Set top value
OCR0A = 250;
// Prescaler 64
TCCR0B |= ((1 << CS01) | (1 << CS00));
while (1) {
if ((TIFR0 & (1 << OCF0A)) != 0) {
// Reset the timer
TIFR0 |= (1 << OCF0A);
// Increase millis
millis++;
}
if (millis >= 1000) {
millis = 0;
// Switch the state of the LED
PORTB ^= (1 << PORTB3);
}
}
}
Now the second approach with the interrupt which doesn't work :
#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/interrupt.h>
unsigned long millis = 0;
// Timer0
ISR (TIMER0_COMPA_vect) {
millis++;
TIFR0 |= (1 << OCF0A);
}
int main () {
// Declare LED as output
DDRB |= (1 << PORTB3);
// Set timer0
// Set CTC mode
TCCR0A |= (1 << WGM01);
// 16 000 000 / (64 * 250) = 1000 Hz
// Set top value
OCR0A = 250;
// Prescaler 64
TCCR0B |= ((1 << CS01) | (1 << CS00));
// Enable interrupt for timer0
TIMSK0 |= (1 << OCIE0A);
// Enable global interrupts
SREG |= 0b10000000;
while (1) {
if (millis >= 1000) {
millis = 0;
// Switch the state of the LED
PORTB ^= (1 << PORTB3);
}
}
}
It doesn't works because the led never turns on. Also, I tried to change the code in the ISR (to turn on a LED for example) and it is never ran.
I don't know why this doesn't work because the documentation of the atmega328p says :
"When the OCIE0A bit is written to one, and the I-bit in the Status Register is set, the Timer/Counter0 Compare Match A interrupt is enabled. The corresponding interrupt is executed if a Compare Match in Timer/Counter0 occurs, i.e., when the OCF0A bit is set in the Timer/Counter 0 Interrupt Flag Register – TIFR0."
It seems to me like the OCIE0A is set to 1, the I-bit in the SREG is set to 1 and the CTC is enable for counter 0, match A.
Also, I found out that the first code breaks as soon as I add this line :
// Enable interrupt for timer0
TIMSK0 |= (1 << OCIE0A);
It means to me that the OCF0A flag is not longer even set to 1.
I searched for an answer for a long time but I couldn't find anything.
I hope I have been understandable enough and I stay at your disposal for any question.
Thank you for reading,
Pauloux