Affinché si possa generare un RTC è necessario un elemento di sincronizzazione per il tempo. Per tale scopo, è possibile usare uno dei Timer/Counter presenti nell’AVR che, nel caso del TTiny13, è unico e identificato come Timer/Counter0. Questo contatore può essere pilotato mediante un prescaler: cambiando il valore del prescaler si possono ottenere incrementi del contatore ad ogni ciclo di clock del sistema, ogni 8 cicli, ogni 64 e così via, fino a un massimo di un incremento ogni 1024 cicli. Per ottenere l’RTC il contatore viene incrementato dal timer/counter clock che a sua volta è stato inizialmente generato dal clock di sistema. I due segnali di clock vengono divisi per opportuni fattori mediante un prescaler. In dettaglio:
SysClkFrq = System Clock Frequency
SysClkPre = System Clock Prescaler
TimClkFrq = Timer/Counter Clock Frequency
TimClkPre = Timer/Counter Clock Prescaler
Il risultato ottenuto per il TimerClkFreq è in Hertz. Il numero di cicli che avvengono in un tempo di T secondi è dunque (figura 1):
Dato che viene generato un interrupt (al seguente link una panoramica di articoli sull'interrupt) ogni 256 cicli del timer /counter, il numero di interrupt che avvengono nello stesso periodo T è dato da:
Per la realizzazione del Real-Time Clock sarà dunque sufficiente prevedere una variabile da incrementare all’occorrenza di ogni interrupt. In base al numero di interrupts conteggiati, sarà quindi possibile risalire al tempo trascorso. Come regola standard è importante ricordare che più piccolo è il valore impostato per il prescaler, maggiore sarà il numero di interrupts con conseguente maggiore precisione del RTC. Per motivi di praticità, per intervalli di tempo molto lunghi sarà necessario aumentare il valore di prescaler e ovviare alle imprecisioni che assumerà l’RTC avvalendosi dell’uso di variabili multiple. Il listato riportato (listato 1) permette di risalire al numero di minuti trascorsi dall’inizio del conteggio.
///////////////////////////////////////////////////////// // Includes ///////////////////////////////////////////////////////// // Include avr-libc stuff #include <avr/io.h> #include <avr/interrupt.h> #include “types.h” ///////////////////////////////////////////////////////// // Defines ///////////////////////////////////////////////////////// #define STOP_TIMER TCCR0B &= 0xF8 #define START_TIMER TCCR0B |= 0x05 ///////////////////////////////////////////////////////// // Global Varibles ///////////////////////////////////////////////////////// BYTE minutes; BYTE timeout; WORD Ticks256; ///////////////////////////////////////////////////////// // Timer 0 Overflow Interrupt handler ///////////////////////////////////////////////////////// ISR(TIM0_OVF_vect) { // 256 ticks have gone by Ticks256++; // If you do the math you’ll find that if the interrupt goes off 275 times, a minute has passed if (Ticks256 == 275) { // a minute has passed minutes++; Ticks256 = 0; } // do something useful here if you wish; // like checking to see if minutes = 60 perhaps? if (minutes >= 60) { // do whatever you want.. you’ll probably want to reset the minutes variable // so you can start counting all over again } } ///////////////////////////////////////////////////////// // Configure device configures the micro‘s setting per our requirements ///////////////////////////////////////////////////////// void ConfigureDevice(void) { cli(); // disable interrupts just in case // configure PORTB... and other settings TCNT0 = 0x00; // clear Timer/Counter START_TIMER; // enable interrupts on timer 0 overflow TIMSK0 |= _BV(TOIE0); sei(); // enable interrupts } ///////////////////////////////////////////////////////// // Main function ///////////////////////////////////////////////////////// void main(void) { // Configure device ConfigureDevice(); // clear minutes and Ticks minutes = 0; Ticks256 = 0; // Loop forever; the interrupts will take it from here while(1) { } }
Listato 1 |

Il timer o contatore è fondamentale in molti MCU. In alcuni casi può essere utile misurare il tempo trascorso, in altri contare eventi esterni; in fisica, una classica applicazione è misurare il numero di particelle che attraversano/colpiscono un determinato rivelatore.