This shows you the differences between two versions of the page.
pm:lab:lab3-2022 [2022/03/27 15:40] sebastian.gherman99 |
pm:lab:lab3-2022 [2023/03/19 14:41] (current) alexandru.predescu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 3: Întreruperi externe. PWM ====== | + | /** |
+ | * uncomment this to publish the solution: | ||
+ | * ~~SHOWSOLUTION~~ | ||
+ | */ | ||
+ | ~~SHOWSOLUTION~~ | ||
+ | |||
+ | ====== Laboratorul 3: Întreruperi externe. PWM (old) ====== | ||
Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile externe și cu modul de generare a semnalelor PWM folosind timer-ele prezente în microcontroller-ul Atmega328p. Vom folosi întreruperi externe pentru a detecta apăsarea unui buton, independent de programul principal. Folosind semnale PWM vom controla un LED RGB și poziția unui servomotor. | Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile externe și cu modul de generare a semnalelor PWM folosind timer-ele prezente în microcontroller-ul Atmega328p. Vom folosi întreruperi externe pentru a detecta apăsarea unui buton, independent de programul principal. Folosind semnale PWM vom controla un LED RGB și poziția unui servomotor. | ||
Line 271: | Line 277: | ||
} | } | ||
</file> | </file> | ||
- | |||
Line 277: | Line 282: | ||
=== Task 0 (întreruperi / butoane) === | === Task 0 (întreruperi / butoane) === | ||
- | 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 întreruperea externă INT0 (consultați schema PINOUT) pentru a detecta apăsarea unui buton. Modificați starea LED-urilor RGB (ON / OFF )la fiecare apăsare de buton. |
- | **Tinkercad** - Testați programul folosind următorul montaj: | + | * Configurați întreruperea externă (INT) pe front descrescător (falling edge) |
- | + | * 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 | |
- | {{:pm:lab:lab3_2021:button_led_interrupts.png?600|}} | + | * NU este recomandat să folosiți delay în ISR. |
- | + | ||
- | <file> | + | |
- | ISR(INT0_vect) | + | |
- | { | + | |
- | // cod întrerupere externă | + | |
- | PORTD ^= (1 << PD7); | + | |
- | } | + | |
- | </file> | + | |
- | + | ||
- | * 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) | + | |
- | + | ||
- | **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) | * 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) | ||
- | * [expert] Se poate folosi un timer pentru a înlocui apelul funcției //millis()// | ||
- | <hidden> | + | {{:pm:lab:lab3_task0.png?direct&600|}} |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/cVPb9x8NUbX|Tinkercad Button Led Interrupts]] | + | |
- | </hidden> | + | |
- | === Task 1a (LED RGB) === | + | === Task 1 (LED RGB) === |
+ | {{:pm:lab:lab3_task1.png?direct&600|}} | ||
- | Conectați un LED RGB catod comun la pinii 9, 10, 11 de pe Arduino folosind câte o rezistență de 330ohm și rulați programul de mai jos: | + | Observați ceva special în montajul de mai sus modul de conectare al led-ului RGB ? (Hint: diagrama PINOUT, PWM) |
- | * Observați modificarea culorii LED-ului | + | La acest task veți cicla cu ajutorul PWM-ului prin toate culorile led-ului RGB. |
- | * Funcția //analogWrite// setează factorul de umplere PWM pentru fiecare culoare | + | |
- | **Tinkercad** - Testați programul folosind următorul montaj: | + | * Cu funcția [[https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/|analogWrite]] veți seta factorul de umplere PWM pentru fiecare culoare |
- | {{:pm:lab:lab3_2021:auto_rgb.png?600|}} | + | Bonus : modificați programul folosind functia //setLedColorHSV()// |
- | + | ||
- | + | ||
- | <file> | + | |
- | void setup() { | + | |
- | // Start off with the LED off. | + | |
- | setColorRGB(0,0,0); | + | |
- | } | + | |
- | + | ||
- | void loop() { | + | |
- | unsigned int rgb[3]; | + | |
- | + | ||
- | // Start off with red. | + | |
- | rgb[0] = 255; | + | |
- | rgb[1] = 0; | + | |
- | rgb[2] = 0; | + | |
- | + | ||
- | // Choose the colors to increment and decrement. | + | |
- | for (int dec = 0; dec < 3; dec += 1) { | + | |
- | int inc = dec == 2 ? 0 : dec + 1; | + | |
- | + | ||
- | // cross-fade the two colors. | + | |
- | for (int i = 0; i < 255; i += 1) { | + | |
- | rgb[dec] -= 1; | + | |
- | rgb[inc] += 1; | + | |
- | setColorRGB(rgb[0], rgb[1], rgb[2]); | + | |
- | delay(5); | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | void setColorRGB(unsigned int red, unsigned int green, unsigned int blue) { | + | |
- | analogWrite(9, red); | + | |
- | analogWrite(10, green); | + | |
- | analogWrite(11, blue); | + | |
- | } | + | |
- | </file> | + | |
- | + | ||
- | === Task 1b (LED RGB / HSV) === | + | |
- | + | ||
- | Modificați programul folosind functia //setLedColorHSV//: | + | |
* Funcția //setLedColorHSV// permite modificarea culorii folosind reprezentarea alternativă HSV (Hue Saturation Value), fiind mai ușor apoi de modificat culoarea, saturația și intensitatea luminoasă. {{:pm:lab:lab3_2021:hsv.txt|setLedColorHSV}} | * Funcția //setLedColorHSV// permite modificarea culorii folosind reprezentarea alternativă HSV (Hue Saturation Value), fiind mai ușor apoi de modificat culoarea, saturația și intensitatea luminoasă. {{:pm:lab:lab3_2021:hsv.txt|setLedColorHSV}} | ||
* Setați valorile pentru saturație (s) și intensitate (v) pe 1 și modificați culoarea (h) în intervalul 0-360 | * Setați valorile pentru saturație (s) și intensitate (v) pe 1 și modificați culoarea (h) în intervalul 0-360 | ||
+ | * Pentru a urmări corespondența dintre cele 2 reprezentări (RGB și HSV) există selectoare de culori precum [[https://colorpicker.me/#3237b9|Online Color Picker]] | ||
+ | {{ :pm:lab:hue-wheel.png?direct&400 |}} | ||
- | Pentru a urmări corespondența dintre cele 2 reprezentări (RGB și HSV) există selectoare de culori precum: | + | === Task 2 (Servo / sweep) === |
- | [[https://colorpicker.me/#3237b9|Online Color Picker]] | + | {{:pm:lab:lab3_task2.png?direct&600|}} |
- | + | ||
- | <hidden> | + | |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/2MYGBAcxapa|Tinkercad Auto RGB]] | + | |
- | </hidden> | + | |
- | + | ||
- | + | ||
- | === Task 2 (LED RGB / Serial) === | + | |
- | + | ||
- | Scrieți un program care primește comenzi pe serială (USART) și setează o anumită culoare a LED-ului RGB, în funcție de valorile primite pentru fiecare canal, separate prin virgulă (R,G,B). Formatul de tip [[https://en.wikipedia.org/wiki/Comma-separated_values|CSV]] reprezintă o variantă simplă și flexibilă (deși mai puțin eficientă decât transmiterea în format binar, sub formă de octeți) de codificare a datelor trimise pe serială. | + | |
- | + | ||
- | * Formatul comenzii este următorul: R(0-255),G(0-255),B(0-255). ex. 0,0,255 va comanda o culoare albastră | + | |
- | * Pentru a identifica sfârșitul comenzii se poate folosi //newline// (\n) (în Tinkercad nu avem această posibilitate, dar se poate folosi un alt caracter de control, de ex. o literă) | + | |
- | * La primirea comenzii, se vor schimba valorile factorului de umplere pentru semnalul PWM ce comandă fiecare culoare (R,G,B) | + | |
- | * Folosiți funcția //parseCSV// pentru a extrage într-un vector valorile separate prin virgulă din mesajul comenzii | + | |
- | + | ||
- | <file> | + | |
- | int parseCSV(char* inputString, int *outputArray, int outputArraySize) { | + | |
- | char *pch; | + | |
- | int val = 0; | + | |
- | int index_serial_data = 0; | + | |
- | pch = strtok(inputString, ","); | + | |
- | + | ||
- | while (pch != NULL && pch != "\n") { | + | |
- | sscanf (pch, "%d", &val); | + | |
- | outputArray[index_serial_data] = val; | + | |
- | index_serial_data++; | + | |
- | if (index_serial_data == outputArraySize) { | + | |
- | break; | + | |
- | } | + | |
- | pch = strtok(NULL, ","); | + | |
- | } | + | |
- | return index_serial_data; | + | |
- | } | + | |
- | </file> | + | |
- | + | ||
- | <hidden> | + | |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/7TIP4DS6OJz|Tinkercad Serial RGB]] | + | |
- | </hidden> | + | |
- | === Task 3 (Servo / sweep) === | + | Rulați exemplul standard din Arduino de mai jos, prin care se modifică în mod “continuu” poziția (0-180). |
- | Conectați un servo la pinul 9 și rulați exemplul standard din Arduino, prin care se modifică în mod "continuu" poziția (0-180) | + | Modificați programul astfel încât servomotorul să se oprească atunci când ajunge în oricare din capete. Cu ajutorul interfeței seriale, se va modifica sensul de rotație. |
- | {{:pm:lab:lab3_2021:auto_servo.png?600|}} | + | <note warning>Atenție la limitele de unghi. Depășirea acestora poate avaria servomotorul</note> |
- | * Urmăriți pe osciloscop semnalul PWM generat | ||
* Se pot controla până la 12 servomotoare folosind un singur timer | * Se pot controla până la 12 servomotoare folosind un singur timer | ||
- | * Calculați factorul de umplere pentru intervalul de comandă al servomotorului (1ms-2ms). Se poate genera un astfel de semnal cu precizie bună folosind un timer în modul Fast PWM, ca mai devreme? | + | * Calculați factorul de umplere pentru intervalul de comandă al servomotorului (1ms-2ms). Se poate genera un astfel de semnal cu precizie bună folosind un timer în modul Fast PWM ? |
| | ||
<file> | <file> | ||
Line 437: | Line 347: | ||
</file> | </file> | ||
- | <hidden> | + | === Task 3 (Servo / buton) === |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/kLxC5nzUW7L|Tinkercad Auto Servo]] | + | {{:pm:lab:lab3_task3.png?direct&600|}} |
- | </hidden> | + | |
- | === Task 4 (Servo / buton) === | + | Folosind o întrerupere de tip PCINT (Pin Change INTerrupt), modificați incremental poziția servomotorului (0-180 și 180-0) cu ajutorul butonului. |
- | + | ||
- | Folosind întreruperile de la **Task 0**, modificați incremental poziția servomotorului (0-180) | + | |
| | ||
- | {{:pm:lab:lab3_2021:button_servo.png?600|}} | + | <note warning>Atenție la limitele de unghi. Depășirea acestora poate avaria servomotorul</note> |
- | * Atenție la limite (min, max). Depășirea acestora poate avaria servomotorul. | + | * Folosiți debouncing pentru a obține o funcționare corectă (o apăsare va incrementa o singură dată poziția) |
- | * Dacă lucrați pe placă, folosiți debouncing pentru a obține o funcționare corectă (o apăsare va incrementa o singură dată poziția) | + | |
* Există și servomotoare care folosesc un alt interval de comenzi (ex. 0.7ms-2.3ms), se poate folosi funcția //writeMicroseconds// pentru a controla direct durata pulsului. [[https://www.arduino.cc/en/Reference/ServoWriteMicroseconds|Servo.writeMicroseconds]] | * Există și servomotoare care folosesc un alt interval de comenzi (ex. 0.7ms-2.3ms), se poate folosi funcția //writeMicroseconds// pentru a controla direct durata pulsului. [[https://www.arduino.cc/en/Reference/ServoWriteMicroseconds|Servo.writeMicroseconds]] | ||
- | <hidden> | + | ===== 5. Resurse ===== |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/23y5RXDFFVl|Tinkercad Button Servo]] | + | |
- | </hidden> | + | |
- | + | ||
- | + | ||
- | ===== 4. Resurse ===== | + | |
* {{:pm:atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|Datasheet Atmega 328p}} | * {{:pm:atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|Datasheet Atmega 328p}} | ||
Line 462: | Line 363: | ||
{{:pm:lab:uno.jpg?direct&200|pinout Arduino UNO}} | {{:pm:lab:uno.jpg?direct&200|pinout Arduino UNO}} | ||
* Responsabili: [[dragos_mihai.ene@stud.acs.upb.ro | Dragoș Ene ]] | [[sebastian.gherman99@stud.acs.upb.ro | Sebastian Gherman ]] | * Responsabili: [[dragos_mihai.ene@stud.acs.upb.ro | Dragoș Ene ]] | [[sebastian.gherman99@stud.acs.upb.ro | Sebastian Gherman ]] | ||
- | ===== 5. Linkuri utile ===== | + | |
+ | <solution> | ||
+ | <hidden>Arhiva cu soluțiile o puteți descărca de aici: {{:pm:lab:lab3_2021:lab3-solved.zip}}</hidden> | ||
+ | </solution> | ||
+ | |||
+ | ===== 6. Linkuri utile ===== | ||
* [[http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html|AVR Libc - interrupt.h]] | * [[http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html|AVR Libc - interrupt.h]] | ||
Line 470: | Line 376: | ||
* [[https://en.wikipedia.org/wiki/Comma-separated_values|CSV]] | * [[https://en.wikipedia.org/wiki/Comma-separated_values|CSV]] | ||
* [[https://www.arduino.cc/en/Reference/ServoWriteMicroseconds|Servo.writeMicroseconds]] | * [[https://www.arduino.cc/en/Reference/ServoWriteMicroseconds|Servo.writeMicroseconds]] | ||
+ |