This shows you the differences between two versions of the page.
pm:lab:lab3-2023 [2023/03/26 14:24] alexandru.predescu |
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&500|}} | + | |
- | | + | |
+ | * 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> | ||
Line 537: | Line 445: | ||
* [[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]] | ||
+ | * [[https://www.arduino.cc/en/Tutorial/BuiltInExamples/Debounce|debouncing]] | ||
+ | * [[https://www.arduino.cc/en/pmwiki.php?n=Tutorial/SecretsOfArduinoPWM|SecretsOfArduinoPWM]] | ||
* [[https://en.wikipedia.org/wiki/Servo_control|Servo control]] | * [[https://en.wikipedia.org/wiki/Servo_control|Servo control]] | ||
- | * [[https://www.arduino.cc/en/pmwiki.php?n=Tutorial/SecretsOfArduinoPWM|SecretsOfArduinoPWM]] | ||
- | * [[https://www.arduino.cc/en/Tutorial/BuiltInExamples/Debounce|debouncing]] | ||
- | * [[https://www.arduino.cc/en/Reference/ServoWriteMicroseconds|Servo.writeMicroseconds]] | ||
- |