Modulul periferic TIMER. Ceas, Afisor 8x7Seg

Sarcina:
I)  sa se proiecteze un sistem bazat pe microcontroler care ar permite afişarea conţinutului unui tablou unidimensional de caractere ASCII la un set de afişoare cu 7 segmente;

II) sa se proiecteze un ceas utilizand modulul periferic TIMER1, valoarea curenta a carui va fi reinnoita in tabloul pentru afişare in forma de caractere ASCII.

Microcontrollerele familiei AVR au de la 2 la 4 contoare de timp de uz general, în dependenţă de model







După cum se observă din tabel, în toate modelele familiei ATmega există, cel puţin, două timere/contoare – T0 şi T1. Timer/contor T0 are setul minimal de funcţii, care însă depinde de modelul micorcontrollerului. În unele modele el poate fi utilizat doar pentru numărarea şi măsurarea intervalelor de timp sau contor de evenimente externe. În unele modele la aceste funcţionalităţi se adaugă şi posibilatea generării de semnale cu modulare în lungimea pulsului (PWM - Pulse Width Modulation) cu o rezoluţie fixă, şi posibilitatea de lucru în regim asincron în calitate de ceas al timpului real.
Timer/contor-ul T1 de asemenea poate fi utilizat pentru numărarea intervalelor de timp şi ca contor al evenimentelor externe. În afară de aceea, el poate memora starea sa în dependenţă de semnale externe. Ca şi timer/contor-ul T0, el poate lucra în regim PWM, dar deja cu o rezoluţie variabilă şi cu mai multe canale (numărul de canale depinde de model).
Timer/contor-ul T2 e absolut analogic timer/contor-ului T0. Dacă în microcontroller sunt prezenţi ambii timer/contori, unul poate lucra în regim asincron, altul – în calitate de contor a evenimentelor externe. Timer/contor-ul T3 după posibilităţile funcţionale e identic timer/contor-ului T1.
Întreruperea TIMER
Modulul de întrerupere timer este un modul periferic inclus în majoritatea controllerelor seriei AVR, care la rândul său poate conţine de la 1 până la 3 module TIMER.
Modulul TIMER de regulă se foloseşte pentru măsurarea timpului. În cazul când avem nevoie de măsurat frecvenţa, generarea unui semnal de o anumită frecvenţă şi alte efecte ce presupun folosirea timpului, se recomandă aplicarea modului TIMER. Componen ţa principală al acestui modul este registrul numărător TCNT.
Modulele Timer/Conters
Modulul de timer este cel mai fregvent modul utilizat. Un microntroller poate conţine de la 1 – 3 timere. Un modul timer are la bază un numărător care incrementează un registru, acest registru numărător poate fi de 8 sau 16 biţi. Modulul timer 0 se poate utiliza pentru formarea intervalelor între generarea întreruperii de timp.
Situaţia de întrerupere va fi provocată la supraîncărcarea registrului contor. Odată întreruperea generată poate chema o funcţie de prelucrare a ei.
ATmega16 dispune de două numărătoare/timere de uz general, unul de 8 biţi şi unul de 16 biţi. Fiecăruia i se poate selecta o valoare individuală pentru prescaler din acelaşi prescaler de 10 biţi. Ambele module pot fi folosite ca timere cu un clock generat intern sau ca numărătoare cu un clock extern de la un pin I/O. Cele 4 valori pentru prescaler sunt CK/8, CK/64, CK/256 şi CK/1024 unde CK este clock-ul dat de oscilatorul extern. Ambele timere pot genera întreruperi ale căror biţi de validare se află în registrul Timer/Counter Interrupt Mask Register (TIMSK) şi ale căror flaguri de întrerupere se află in registrul Timer/Counter Interrupt Flag Register (TIFR).
Timer/Counter0 este un numărător pe 8 biţi. Registrul de control al acestuia este Timer/Counter0 Control Register (TCCR0) din care se setează valoarea prescalerului, ceasul intern sau extern şi starea pornit/oprit a modulului. La trecerea din 0xFF în 0x00 flagul overflow este setat şi este generată întreruperea TMR0_OVR dacă aceasta este validată. Ceasul extern este sincronizat cu oscilatorul microcontrollerului. Pentru a asigura o numărare corectă a impulsurilor externe, durata dintre două tranziţii ale clock-ului extern trebuie să fie mai mare ca perioada oscilatorului microcontrolerului.
Timer/Counter1 este un numărător pe 16 biţi. Registrele de control ale acestuia sunt Timer/Counter1 Control Registers (TCCR1A and TCCR1B). Diferite flaguri de stare (overflow, captura unui eveniment, etc) se află în registrul Timer/Counter Interrupt Flag Register (TIFR). De asemenea ceasul extern trebuie să îndeplinească condiţia ca perioada dintre două tranziţii să fie mai mare decât perioada oscilatorului microcontrollerului pentru a asigura o funcţionare corectă a modulului.
    Modulul Timer/Counter1 suportă funcţia de comparare folosind registrele Output Compare Register 1 A şi B (OCR1A şi OCR1B) pe care le compară cu registrul TCNT1. Funcţiile de comparare includ resetarea numărătorului la egalitatea cu registrul OCR1A sau alte acţiuni pe pinii de ieşire la egalitatea cu ambele registre A şi B. Modulul poate fi utilizat şi ca modulator de impulsuri în durată pe 8, 9 sau 10 biţi. De asemnea funcţia Input Capture poate salva conţinutul TCNT1 în registrul Input Capture Register (ICR1) la apariţia unui eveniment extern pe pinul de captură ICP. Setările evenimentului de captură sunt definite de registrul Timer/Counter1 Control Registers B (TCCR1B). În plus modulul Analog Comparator poate genera evenimentul de captură.
Pentru configurarea modulului Timer/Counter 0 se utilizează registrul TCCR0, iar pentru a configura frecvenţa apariţiilor situaţiilor de întrerupere se va seta prescalerul ce se află în TCCR0.



CS02, CS01, CS00 - cu ajutorul lor vom seta viteza de progresie a timerului.
Tabelul de adevăr:

Situaţia de întrerupere va fi generată la supraîncărcarea registrului TCNT0.


Fig.1 Prezentarea grafică a funcţionării Timerului.
Pentru a configura fregvenţa apariţiei situaţiei de intrerupere se va seta prescalerul care se configura în TCCR0.
Pentru a seta mai fin întreruperea trebuie de reiniţializat registrul TCNT la fiecare întrerupere.
Pentru a organiza un sistem care va utiliza întreruperea de Timer trebuie să:
  • validăm utilizarea modulului întreruperii din registrul TIMSK;
  • înregistrăm în vectorul de întreruperi chemarea funcţiei de prelucrare a întreruperii;
  • descriem subrutina de prelucrare a întreruperii;
Fiecare modul periferic are regiştri in spaţiu de 64 I/O. Comunicaţia modulelor periferice are loc prin intermediul acestor regiştri. Există 3 tipuri de regiştri periferice:
  • TCNT0 - de date (transfer de date dintre nucleu şi periferie)
  • TCCR0 - de configurare (se utilizează pentru configurarea modulului periferic)
  • TIFR, TIMSK - de fanioane(reprezintă starea curenta a modulului periferic)
Regiştri de multe ori sunt combinaţi cei de configurare şi fanioane. Registrul TCNT (timer counter) conţine 8 biţi. Trecerea valorii registrului de numărare de la valoarea maximală în zero, se numeşte supraîncărcare/depăşire (overflow). Evenimentul de supraîncărcare este legat cu modulul de întrerupere a timer-ului. Când are loc depăşirea , se setează un bit TIFR.TOUF0 în 1.
Frecvenţa apariţiei întreruperii Timer overflow poate fi reglată prin:
  • Reglarea prin setarea divizorului de la semnalul de clock pentru sursa de încrementare.
  • Setarea valorii iniţiale.
Regimurile de lucru ale Modulul TIMER
Modulul TIMER poate lucra în mai multe regimuri:
1)  Numărător – destinat lucrului cu timpul.
2)  Imput Capture – capturarea intrării care presupune determinarea apariţiei unui eveniment extern. Principala sarcină a unităţii de capturare la intrare este de a pune la dispoziţie suficientă memorie din cea a procesorului pentru apariţia de evenimente eventuale. Timpul dintre două evenimente este critic. Dacă procesorul nu a citit valoarea asociată capturii în Registrul ICR1, înainte de apariţia unui nou eveniment ICR1 va fi suprascris cu o nouă valoare. În acest caz valoarea asociată capturii va fi incorectă. Utilizând input capture interrupt, registrul ICR1 poate fi citit înaintea producerii rutinei întreruperilor. Chiar dacă input capture interrupt are prioritate ridicată, timpul maxim de răspuns la întrerupere depinde de numărul maxim de cicluri necesare tratării unei cereri de întrerupere. Durata unui ciclu pentru un semnal extern impune ca declanşatorul de nivel să fie schimbat după fiecare captură.
3) Output Capture – modul în care se poate genera un semnal extern la coincidenţa registrului timer cu o valoare prestabilită. Comparatorul pe 16 biţi compară TCNT1 cu ieşirea registrului Output Compare Register (OCR1x). Dacă TCNT este egal cu OCR1x comparatorul semnalizează o potrivire. Aceasta setează Output Compare Flag (OCF1x) pentru următorul ciclu de ceas. Dacă OCIE1x =1, Output Compare flag generează o ieşire output compare interrupt. OCF1x flag este dezactivat automat atunci când se execută o întrerupere. OCF1x flag poate fi de asemenea dezactivat prin trecerea în ‘1’ logic a bitului I/O. Ţinând cont că scrierea lui TCNT1 în orice mod de operare va bloca orice comparare pentru un singur ciclu de ceas, există riscuri la schimbarea unuia din canalele output compare ale lui TCNT1 indiferent dacă Timer/Counter este pornit sau oprit. Dacă TCNT1 este egal cu OCR1x rezultatul comparării va fi pierdut, generându-se o formă de undă greşită.
4) Puls Width Modulation (PWM) – modulaţia impulsurilor de durată. Permite modularea unui semnal cu bandă reglabilă, modulată.
Watch Dog Timer
Microcontrollerul seriei AVR are inclus în componenţa sa modulul Watch Dog, ce permite resetarea sistemului în caz de un comportament de ciclare al său.
Mersul lucrării:
I ) sa se proiecteze un sistem bazat pe microcontroler care ar permite afişarea conţinutului unui tablou unidimensional de caractere ASCII la un set de afişoare cu 7 segmente;
Schema Bloc:










Codul sursă:
#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\delay.h>

char data[]="04122013";
int i=0;

void test(void){
int k=0;
while (k<2){
for (int i=0; i<6;i++){
PORTC=0b00000000;
PORTA=(1<<i);
_delay_ms(100);
}
k++;}
PORTA=0xFF;
_delay_ms(200);
PORTA=0x00; }
                                                                                                                     


//Functia DECOD
char decod(char c){
switch (c){
case '0': {c=0b00111111; break; }
case '1': {c=0b00000110; break;       }
case '2': {c=0b01011011; break;       }
case '3': {c=0b01001111; break;       }
case '4': {c=0b01100110; break;       }
case '5': {c=0b01101101; break;       }
case '6': {c=0b01111101; break; }
case '7': {c=0b00000111; break; }
case '8': {c=0b01111111; break;       }
case '9': {c=0b01101111; break; }
default: c=0x00;
}
return c;
}
                                                                                                                      // Functia MAIN
void main(void){

// Waveform Generation Mode setarea regimului Normal
TCCR0=(0<<CS00)|(1<<CS01)|(0<<CS02)|(0<<WGM01)|(0<<WGM00);  // CK/8
TIMSK = (1<<TOIE0);                                   // permiterea intrerupeti in situatia de owerflov a TCNT0
DDRA=0xFF;
DDRC=0xFF;
PORTA=0x00;
PORTC=0x00;
test();
sei();                // permitera intreruperi
while(1){  }
}

ISR(TIMER0_OVF_vect){
if ((i<7) & (i>=0))
i++;
else i=0;
            PORTC=~(1<<i);
            if (i==1) PORTA=decod(data[i])|(1<<7);
            else if (i==3) PORTA=decod(data[i])|(1<<7);
            else      PORTA=decod(data[i]);
}


II ) sa se proiecteze un ceas utilizand modulul periferic TIMER1, valoarea curenta a carui va fi reinnoita in tabloul pentru afişare in forma de caractere ASCII.
Schema bloc:

Codul sursă:

#include <avr/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define DEL    _delay_ms(1)

char tab[7];

char decod( char digit){
char retval;
switch (digit){
            case 0:  {retval=0b00111111;   break; }
            case 1:  {retval=0b00000110;   break; }
            case 2:  {retval=0b01011011;   break; }
            case 3:  {retval=0b01001111;   break; }
            case 4:  {retval=0b01100110;   break; }
            case 5:  {retval=0b01101101;   break; }
            case 6:  {retval=0b01111101;   break; }
            case 7:  {retval=0b00000111;              break; }
            case 8:  {retval=0b01111111;   break; }
            case 9:  {retval=0b01101111;   break; }
default :retval=0b00000000;
}
return retval;
}
//**********************************************************
void afis(void){
for (int i=0; i<6; i++){
PORTC=~(1<<i);
if (i==2) PORTA=decod(tab[i])|(1<<7);
else if (i==4) PORTA=decod(tab[i])|(1<<7);
else PORTA=decod(tab[i]);
DEL;
}
}
//***********************************************************
void main(void){
DDRA=0xFF;
PORTA=0x00;

DDRC=0x3F;
PORTC=0xFF;

TCCR1B = (1<<CS12)|(1<<CS10)|(1<<WGM12);                  // /1024 regim CTC
OCR1A = 976;
TIMSK = 1<<OCIE1A;           //permitera intrerupeti ‚egalitate’
sei();

while (1){
afis();   }   }
//********************************************************
 ISR(TIMER1_COMPA_vect)
{         
                                                                       //secunde
tab[0]++;
 if (tab[0]>9) { tab[0]=0;        
tab[1]++;}
                                               // minute
if (tab[1]>5) {tab[2]++;                      
tab[1]=0;}
 if (tab[2]>9) {tab[3]++;                     
tab[2]=0; }
 if (tab[3]>5) {tab[4]++;                     
tab[3]=0;}                                // ore
 if (tab[4]>4) {tab[5]++;                     
tab[4]=0;}
 if (tab[5]>2) {tab[5]=0;} 
}