Differences

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

Link to this comparison view

pm:lab:lab2-2022 [2023/03/18 21:43]
alexandru.predescu [4. Exerciții]
pm:lab:lab2-2022 [2024/03/17 09:54] (current)
florin.stancu
Line 5: Line 5:
 ~~SHOWSOLUTION~~ ~~SHOWSOLUTION~~
  
-====== Laboratorul 2: Întreruperi. Întreruperi externe ======+====== Laboratorul 2: Întreruperi ​hardware. Întreruperi externe ======
  
-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 apăsarea unui buton, independent de programul principal.+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 buton, independent 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 73: Line 73:
 === Configurăm perifericul care va trimite întreruperile === === Configurăm perifericul care va trimite întreruperile ===
  
-În 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''​. ​+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>
Line 84: Line 84:
   ​   ​
 <note tip> <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:doc8272.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**.+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>​ </​note>​
           ​           ​
 === Scriem rutina de tratare a întreruperii === === Scriem rutina de tratare a întreruperii ===
  
-De exemplu, pentru întreruperile de tip ''​INT0'' ​și respectiv ''​PCINT2'',​ codul va arăta în felul următor:+De exemplu, pentru întreruperile de tip ''​INT0''​respectiv ''​PCINT2'',​ codul va arăta în felul următor:
  
 <file c> <file c>
Line 110: Line 110:
  
 <note important>​ <note important>​
-Dacă avem mai multe întreruperi pe același vector ​și 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.+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>​ </​note>​
  
Line 130: Line 130:
  
  
-==== 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 146: 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>​
  
  
Line 153: Line 153:
   * întreruperile componentelor //​interne//:​ timere, interfețe seriale (USART), convertor analog-digital   * întreruperile componentelor //​interne//:​ timere, interfețe seriale (USART), convertor analog-digital
   * întreruperile componentelor //​externe//:​ activate de pinii externi ai uC-ului   * întreruperile componentelor //​externe//:​ activate de pinii externi ai uC-ului
-În [[pm:​lab:​lab2-2022|Laboratorul 2]] ați studiat mecanismul de întreruperi de pe Atmega328p și ați configurat întreruperi în contextul timer-elor. 
  
-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.+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.
  
 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ă întrerupere. Semnalele 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. 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ă întrerupere. Semnalele 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.
Line 193: Line 192:
 </​file>​ </​file>​
  
 +
 +<​hidden>​
 +AAB: add more info about debouncing, some photos from oscilloscope maybe...
 +mention some simple debouncing methods, like using delays
 +</​hidden>​
  
 ===== 4. Exerciții ===== ===== 4. Exerciții =====
  
-=== Task 1 (întreruperi / butoane) === +=== 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. 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.
 +
 +  * Configurați întreruperea externă (INT) pe front descrescător (falling edge) sau PCINT-ul corespunzător pinului folosit
 +  * Modificați starea LED-ului la apăsarea oricărui buton (PD2, PD4)
  
 **Tinkercad** - Testați programul folosind următorul montaj: **Tinkercad** - Testați programul folosind următorul montaj:
Line 203: Line 210:
 {{:​pm:​lab:​lab3_2021:​button_led_interrupts.png?​600|}} {{:​pm:​lab:​lab3_2021:​button_led_interrupts.png?​600|}}
  
-<​file>​+ 
 +**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: 
 +  * NU este recomandat să folosiți delay în ISR 
 +  * 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) 
 + 
 + 
 +<​file ​c>
 ISR(INT0_vect) ISR(INT0_vect)
 { {
   // cod întrerupere externă   // cod întrerupere externă
-  PORTD ^= (1 << PD7);  +  PORTD ^= (1 << PD7);
 } }
-</​file>​ 
  
-  * Configurați întreruperea externă ​(INTpe front descrescător (falling edge) sau PCINT-ul corespunzător pinului folosit +ISR(PCINT2_vect{ 
-  ​* Modificați starea LED-ului la apăsarea oricărui buton (PD2, PD4) +  ​// cod întrerupere de tip pin change 
-  ​* Modificați starea LED-ului de pe placă (pin 13) la interval de o secundă.+  ​// TODO 
 +}
  
-**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: +void setup_interrupts() { 
-  ​* NU este recomandat să folosiți delay în ISR +  ​// buton 1: PD2 INT0 
-  ​* 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)+  ​// buton 2PD4 / PCINT20 
 +  ​cli(); 
 + 
 +  // input 
 +  DDRD &= ~(1 << PD2& ~(1 << PD4); 
 +  ​// input pullup 
 +  PORTD |= (1 << PD2) | (1 << PD4); 
 + 
 +  // configurare intreruperi 
 +  // intreruperi externe 
 +  // TODO 
 + 
 +  // întreruperi ​de tip pin change ​(activare vector de întreruperi) 
 +  ​// TODO 
 + 
 +  // activare intreruperi 
 +  // intrerupere externa 
 +  // TODO 
 + 
 +  // întrerupere de tip pin change 
 +  // TODO 
 + 
 +  sei()
 +
 + 
 +void setup() { 
 +  setup_interrupts();​ 
 +  DDRD |= (1 << PD7); 
 +  PORTD &= ~(1 << PD7); 
 +
 + 
 +void loop() {   
 +   
 +
 +</​file>​
  
 <​hidden>​ <​hidden>​
 **Soluția** se găsește pe [[https://​www.tinkercad.com/​things/​cVPb9x8NUbX|Tinkercad Button Led Interrupts]] **Soluția** se găsește pe [[https://​www.tinkercad.com/​things/​cVPb9x8NUbX|Tinkercad Button Led Interrupts]]
 +</​hidden>​
 +
 +=== Task 2 (blink control) - 4p === 
 +Pe baza aceluiași montaj, 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 intervalul de semnalizare (blink) al unui LED conectat la ''​PD7''​ (pin 7) în ISR astfel:
 +
 +  * butonul conectat la ''​PD2''​ crește intervalul cu 100 ms
 +  * butonul conectat la ''​PD4''​ scade intervalul cu 100 ms
 +
 +<file c>
 +
 +volatile int dt = 500;
 +
 +ISR(INT0_vect)
 +{
 +  // cod întrerupere externă
 +  // TODO
 +}
 +
 +ISR(PCINT2_vect) {
 +  // cod întrerupere de tip pin change
 +  // TODO
 +}
 +
 +// setup_interrupts() la fel ca la Task 1
 +
 +void setup() {
 +  setup_interrupts();​
 +  DDRD |= (1 << PD7);
 +  PORTD &= ~(1 << PD7);
 +}
 +
 +void loop() {  ​
 +  PORTD |= (1 << PD7);
 +  delay(dt);
 +  PORTD &= ~(1 << PD7);
 +  delay(dt);
 +}
 +
 +</​file>​
 +
 +<​hidden>​
 +**Soluția** se găsește pe [[https://​www.tinkercad.com/​things/​knmCTWcDM6Q|Tinkercad Button Led Blink Interrupts]]
 </​hidden>​ </​hidden>​
  
Line 232: Line 321:
   * Responsabili:​ [[alexandru.predescu@upb.ro | Alexandru Predescu]]   * Responsabili:​ [[alexandru.predescu@upb.ro | Alexandru Predescu]]
  
-<​solution>​ 
-<​hidden>​Arhiva cu soluțiile o puteți descărca de aici: {{:​pm:​lab:​lab2_2022:​lab2-solved.zip}}</​hidden>​ 
-</​solution>​ 
  
 ===== 5. Linkuri utile ===== ===== 5. Linkuri utile =====
pm/lab/lab2-2022.1679168630.txt.gz · Last modified: 2023/03/18 21:43 by alexandru.predescu
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