This shows you the differences between two versions of the page.
|
pm:lab:lab3-2023 [2023/03/26 14:27] alexandru.predescu [6. Linkuri utile] |
pm:lab:lab3-2023 [2023/03/27 11:26] (current) narcis_florin.caroi [4. Exerciții] |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| * ~~SHOWSOLUTION~~ | * ~~SHOWSOLUTION~~ | ||
| */ | */ | ||
| - | ~~SHOWSOLUTION~~ | ||
| - | ====== Laboratorul 3: Timere. PWM (work in progress) ====== | + | ====== Laboratorul 3: Timere. PWM ====== |
| Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile hardware generate de timer-ele prezente în microcontroller-ul Atmega328p. Vom folosi timer-ele pentru a număra intervale de timp și pentru a genera semnale periodice. Folosind semnale PWM vom controla intensitatea luminoasă a unui LED și poziția unui servomotor. | Acest laborator are ca scop familiarizarea voastră cu lucrul cu întreruperile hardware generate de timer-ele prezente în microcontroller-ul Atmega328p. Vom folosi timer-ele pentru a număra intervale de timp și pentru a genera semnale periodice. Folosind semnale PWM vom controla intensitatea luminoasă a unui LED și poziția unui servomotor. | ||
| Line 350: | Line 349: | ||
| ===== 4. Exerciții ===== | ===== 4. Exerciții ===== | ||
| + | {{:pm:lab:schema-intreruperi-pwm.jpeg?600|}} | ||
| + | === 4.1. Task 0 === | ||
| - | === 4.1. Timere === | + | Folosind Timer 1 de pe Arduino și operațiile cu regiștri, afișați pe interfața serială un mesaj la alegerea voastră o dată la 5 secunde. |
| <note tip> | <note tip> | ||
| + | |||
| + | Timerul de pe Arduino nu poate cronometra perioade atât de lungi. Veți fi nevoiți să afișați mesajul după un anumit număr de perioade, de lungime aleasă de voi. Ex: perioadă de 0.5s (2Hz), afișăm mesajul la fiecare a doua intrare în funcția asociată întreruperii de timer; perioadă de 0.1s (10Hz), afișăm mesajul la fiecare a 10-a intrare. | ||
| + | |||
| Alegerea parametrilor pentru timer pentru setările registrelor: | Alegerea parametrilor pentru timer pentru setările registrelor: | ||
| Line 363: | Line 367: | ||
| </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 | ||
| </note> | </note> | ||
| - | **Task 1** (1p) Rulați exemplul de mai jos. | + | === 4.2. Task 1 === |
| - | * Ce mod de funcționare folosește timer-ul? Dar prescaler-ul? | + | |
| - | <file c> | + | Folosind codul de la exercițiul anterior, la fiecare 5 secunde veți alterna între două stări de redare a unei melodii pe buzzer-ul din montaj: |
| - | #define BTN 2 | + | * viteză normală și octavă normală |
| - | #define LED 11 | + | * viteză dublă (noteDuration / 2) și octavă superioară |
| - | volatile int ledState = 0; | + | Creșterea unei octave se realizează dublând frecvența notelor. Pentru redarea unei note veți folosi funcția [[https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/|tone()]]. Urmăriți exemplele de pe acest repository [[https://github.com/robsoncouto/arduino-songs|arduino-songs]] și alegeți o melodie. |
| - | void setup() { | + | <note tip> |
| - | pinMode(BTN, INPUT_PULLUP); | + | Realizați redarea melodiei în funcția loop() pentru a putea folosi întreruperile generate de timer și pentru a reda continuu melodia. |
| - | pinMode(LED, OUTPUT); | + | </note> |
| - | digitalWrite(LED, ledState); | + | |
| - | + | ||
| - | // configurare timer | + | |
| - | cli(); | + | |
| - | TCCR1A = 0; | + | |
| - | TCCR1B = 0; | + | |
| - | TCNT1 = 0; | + | |
| - | OCR1A = 31249; | + | |
| - | TCCR1B |= (1 << WGM12); | + | |
| - | TCCR1B |= (1 << CS12); | + | |
| - | TIMSK1 |= (1 << OCIE1A); | + | |
| - | sei(); | + | |
| - | } | + | |
| - | ISR(TIMER1_COMPA_vect) { | + | === 4.3. Task 2 === |
| - | /*digitalWrite(LED, ledState); | + | |
| - | ledState = !ledState;*/ | + | |
| - | PORTB ^= (1 << PB3); | + | |
| - | } | + | |
| - | void loop() | + | Folosind Timer 0, ciclați led-ul RGB între mai multe culori și mișcați servo-motorul câte 10° la fiecare x secunde (alegeți voi o perioadă potrivită pentru urmărirea schimbărilor). Nu uitați de sugestia de la primul task (va trebui să numărați un număr de perioade mult mai scurte decât cea dorită). |
| - | { | + | |
| - | + | ||
| - | } | + | |
| - | </file> | + | |
| - | {{:pm:lab:lab3_2023:task1.png?direct&500|}} | + | <note warning>Atenție la limitele de unghi ale servo-motorului. Depășirea acestora poate avaria servomotorul. Verificați ca unghiul să nu depășească intervalul [0°, 180°] (sau [0, pi] pentru cei ce își amintesc cu plăcere de trigonometrie :-P). |
| + | </note> | ||
| - | **Task 2** (2p) Dorim să vizualizăm efectele prescaler-ului asupra frecvenței cu care se aprinde LED-ul. | + | La acest task veți afișa diverse culori cu ajutorul PWM-ului și veți controla un servo-motor: |
| - | * Vom folosi butonul legat la PD2 pentru a cicla prin valorile posibile ale prescaler-ului. | + | |
| + | * 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 | ||
| + | * Exemplu pentru controlul unui servo-motor ce oscilează în intervalul [0°, 180°] | ||
| - | <solution> | + | <file> |
| - | <hidden> | + | |
| - | <spoiler Rezolvare > | + | |
| - | <file c> | + | |
| - | #define BTN 2 | + | |
| - | #define LED 11 | + | |
| - | + | ||
| - | volatile int ledState = 0; | + | |
| - | int lastBtnState = 0; | + | |
| - | + | ||
| - | void setup() { | + | |
| - | Serial.begin(9600); | + | |
| - | pinMode(BTN, INPUT_PULLUP); | + | |
| - | pinMode(LED, OUTPUT); | + | |
| - | digitalWrite(LED, ledState); | + | |
| - | + | ||
| - | // configurare timer | + | |
| - | cli(); | + | |
| - | TCCR1A = 0; | + | |
| - | TCCR1B = 0; | + | |
| - | TCNT1 = 0; | + | |
| - | OCR1A = 31249; | + | |
| - | TCCR1B |= (1 << WGM12); | + | |
| - | TCCR1B |= (1 << CS12); | + | |
| - | TIMSK1 |= (1 << OCIE1A); | + | |
| - | sei(); | + | |
| - | } | + | |
| - | + | ||
| - | ISR(TIMER1_COMPA_vect) { | + | |
| - | /*digitalWrite(LED, ledState); | + | |
| - | ledState = !ledState;*/ | + | |
| - | PORTB ^= (1 << PB3); | + | |
| - | } | + | |
| - | + | ||
| - | int ps = 1; | + | |
| - | + | ||
| - | void loop() | + | |
| - | { | + | |
| - | if(digitalRead(BTN) == LOW){ | + | |
| - | if(!lastBtnState){ | + | |
| - | lastBtnState = 1; | + | |
| - | delay(200); | + | |
| - | TCCR1B &= ~(1 << CS12 | 1 << CS11 | 1 << CS10); | + | |
| - | TCCR1B |= ps; | + | |
| - | Serial.println(ps); | + | |
| - | ps += 1; | + | |
| - | if (ps > 5){ | + | |
| - | ps = 1; | + | |
| - | } | + | |
| - | } | + | |
| - | } else { | + | |
| - | lastBtnState = 0; | + | |
| - | } | + | |
| - | } | + | |
| - | </file> | + | |
| - | </spoiler> | + | |
| - | </hidden> | + | |
| - | </solution> | + | |
| - | + | ||
| - | + | ||
| - | **Task 3** (3p) Conectați un buzzer la pinul 9 (PB1). 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. | + | |
| - | * Din Arduino IDE: File > Examples > Digital > toneMelody | + | |
| - | * Fiecare notă muzicală are asociată o frecvență (de ex. La - 440 Hz) | + | |
| - | * Atunci când butonul (legat la PD2) va fi apăsat, notele vor fi ridicate cu o octavă (frecvență dublă a notelor), și vor reveni la normal atunci când butonul nu mai este apăsat. Hint: folosiți intreruperi externe. (1p) | + | |
| - | + | ||
| - | + | ||
| - | {{:pm:lab:lab3_2023:task2.png?direct&500|}} | + | |
| - | + | ||
| - | === 4.2. PWM === | + | |
| - | + | ||
| - | ** Task 1 ** (2p) Folosind un semnal PWM, modificați progresiv intensitatea luminoasă a LED-ului conectat la Arduino. | + | |
| - | * LED-ul trebuie să se aprindă complet la intervale de 2 s. | + | |
| - | * Modificați factorul de umplere a semnalului PWM la intervale de 100 ms. | + | |
| - | + | ||
| - | ** Task 2 ** (2p) Rulați exemplul standard din Arduino prezentat mai jos, prin care se modifică în mod “continuu” poziția unui servomotor în intervalul (0-180). Adăugați un indicator al poziției servomotorului, folosind LED-ul conectat la Arduino: | + | |
| - | * Implementați un semnal PWM proporțional cu poziția servomotorului (0 = 0%, 180 = 100%) | + | |
| - | * Vă puteți folosi de funcția ''map()'' din Arduino pentru a translata intervalele: [[https://www.arduino.cc/reference/en/language/functions/math/map/|map()]] | + | |
| - | + | ||
| - | <file c> | + | |
| #include <Servo.h> | #include <Servo.h> | ||
| Line 497: | Line 402: | ||
| void setup() { | void setup() { | ||
| - | myservo.attach(9); // attaches the servo on pin 9 to the servo object | + | myservo.attach(3); // attaches the servo on pin 3 to the servo object |
| // test led | // test led | ||
| DDRD |= (1 << PD7); | DDRD |= (1 << PD7); | ||
| Line 516: | Line 421: | ||
| </file> | </file> | ||
| - | Servomotoarele sunt construite pe baza unui motor DC sau Brushless DC, au angrenaje integrate și un arbore (ax) care poate fi controlat cu precizie. Servo-urile standard permit poziționarea arborelui la diferite unghiuri, de obicei între 0 și 180 de grade. Există și variante cu rotație continuă ce permit modificarea precisă a vitezei de rotație a arborelui. | + | Bonus : modificați programul folosind functia //setLedColorHSV()// |
| - | + | ||
| - | Servomotoarele hobby ([[https://en.wikipedia.org/wiki/Servo_(radio_control)|Servo]]) sunt în mod uzual comandate printr-un semnal PWM cu frecvența de 50 Hz și perioada semnalului T_on în intervalul 1-2 ms, unde 1.5 ms reprezintă poziția de centru. Practic, semnalul PWM este folosit pentru a codifica și transmite poziția dorită către microcontroller-ul integrat care se ocupă de poziționarea efectivă servomotorului. | + | |
| - | + | ||
| - | {{:pm:lab:lab3_task2.png?direct&300|}} | + | |
| - | | + | |
| + | * 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 | ||
| + | * 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 |}} | ||
| ===== 5. Resurse ===== | ===== 5. Resurse ===== | ||
| Line 528: | Line 432: | ||
| * Arduino UNO pinout | * Arduino UNO pinout | ||
| {{:pm:lab:uno.jpg?direct&600|pinout Arduino UNO}} | {{:pm:lab:uno.jpg?direct&600|pinout Arduino UNO}} | ||
| - | * Responsabili: [[alexandru.predescu@upb.ro | Alexandru Predescu]] | + | |
| + | Responsabili: | ||
| + | * [[alexandru.predescu@upb.ro | Alexandru Predescu]] | ||
| + | * [[enedragos99@gmail.com | Dragos Ene]] | ||
| + | * [[narciscaroi24@gmail.com | Narcis Caroi]] | ||
| <solution> | <solution> | ||
| - | <hidden>https://www.tinkercad.com/things/4VwiEuamlWp</hidden> | + | <hidden>{{:pm:lab:lab3pm.rar|}}</hidden> |
| </solution> | </solution> | ||
| - | ===== 6. Resurse utile ===== | + | ===== 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]] | ||