Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:lab:lab2-2022 [2022/05/01 14:26]
florin.stancu
pm:lab:lab2-2022 [2024/03/17 09:54] (current)
florin.stancu
Line 5: Line 5:
 ~~SHOWSOLUTION~~ ~~SHOWSOLUTION~~
  
-====== Laboratorul 2: Întreruperi, Timere ​======+====== Laboratorul 2: Întreruperi ​hardware. Întreruperi externe ​======
  
-Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile hardware și cu timer-ele prezente în microcontroller-ul Atmega328p. Vom folosi ​timer-ele doar pentru a număranu și pentru a genera semnal PWM. Această funcționalitate va fi studiată și utilizată în laboratoarele următoare.+Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile hardware și în particular ​cu întreruperile externe. Vom folosi ​întreruperi externe ​pentru a detecta imediat (în timp real) apăsarea unui butonindependent de programul principal.
  
 ===== 1. Întreruperi ===== ===== 1. Întreruperi =====
Line 54: Line 54:
  
  
-==== 1.1. Utilizarea întreruperilor ====+==== Utilizarea întreruperilor ====
  
 În general, pașii parcurși pentru a activa o întrerupere sunt următorii: În general, pașii parcurși pentru a activa o întrerupere sunt următorii:
Line 68: Line 68:
 cli(); cli();
 </​file>​ </​file>​
 +
 +În general, pașii parcurși pentru a activa o întrerupere externă INT sau PCINT sunt următorii:
  
 === Configurăm perifericul care va trimite întreruperile === === Configurăm perifericul care va trimite întreruperile ===
 +
 +De exemplu, pentru ''​INT0''​ și ''​INT1''​ (pinii ''​PD2''​ și ''​PD3''​),​ configurarea se face din registrul ''​EICRA''​ (External Interrupt Control Register A, secțiunea 12.2.1, pagina 54 din {{:​pm:​atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|datasheet}},​ în timp ce pentru întreruperi de tip pin change se folosește registrul ''​PCICR''​. ​
  
 <file c> <file c>
-// exemplu de configurare pentru Timer 1 în mod CTC, care va genera ​întreruperi ​cu frecvența de 2Hz +// întreruperi ​externe 
-OCR1A = 31249; ​           // compare match register 16 MHz/256/2 Hz - 1 +EICRA |= (1 << ​ISC00);    // set INT0 to trigger on ANY logic change 
-TCCR1B ​|= (1 << ​WGM12);   ​// CTC mode +// întreruperi de tip pin change (activare vector de întreruperi) 
-TCCR1B ​|= (1 << ​CS12);    // 256 prescaler ​+PCICR |= (1 << ​PCIE2); // enable the pin change interrupt, set PCIE2 to enable PCMSK2 scan 
 +// alte întreruperi
 </​file>​ </​file>​
-        ​+   
 +<note tip> 
 +O întrerupere externă poate fi configurată astfel încât **să detecteze tranziția semnalului logic** pe front crescător, descrescător sau oricare (vezi tabelul 13-1 din {{:​pm:​atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|datasheet}}). În comparație,​ o întrerupere de tip pin change este generată la modificarea **nivelului logic** al semnalului, iar valoarea semnalului **trebuie verificată explicit în codul întreruperii**. 
 +</​note>​ 
 +          ​
 === Scriem rutina de tratare a întreruperii === === Scriem rutina de tratare a întreruperii ===
  
-Rutinele de tratare a întreruperii trebuie menționate în memorie la anumite adrese fixe (în vectorul de întreruperi). Pentru a face acest lucru folosim macro-ul de ISR(), care primește ca parametru tipul de întrerupere ce este tratată. +De exemplu, pentru întreruperile de tip ''​INT0'',​ respectiv ''​PCINT2''​, codul va arăta în felul următor:
- +
-De exemplu, pentru întreruperile ​generate ​de Timer 1 în mod CTC, codul va arăta în felul următor:+
  
 <file c> <file c>
-// implementare rutină de tratare a întreruperii TIMER1_COMPA +ISR(INT0_vect) 
-ISR(TIMER1_COMPA_vect) { +
-  // cod întrerupere ​de la Timer1+  // cod întrerupere ​externă PD2 /INT0 
 +  // verificare tranziție pe front crescător, descrescător sau oricare 
 +  // (după cum este configurat INT0)
 } }
  
 +ISR(PCINT2_vect){
 +  // cod întrerupere de tip pin change
 +  if ((PIND & (1 << PD4)) == 0){
 +     // întreruperea a fost generată de pinul PD4 / PCINT20
 +     // verificăm nivelul logic al pinului
 +  }
 +  // întreruperea a fost generată de alt pin
 +}
 </​file>​ </​file>​
 +
 +<note important>​
 +Dacă avem mai multe întreruperi pe același vector (de ex. mai multe butoane), nu se poate determina cu exactitate care dintre butoane a generat întreruperea de tip PCINT. În plus, este posibil să apară mai multe întreruperi în timp ce starea unui pin verificat să rămână neschimbată,​ caz în care va fi detectată o nouă apăsare în mod eronat.
 +</​note>​
  
 === Activăm întreruperea și testăm programul === === Activăm întreruperea și testăm programul ===
 +  ​
 +În cazul de față, pentru activarea întreruperilor externe, se configurează registrul External Interrupt Mask Register (''​EIMSK''​) astfel:
 +   * biții ''​INT1:​0''​ controlează dacă întreruperile externe (INT0-INT1) sunt activate
 +Pentru celelalte întreruperi,​ se configurează registrul corespunzător (e.g. ''​PCMSK2''​ pentru activarea întreruperilor de tip pin change pe fiecare pin de pe portul D)
   ​   ​
 <file c> <file c>
-// activare ​întrerupere ​TIMER1_COMPA +// întrerupere ​externă 
-TIMSK1 ​|= (1 << ​OCIE1A); +EIMSK |= (1 << ​INT0);     // Turns on INT0 
-// activare întreruperi ​la nivel global+// întrerupere de tip pin change 
 +PCMSK2 |= (1 << PCINT20); // Turns on PCINT20 (PD4) 
 +// activare întreruperi ​globale
 sei(); sei();
 </​file>​ </​file>​
  
  
-==== 1.2. Lucrul cu întreruperi ====+ 
 +==== Lucrul cu întreruperi ====
  
 Reguli de programare în context întrerupere:​ Reguli de programare în context întrerupere:​
  
   * Nu există o valoare de return. La închierea execuției handler-ului,​ procesorul execută din nou instrucțiuni de unde rămăsese înainte de declanșarea întreruperii   * Nu există o valoare de return. La închierea execuției handler-ului,​ procesorul execută din nou instrucțiuni de unde rămăsese înainte de declanșarea întreruperii
-  * Datorită faptului că handler-ul întârzie orice altă activitate din main și inhibă execuția altor întreruperi,​ se dorește ca timpul de execuție să fie cât mai mic. +  * Datorită faptului că handler-ul întârzie orice altă activitate din main și inhibă execuția altor întreruperi,​ se dorește ca **timpul de execuție să fie cât mai mic**
-  * La folosirea unor variabile comune în mai multe handler-e de întrerupere și/sau main trebuie avut în vedere accesul concurent la acestea (în special la variabilele de 16/32 biți a căror modificare necesită mai mulți cicli de procesor).+  * La folosirea unor variabile comune în mai multe handler-e de întrerupere și/sau main trebuie avut în vedere ​**accesul concurent** la acestea (în special la variabilele de 16/32 biți a căror modificare necesită mai mulți cicli de procesor).
   * Variabilele comune trebuie marcate ca ''​volatile''​ pentru ca accesele la acestea să nu fie optimizate de către compilator   * Variabilele comune trebuie marcate ca ''​volatile''​ pentru ca accesele la acestea să nu fie optimizate de către compilator
  
Line 118: Line 146:
   * **reti()** - întoarcerea dintr-o rutină de tratare a intreruperii,​ activează întreruperile globale. Ar trebui sa fie ultima instrucțiune apelată într-o rutină care folosește flag-ul ISR_NAKED.   * **reti()** - întoarcerea dintr-o rutină de tratare a intreruperii,​ activează întreruperile globale. Ar trebui sa fie ultima instrucțiune apelată într-o rutină care folosește flag-ul ISR_NAKED.
  
-<note important>​Întreruperile ​întâlnite ​care nu au o rutină de tratare vor cauza o întrerupere de reset!</​note>​+<note important>​Întreruperile ​active ​care nu au specificată ​o rutină de tratare ​**vor cauza o întrerupere de reset**!</​note>​
  
  
-===== 2. Timer =====+===== 2. Întreruperi externe. INT vs. PCINT ===== 
 +Întreruperile se pot împărți în două categorii:​ 
 +  * întreruperile componentelor //​interne//:​ timere, interfețe seriale (USART), convertor analog-digital 
 +  * întreruperile componentelor //​externe//:​ activate de pinii externi ai uC-ului
  
 +Pe lângă întreruperile componentelor interne uC-ului, există și câteva linii pentru întreruperi de la periferice externe: **INT0-INT1** și **PCINT0-PCINT2**. Diferența dintre aceste două tipuri de întreruperi externe este dată de capabilitățile suportate și de granularitatea lor.
  
-==== 2.1Principiul ​de funcționare al unui Timer ====+Semnalele pentru întreruperile **INTn** pot genera o întrerupere la tranziție (crescătoare,​ descrescătoare sau ambele) sau pe nivel 0, în funcție de configurarea întreruperiiÎntreruperile **PCINTn** (Pin Change INTerrupt) se declanșează la ambele tranziții (mai exact, atunci când se face toggle la valoare) și câte 8 pini sunt multiplexați pe o singură întrerupereSemnalele ​de întrerupere PCINT se pot activa individual, însă pentru a afla exact ce semnal a declanșat o anumită întrerupere trebuie verificat registrul PINn corespunzător. Dacă mai multe semnale se declanșează în același timp, ele nu vor putea fi deosebite.
  
-Timer-ul/​Counter-ul oferă facilitatea ​de a măsura intervale fixe de timp și de a genera întreruperi la expirarea intervalului măsuratUn timer, odată inițializat va funcționa independent de unitatea centrală ​(UCP). Acest lucru permite eliminarea buclelor de delay din programul principal.+<note important>​În cazul întreruperilor ​de tip pin change interrupt, ​nu se confunda vectorul ​de tratare ​întreruperilor ex. PCINT2 cu întreruperea efectivă exPCINT20 ​(PD4). Maparea dintre vector și întreruperi se poate găsi în secțiunea 30 pag. 278 din {{:​pm:​atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|datasheet}}</​note>​
  
-Componentele și funcționarea unui timer pentru ATmega328p pot fi descrise ​în linii mari de cele trei unități din figura de mai jos:+===== 3. Întreruperi externe ​în Arduino =====
  
-{{.:​lab2:​timer_block.png?​600|Componentele ​și funcționarea unui timer pentru ATmega324}}+Deși noi vom lucra în principal cu registre, în Arduino, întreruperile se mai pot configura folosind ​funcția **attachInterrupt()**. 
 +Funcția primește ca parametru numărul întreruperii externe (pe Arduino UNO avem INT0, INT1), funcția care va fi apelată (echivalent ISR), și modul prin care se face detecția tranziției:​
  
-  ​**Registrul numărător** (Timer Counter, TCNT) - măsoară efectiv intervalele de timp și este incrementat automat cu o frecvență dată. +  * LOW: nivel logic 0 
-  ​**Prescaler-ul** - are rolul de a diviza în funcție de necesitățile aplicației frecvența de ceas. +  * CHANGE: tranziție de nivel logic 
-  ​- La fiecare incrementare a ''​TCNT''​ are loc o **comparație între acest registru și o valoare stocată în registrul ''​OCRn''​**. Această valoare poate fi încarcată de către programator prin scrierea registrului ''​OCRn''​. Dacă are loc egalitatea se generează o întrerupere,​ în caz contrar incrementarea continuă.+  * RISING: front crescător 
 +  ​FALLING: front descrescător
  
 +Dezactivarea întreruperilor externe se poate face cu funcția **detachInterrupt()**
 +Activarea sau dezactivarea temporară a tuturor întreruperilor se poate face cu funcțiile **noInterrupts()** și **interrupts()**
  
-Timer-ele sunt prevăzute cu mai multe canale astfel încât se pot desfășura diferite număratori în paralel. ATmega328p este prevăzut cu 3 unități de timer: două de pe 8 biți și una de 16 biți.+<file c> 
 +int counter = 0;
  
-Timer-ele pot funcționa și în moduri PWM, astfel încat să genereze pe un pin de ieșire un semnal de comandă cu tensiune ​(medievariabilă. Mai multe detalii veți afla în laboratoarele următoare.+void myCallback() 
 +  counter += 1; 
 +}
  
-==== 2.2. Moduri de funcționare ====+void setup() { 
 +  pinMode(2, INPUT_PULLUP);​ 
 +  attachInterrupt(0,​ myCallback, FALLING); 
 +}
  
-Timer-ele oferă mai multe moduri de funcționare ​(cu mici diferențe între Timer/​Counter0,​ Timer/​Counter1 și Timer/​Counter2), ce se diferențiaza prin: +void loop() { 
-  ​* valorile până la care se face incrementarea +  ​Serial.print("​numar apasari: "); 
-  ​* felul în care se numără ​(doar crescător, sau alternativ crescător/​descrescător+  ​Serial.println(counter); 
-  ​* când se face resetarea contorului+  ​delay(1000);​ 
 +
 +</​file>​
  
-În următorul tabel sunt prezentate cele două moduri pe care le vom folosi în acest laborator. 
  
-^ Mod ^ Descriere ^ Imagine contor ^ Proprietăți ^ +<​hidden>​ 
-|  **Normal **  | - pornește de la 0 \\ - numără până la 0xFFFF | {{.:lab2:​timer_normal_v2.png?​350|Modul Normal}} | frecvența este fixată la câteva valori predefinitedate de frecvența ceasului și de prescaler | +AABadd more info about debouncing, some photos from oscilloscope maybe... 
-|  **CTC \\ Clear Timer on Compare** ​ | - pornește de la 0 \\ - numără până când se atinge un prag (''​OCRnA''​ pentru Timer 0/2, ''​OCR1A''​ sau ''​ICR1''​ pentru Timer 1) | {{.:​lab2:​timer_ctc_v2.png?​350|Modul CTC}}| frecvența este variabilă, determinată de valoarea pragului, frecvența ceasului și de prescaler |+mention some simple debouncing methodslike using delays 
 +</hidden>
  
-Definiții care apar în datasheet:​ +===== 4. Exerciții =====
-  * **BOTTOM**: capătul inferior din intervalul de numărare +
-  * **TOP**: capătul superior al intervalului de numărare +
-  * **MAX**: ​ limita superioară a numărării,​ 255 (0xff) pentru 8 biți, 65535 (0xffff) pentru 16 biți. **TOP** poate fi **MAX** în anumite moduri de funcționare (ex: //​Normal//​).+
  
-==== 2.3Registre ====+=== Task 1 (întreruperi / butoane) - 6p ===  
 +Folosiți întreruperi externe (INT și/sau PCINT) pentru a detecta apăsarea unui buton conectat la ''​PD2''​ (pin 2) și a unuia conectat la ''​PD4''​ (pin 4)Modificați starea unui LED conectat la ''​PD7''​ (pin 7) în ISR.
  
-^ Timer ^ Registre ^ Rol ^ +  ​Configurați întreruperea externă ​(INT) pe front descrescător (falling edgesau PCINT-ul corespunzător pinului folosit 
-|  **Timer0** ​ \\ \\  **8 biți**  | ''​TCNT0''​ | Registrul contor al timer-ului 0 (cel care numără) | +  * Modificați starea LED-ului la apăsarea oricărui buton (PD2PD4)
-| ::: | ''​TCCR0A'',​ ''​TCCR0B''​ | Registre de control ale timer-ului 0 (diverși biți pentru configurarea timer-ului)+
-| ::: | ''​OCR0A'',​ ''​OCR0B''​ | Registre prag pentru timer-ul 0 (prag al numărătorii la care se poate declansa intreruperea,​ în funcție de configurare) | +
-| ::: | ''​TIMSK0'',​ ''​TIFR0''​ | Registre cu biți de activare întreruperi timer 0 / flag-uri de activare (activați întreruperile) | +
- **Timer1** ​ \\ \\   **16 biți**  | ''​TCNT1'' ​ | Registrul contor al timer-ului 1 (la fel ca la timer0, doar că pe 16 biți) | +
-| ::: | ''​TCCR1A''​ \\ ''​TCCR1B''​ \\ ''​TCCR1C''​ | Registre control ale timer-ului 1 (la fel ca la timer0) | +
-| ::: | ''​OCR1A'' ​''​OCR1B''​ | Registre prag pe 16 biți ale timer-ului 1 (la fel ca la timer0+
-| ::: | ''​TIMSK1'',​ ''​TIFR1''​| (la fel ca la timer0) | +
-| ::: | ''​ICR1''​ | Registru folosit pentru a reține valoarea contorului la apariția unui eveniment extern pe pin-ul ''​ICP''​ sau ca prag pentru unul din modurile CTC| +
-|  **Timer2** ​ \\ \\  **8 biți** ​ | aceleași registre ca la Timer0 | Diferența față de Timer-ul 0 este posibilitatea folosirii unui oscilator extern separat pentru Timer-ul 2, \\ pe pinii ''​TOSC1''​ și ''​TOSC2''​ | +
-| ::: | ''​ASSR'',​ ''​GTCCR''​ | Registre ce țin de funcționarea asicronă a acestui timer față de restul sistemului ​ |+
  
-<note tip>​Întreruperile sunt activate doar dacă bitul ''​I''​ din ''​SREG''​ este setat (întreruperile sunt activate global) +**Tinkercad** - Testați programul folosind următorul montaj:
-</​note>​+
  
-==== 2.4. Lucrul cu Timer-ul ==== +{{:​pm:​lab:​lab3_2021:​button_led_interrupts.png?600|}}
-=== Setarea modului de funcționare ===+
  
-Pentru a configura un mod de funcționare,​ vom seta: 
-  * biții ''​WGM''​ din timer-ul respectiv (care se găsesc în registrele ''​TCCRnA''​ din datasheet, la secțiunile aferente timerelor, "​Register Description"​) 
-  * pragul de numărare 
  
-De exemplu, ca să setăm timer-ul 0 să numere până la 5, ne vom uita în datasheet la capitolul 14 (//8-bit Timer/​Counter0 with PWM//) - secțiunea //Register Description//​ -> //TCCR0A// +**Arduino** - Încărcați codul pe placă și observați comportamentul. La apăsarea butonului, LED-ul își schimbă starea o singură dată? Adăugați o metodă de [[https://www.arduino.cc/en/Tutorial/BuiltInExamples/Debounce|debouncing]] pentru a detecta o singură apăsare pe buton: 
-  ​- găsim modul ''​CTC''​ ca având biții ''​0 1 0''​ pe biții ''​WGM2..0''​ +  ​* NU este recomandat să folosiți delay în ISR 
-  ​- aflăm că modul ''​CTC''​ numără până la ''​OCRA''​+  ​* Se poate folosi funcția //​millis()//​ pentru a verifica intervalul de timp de la ultima apăsare (100 ms ar trebui să fie suficient pentru un pushbutton/​microswitch,​ dar ajustați după caz) 
  
-Presupunând că plecăm de la un registru complet neinițializat (0 este valoarea default pentru majoritatea biților), avem următorul cod: 
 <file c> <file c>
 +ISR(INT0_vect)
 +{
 +  // cod întrerupere externă
 +  PORTD ^= (1 << PD7);
 +}
  
-TCCR0A |= (1 << WGM01); +ISR(PCINT2_vect{ 
-OCR0A = 5;+  // cod întrerupere de tip pin change 
 +  // TODO 
 +}
  
-</file>+void setup_interrupts() { 
 +  ​// buton 1: PD2 / INT0 
 +  // buton 2: PD4 / PCINT20 
 +  cli();
  
 +  // input
 +  DDRD &= ~(1 << PD2) & ~(1 << PD4);
 +  // input pullup
 +  PORTD |= (1 << PD2) | (1 << PD4);
  
-=== Setarea prescaler-ului ===+  // configurare intreruperi 
 +  // intreruperi externe 
 +  // TODO
  
-Pentru setarea prescaler-ului se vor modifica biții ​tip ''​CS..''​ din registrul ''​TCCRnB''​ al timer-ului respectiv.+  // întreruperi de tip pin change (activare vector de întreruperi) 
 +  // TODO
  
-De exemplu, pentru setarea valorii de prescaler 256 pentru timer-ul 2, vom urmări în datasheet capitolul 17 (//8-bit Timer/Counter2 with PWM//) - secțiunea ​//Register Description//​ -> //​TCCR2B//​ +  ​// activare intreruperi 
-  - găsim tabelul pentru valorile ''​CS..''​ +  ​// intrerupere externa 
-  - aflăm că prescaler-ul 256 corespunde biților ''​1 1 0''​ pentru biții ''​CS22 CS21 CS20''​+  ​// TODO
  
-Presupunând că plecăm ​de la un registru complet neinițializat (0 este valoarea default pentru majoritatea biților), avem următorul cod: +  // întrerupere ​de tip pin change 
-<file c> +  /TODO
-TCCR2B |= (1 << CS22) | (1 << CS21); +
-</file>+
  
- +  ​sei();
-=== Configurarea întreruperilor === +
- +
-Pentru un timer deja configurat, pentru a activa întreruperile trebuie doar să activăm bitul corespunzător din ''​TIMSKx''​ +
- +
-De exemplu, pentru pragul A al timer-ului 1 vom scrie: +
- +
-<file c > +
-ISR(TIMER1_COMPA_vect) { +
-  // cod întrerupere  +
-+
- +
-void configure_timer1() { +
-  // exemplu de configurare pentru Timer 1 în mod CTC +
-  // care va genera întreruperi cu frecvența de 2Hz +
-  TCCR1A = 0; +
-  TCCR1B = 0; +
-  TCNT1 = 0; +
-  OCR1A = 31249; ​           // compare match register 16MHz/​256/​2Hz-1 +
-  TCCR1B |= (1 << WGM12); ​  ​// CTC mode +
-  TCCR1B |= (1 << CS12); ​   // 256 prescaler  +
-+
- +
-void init_timer1() { +
-  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt+
 } }
  
 void setup() { void setup() {
-  ​// dezactivăm întreruperile globale +  ​setup_interrupts(); 
-  cli();   +  ​DDRD |= (1 << PD7); 
-  ​configure_timer1(); +  ​PORTD &= ~(1 << PD7);
-  ​init_timer1();​ +
-  // activăm întreruperile globale +
-  sei();+
 } }
  
-void loop() { +void loop() {   
 +  
 } }
 </​file>​ </​file>​
  
-==== 2.5Calculator ====+<​hidden>​ 
 +**Soluția** se găsește pe [[https://​www.tinkercad.com/​things/​cVPb9x8NUbX|Tinkercad Button Led Interrupts]] 
 +</​hidden>​
  
-În general, pentru configurarea unui Timer, este necesară alegerea unui prescaler ​și a unei limite de numărareîn funcție de perioada dorită ​și de frecvențde lucru a procesorului ​(e.g. 16 MHz pentru Arduino UNO) și de modul de funcționare ales. Un exemplu ​de calcul este prezentat mai jos:+=== Task 2 (blink control) - 4p ===  
 +Pe baza aceluiași montajfolosiți întreruperi externe (INT și/sau PCINT) pentru ​detecta apăsarea unui buton conectat la ''​PD2'' ​(pin 2) și a unuia conectat la ''​PD4''​ (pin 4). Modificați intervalul ​de semnalizare (blink) al unui LED conectat la ''​PD7''​ (pin 7) în ISR astfel:
  
-  * calcul frecvență întreruperi în funcție de frecvența ceasului ​și a pragului de numărare:+  * butonul conectat la ''​PD2''​ crește intervalul cu 100 ms 
 +  * butonul conectat la ''​PD4''​ scade intervalul cu 100 ms
  
-''​f_int = f_clk / (prescaler * (tc + 1))''​ +<file c>
-  * calcul prag de numărare al timer-ului pentru a obține frecvența dorită:+
  
-''​tc ​f_clk / (prescaler * f_int) - 1''​+volatile int dt 500;
  
-Observăm că trebuie aleasă o valoare convenabilă pentru prescaler ​(din cele disponibile,​ ex. 8, 64, 256, 1024și un prag de numărare (0-255 pentru timer-e pe 8 biți, 0-65535 pentru timer-e pe 16 biți) astfel încât să se obțină frecvența exactă.+ISR(INT0_vect) 
 +
 +  // cod întrerupere externă 
 +  // TODO 
 +}
  
 +ISR(PCINT2_vect) {
 +  // cod întrerupere de tip pin change
 +  // TODO
 +}
  
-Există calculatoare care pot fi utile pentru determinarea rapidă a valorilor pentru registrele de configurare ale unui Timer precum:+// setup_interrupts() la fel ca la Task 1
  
-{{url>​https://​web.archive.org/​web/​20180312235028/​https://​et06.dunweber.com/​atmega_timers/​|ATmega Timer/​Counter/​Prescaler calculator}}+void setup() ​{ 
 +  setup_interrupts();​ 
 +  DDRD |= (1 << PD7); 
 +  PORTD &= ~(1 << PD7); 
 +}
  
 +void loop() {  ​
 +  PORTD |= (1 << PD7);
 +  delay(dt);
 +  PORTD &= ~(1 << PD7);
 +  delay(dt);
 +}
  
-===== 3. Afișaje cu 7 segmente===== 
- 
-Afișajele LED cu 7 segmente sunt utilizate în multe aplicații ca indicatoare numerice pe panoul frontal. Cele mai comune aplicații sunt calculatoarele,​ ceasurile digitale, cuptoarele cu microunde, echipamentele electronice de laborator, cum ar fi generatoarele de funcții și contoarele de frecvență. De asemenea, este obișnuit să existe afișaje cu 7 segmente care au un punct ce poate fi activat după cifră. 
- 
-{{ :​pm:​lab:​lab2:​7segment_digit.png?​100 |}} 
- 
-Un afișaj LED cu 7 segmente este un aranjament de bare LED (a, b, c, d, e, f, g, dp) care pot fi alimentate individual pentru a afișa cifre (și unele caractere). Configurația poate fi fie anod comun, fie catod comun: 
-   * **Anod comun**: anozii (pozitiv) tuturor LED-urilor sunt conectați electric la un pin și fiecare catod (negativ) al LED-urilor are propriul pin 
-   * **Catod comun**: catozii (negativ) tuturor LED-urilor sunt conectați electric la un pin și fiecare anod (pozitiv) al LED-urilor are propriul pin 
- 
-{{ :​pm:​lab:​lab2:​common_cathode.png?​400 |}} 
- 
-{{ :​pm:​lab:​lab2:​common_anode.png?​400 |}} 
- 
-<note tip> Există și variante cu mai mult de o cifră integrată în componenta de afișare. Afișajele cu mai multe cifre sunt motivul pentru care catozii (sau anozii) sunt conectați, astfel încât cifrele să poată fi multiplexate și să nu folosească o grămadă de pini pentru a controla afișajul.</​note>​ 
- 
-Următorul tabel de căutare poate fi util pentru programarea unui driver de afișare cu 7 segmente: 
- 
-^ Simbol ^ hex ^ a ^ b ^ c ^ d ^ e ^ f ^ g ^| 
-| 0 | 0x7e | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 
-| 1 | 0x30 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 
-| 2 | 0x6d | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 
-| 3 | 0x79 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 
-| 4 | 0x33 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 
-| 5 | 0x5b | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 
-| 6 | 0x5f | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 
-| 7 | 0x70 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 
-| 8 | 0x7f | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
-| 9 | 0x7b | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 
- 
- 
- 
-===== 4. Exerciții ===== 
-Alegerea parametrilor pentru timer pentru setările registrelor:​ 
-<file c> 
-  OCR1A = 31249; //counter 
-  TCCR1B |= (1 << WGM12); ​  // CTC mode 
-  TCCR1B |= (1 << CS12); ​   // 256 prescaler ​ 
-  TIMSK1 |= (1 << OCIE1A); ​ // enable timer compare interrupt 
 </​file>​ </​file>​
- 
-Dacă frecvența de bază a procesorului este de 16 MHz și prescalerul 256 atunci timerul are frecvența de 62500 Hz deci se va incrementa cu 1 la fiecare 1/62500 Hz = 16 μs. O întrerupere va fi generată când valoarea din timer va fi egală cu cea din registrul OCR1A (31249). 16μs×31250 = 0.5s 
- 
-{{:​pm:​lab:​lab2_2022:​ex1.png?​800|}} 
- 
-**Task 1** (1p) Rulați exemplul din {{:​pm:​lab:​lab2_2022:​task1.zip|scheletul de laborator}}. Ce mod de funcționare folosește timer-ul? Dar prescaler-ul?​ 
- 
-**Task 2** (2p) Dorim să vizualizăm efectele prescaler-ului asupra frecvenței cu care se incrementează numărul din display-ul cu 7 segmente. Vom folosi butonul legat la PD3 pentru a cicla prin valorile posibile ale prescaler-ului. 
  
 <​hidden>​ <​hidden>​
-Schema task 1&2:  +**Soluția** se găsește pe [[https://​www.tinkercad.com/​things/​knmCTWcDM6Q|Tinkercad Button Led Blink Interrupts]]
-https://​www.tinkercad.com/​things/​ltXoLQCYr7X-ex2-schelet-lab-timer/​editel?​sharecode=wsn61JV_WbbCX-QdCVPOoFJwAm2nZ8nGxsxb_hdkpLY +
-*nu modificati schema +
- +
-[[https://​github.com/​cs-pub-ro/​laborator-pm/​tree/​master/​laborator/​lab2/​task1_sol ​Solutie task 1&2]]+
 </​hidden>​ </​hidden>​
  
-**Task 3** (3p) Realizați un cronometru de tip “countdown timer”. La finalul numărătorii,​ LED-ul va trebui să rămână aprins iar la apăsarea butonului se va reseta cronometrul la valoarea maximă. Valoarea maximă a cronometrului va fi de 10 secunde și se va afișa pe display valoarea corespunzătoare (9..0). 
- 
-Bonus (1p): Aprindeți LED-ul pentru 200 ms la fiecare secundă cât timp cronometrul numără descrescător. 
-{{:​pm:​lab:​lab2_2022:​ex4.png?​1000|}} 
- 
-**Task 4** (4p) Conectați un buzzer la pinul PD2. Folosind notele muzicale definite în repo-ul ​ [[https://​github.com/​robsoncouto/​arduino-songs|arduino-songs]] sau biblioteca Melody, implementați un cântec la alegere. Atunci când butonul va fi apăsat, notele vor fi ridicate cu o octavă (vor reveni la normal atunci când butonul nu mai este apăsat). 
  
-Bonus (1p) Pe măsură ce cronometrul se apropie de zero, viteza de redare va fi încetinită liniar astfel încât atunci când cronometrul ajunge la 0 viteza va fi 0.1 din valoarea normală. 
  
 ===== 5. Resurse ===== ===== 5. Resurse =====
Line 341: Line 319:
   * Arduino UNO pinout   * Arduino UNO pinout
 {{:​pm:​lab:​uno.jpg?​600|pinout Arduino UNO}} {{:​pm:​lab:​uno.jpg?​600|pinout Arduino UNO}}
-  * Responsabili: ​[[St3fandascalu@gmail.com ​ | Stefan Dascalu]], ​[[alexandru.predescu@upb.ro | Alexandru Predescu]]+  * Responsabili:​ [[alexandru.predescu@upb.ro | Alexandru Predescu]]
  
-<​solution>​ 
-Arhiva cu soluțiile o puteți descărca de aici: {{:​pm:​lab:​lab2_2022:​lab2-solved.zip}} 
-</​solution>​ 
  
 ===== 5. Linkuri utile ===== ===== 5. Linkuri utile =====
pm/lab/lab2-2022.1651404405.txt.gz · Last modified: 2022/05/01 14:26 by florin.stancu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0