/*
1. Select the normal operation and CTC mode for timer0
2. Pre-scale the internal clock by a factor of 1024
3. Store the desired value (78) in OCR0A
4. Timer0 operates and increments values into TCNT0 register
5. Monitor the OCF0A flag to see if match occurs between TCNT0 and OCR0A.
6. Clear the OCF0A flag after each match occors by writing 1 to it.
7. Repeat from step 5 for 100 times.
8. Toggle the LED connected to PB1 every 1 second.
4. Enable Global interrupt enable I bit in SREG register
5. Enable OCIE0A bit in TIMSK register to enable Timer0 compare match interrupt.
6. Write the Interrupt service routine to repeat the operation 100 times to obtain a delay of 1 second.
7. Toggle the LED connected to the PB1 pin once the operation repeated 100 times.
Really like the coding style with this by creating a timer function based on 1 milisecond
intervals.
See similar sketch for ATtiny13a
/Documents/Arduino/ATtiny13A/C Examples/Timer Counter Examples/Timer_and_Compare_Match/
*/
#include <TinyDebug.h>
#include <avr/io.h>
#include <avr/delay.h>
#define led1 PB3 // output
#define led2 PB4 // output
uint8_t intr_count = 0;
void timer_compare() {
// TCCR0A – Timer/Counter Control Register A
// We want 'Mode of Operation' set to 'Normal' so COM0xx bits are set to 0
// Need to set bit WGM01 for CTC 'Mode of Operation'
TCCR0A = 0b00000010; // set bits COM0A0(7), COM0A1(6), COM0B0(5), COM0B1(4) to 0, WGM01(1) to 1, WGM00(0) to 0
// TCCR0B – Timer/Counter Control Register B
// set the prescaler to 1024
// 8.0 MHz / 1024 = 7812 Hz, will overflow every 7812 ticks
TCCR0B |= (1 << CS00) | (1 << CS02); // prescaling with 1024
// OCR0A – Output Compare Register A
// compare value, 78 increments at .128008 Ms each tick * 78 = 9.984 miliseconds, * 100 = 998.4 ms
OCR0A= 78; // 8 bit register can hold value up to 255
// TCNT0 – Timer/Counter Register
// keeps track of overflow value, max value is 255
// 8000000 MHz / 1024 = 7812 Hz, will overflow every 7812 ticks
// 1 / 7812 = .000128008 seconds or .128008 miliseconds
// This is the time period that each count takes to increment in TCNT0 register.
// Number of steps to get to 10 milisecond (1/100 second) 10ms = 10 / .128008 = 78.12
TCNT0 = 0; // preload with value:
// TIMSK – Timer/Counter Interrupt Mask Register
// Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable
// 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.
// TIMSK |= (1 << OCIE0A);
// Bit 7 – I: Global Interrupt Enable - or use sei()
// SREG = SREG | 0b10000000;
sei(); // * enabling global interrupt
}
void delay100() {
int i = 0;
while (i <= 100) { // 100 = 1 sec
// TIFR is the flag register that holds the flag bits of timer overflow and compare match for Timer0
// When match occurs between OCR0A and TCNT0 the flag bit OCF0A will be set to 1
while ((TIFR & (1 << OCF0A)) == 0); // waiting 10ms for OCF0A flag bit to be set high
TIFR |= (1 << OCF0A); // toggling OCF0A resets the match timer
i++; // increment by one
}
}
void delay10() {
int i = 0;
while (i <= 10) { // 10 = .1 sec
// TIFR is the flag register that holds the flag bits of timer overflow and compare match for Timer0
// When match occurs between OCR0A and TCNT0 the flag bit OCF0A will be set to 1
while ((TIFR & (1 << OCF0A)) == 0); // waiting 10ms for OCF0A flag bit to be set high
TIFR |= (1 << OCF0A); // toggling OCF0A resets the match timer
i++; // increment by one
}
}
ISR(TIM0_COMPA_vect) {
if (intr_count == 200) { // 100 count = 1 sec, 200 = 2 sec
PORTB |= (1 << led1); // led1 high
PORTB &= ~(1 << led2); // led2 low
delay10();
PORTB &= ~(1 << led1); // led1 low
PORTB |= (1 << led2); // led2 high
delay10();
PORTB |= (1 << led1); // led1 high
PORTB &= ~(1 << led2); // led2 low
delay10();
PORTB &= ~(1 << led1); // led1 low
PORTB |= (1 << led2); // led2 high
delay10();
PORTB &= ~(1 << led2); // led2 low
intr_count = 0; // reset counter to 0
}
else intr_count++; // incrementing intr_count by 1
}
int main() {
Debug.begin();
DDRB |= (1 << led1) | (1 << led2); // set PORTB3 and PORTB4 as output
unsigned long millsec = 0;
unsigned long event1 = 500UL;
unsigned long previousTime1 = 0;
timer_compare();
while (1) {
Debug.print("TIFR1 "); Debug.println(TIFR); // initial state of TIFR is 0
Debug.print("OCF0A1 "); Debug.println(1 << OCF0A); // 1 << OFF0A is 0b00010000 (16)
// waiting 10ms for OCF0A flag bit to be set high at match
// TIFR = 0b00000000 & OCR0A = 0b00010000, 9 & 1 = 0
while ((TIFR & (1 << OCF0A)) == 0);
Debug.print("TIFR2 "); Debug.println(TIFR); // TIFR is now 16
Debug.print("OCF0A2 "); Debug.println(1 << OCF0A); //
TIFR |= (1 << OCF0A); // write 1 to OCF0A, to reset the match timer
Debug.print("TIFR3 "); Debug.println(TIFR); // prints every 10 miliseconds
Debug.print("OCF0A3 "); Debug.println(1 << OCF0A); // prints every 10 miliseconds
millsec ++; // increment by one
Debug.print("millsec "); Debug.println(millsec); // prints every 10 miliseconds
if (millsec - previousTime1 >= event1) {
previousTime1 = millsec;
event1 = 500UL;
TIMSK |= (1 << OCIE0A);
//TIFR |= (0 << OCF0A);
//TIMSK = 0b00000000;
Debug.print("TIMSK1 "); Debug.println(TIMSK); // prints every 10 miliseconds
Debug.print("OCIE0A "); Debug.println(1 << OCIE0A); // prints every 10 miliseconds
Debug.print("TIMSK2 "); Debug.println(TIMSK); // prints every 10 miliseconds
}
//_delay_ms(1000);
//TIMSK = 0b00000000;
}
return 0;
}