This shows you the differences between two versions of the page.
pm:lab:lab4-2023-2024 [2024/03/31 04:25] mihnea.dinica |
pm:lab:lab4-2023-2024 [2025/04/02 11:11] (current) florin.stancu |
||
---|---|---|---|
Line 86: | Line 86: | ||
**F_ADC = F_CPU / PRESCALER** | **F_ADC = F_CPU / PRESCALER** | ||
- | Alegerea prescaler-ului depinde de frecventa de esentionare si de acuratetea dorita. Cu cat prescaler-ul este mai mare frecventa ADC va fi mai mica si acuratetea va fi mai mare. Mai multe informatii se pot gasi in capitolul 23.5 din [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet ATmega324P]]. | + | Alegerea prescaler-ului depinde de frecventa de esentionare si de acuratetea dorita. Cu cat prescaler-ul este mai mare frecventa ADC va fi mai mica si acuratetea va fi mai mare. Mai multe informatii se pot gasi in capitolul 25.4 din [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet ATmega324P]]. |
==== Moduri de functionare ==== | ==== Moduri de functionare ==== | ||
Line 103: | Line 103: | ||
=== ADMUX - ADC Multiplexer Selection Register === | === ADMUX - ADC Multiplexer Selection Register === | ||
{{ :pm:lab:adc_6.png?500 |}} | {{ :pm:lab:adc_6.png?500 |}} | ||
- | * **Bit 7:6 - REFS1:0 Reference Selection Bits → Selecteaza tensiunea de referinta | + | * **Bit 7:6 - REFS1:0 Reference Selection Bits** → Selecteaza tensiunea de referinta |
{{ :pm:lab:adc_7.png?500 |}} | {{ :pm:lab:adc_7.png?500 |}} | ||
- | * **Bit 5 - ADLAR ADC Left Adjust Result → Modul de aliniere a celor 10 biti. (left-aligned sau right-aligned) | + | * **Bit 5 - ADLAR ADC Left Adjust Result** → Modul de aliniere a celor 10 biti. (left-aligned sau right-aligned) |
- | * **BIT 4:0 - MUX 4:0 Analog Channel Gain Selection Bits → Selecteaza portul de intrare de pe care se face conversia | + | * **Bit 4:0 - MUX 4:0 Analog Channel Gain Selection Bits** → Selecteaza portul de intrare de pe care se face conversia |
{{ :pm:lab:adc_8.png?500 |}} | {{ :pm:lab:adc_8.png?500 |}} | ||
Line 117: | Line 117: | ||
* **Bit 3 – ADIE: ADC Interrupt Enable** -> Porneste intreruperile pentru ADC | * **Bit 3 – ADIE: ADC Interrupt Enable** -> Porneste intreruperile pentru ADC | ||
* **Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits** -> Setare prescaler | * **Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits** -> Setare prescaler | ||
+ | {{ :pm:lab:adc_10.png?500 |}} | ||
=== ADCSRB – ADC Control and Status Register B === | === ADCSRB – ADC Control and Status Register B === | ||
{{ pm:lab:ADCSRB.png?600 | ADCSRB }} | {{ pm:lab:ADCSRB.png?600 | ADCSRB }} | ||
* **Bit 2:0 – ADTS2:0: ADC Auto Trigger Source** -> Sursa de la care sa se genereze o noua conversie. Depinde de ADATE din ADCSRA | * **Bit 2:0 – ADTS2:0: ADC Auto Trigger Source** -> Sursa de la care sa se genereze o noua conversie. Depinde de ADATE din ADCSRA | ||
+ | {{ :pm:lab:adc_13.png?500 |}} | ||
=== Exemplu === | === Exemplu === | ||
- | Setup: | + | Initializare ADC pentru a citi de pe pinul PA1. |
<code> | <code> | ||
ADMUX = 0; | ADMUX = 0; | ||
Line 137: | Line 138: | ||
/* enable ADC */ | /* enable ADC */ | ||
ADCSRA |= (1 << ADEN); | ADCSRA |= (1 << ADEN); | ||
- | |||
</code> | </code> | ||
- | Read: | + | Citire valoare convertita. |
<code> | <code> | ||
/* start conversion */ | /* start conversion */ | ||
ADCSRA |= (1 << ADSC); | ADCSRA |= (1 << ADSC); | ||
/* wait until conversion is complete */ | /* wait until conversion is complete */ | ||
- | while (!(ADCSRA & (1 << ADIF))); | + | while ((ADCSRA & (1 << ADSC))); |
- | uint16_t result = ADC; | + | uint32_t result = ADC; |
</code> | </code> | ||
- | |||
- | ===== 3. ADC in Arduino ===== | ||
- | Biblioteca arduino ne pune la dispozitie o functie simpla pentru a folosi ADC-ul si anume **analogRead()**. | ||
- | |||
- | <code> | ||
- | void loop() { | ||
- | val = analogRead(A0); // read the input pin | ||
- | Serial.println(val); // debug value | ||
- | delay(100); | ||
- | } | ||
- | </code> | ||
- | |||
- | Aceasta functie primeste ca parametru un pin si va bloca pana citirea valorii de pe acel pin se termina. Pentru aplicatii simple acest lucru este suficient, dar pentru aplicatii mai complexe in care ne dorim sa continuam procesarea in timp ce facem conversia va trebui sa folosim cod specific pentru microcontrollerul nostru. | ||
- | |||
- | Tensiunea de referinta folosita se poate seta cu functia analogReference() | ||
===== 4. Exercitii ===== | ===== 4. Exercitii ===== | ||
- | **Task 0** Folositi cod Arduino pentru a citi valoarea unui potentiometru si a unui senzor de temperatura si apoi trimiteti valorile pe seriala. | + | Obiectivul exercitiilor este sa controlam convertorul analog-digital integrat in microprocesorul Atmega324p pentru diferite citiri (butoane multiplexate prin divizoare de tensiune, senzor de temperatura). |
- | - Transmiteți către consolă, folosind seriala disponibilă, tensiunea (calculată pe microcontroller) de la ieșirea potențiometrului și valoarea returnată de ADC (0-1023). | + | |
- | - Valoarea citită pentru senzorul de temperatură trebuie sa fie exprimată in grade Celsius. Tensiunea de iesire a senzorului variaza liniar cu temperatura. Puteti sa faceti conversia experimental sau folosindu-vă de datasheet ([[https://www.analog.com/media/en/technical-documentation/data-sheets/TMP35_36_37.pdf|Datasheet TMP36]] / [[https://www.ti.com/lit/ds/symlink/lm35.pdf|Datasheet LM35]]). | + | |
- | {{ pm:lab:PB1.png?500 | PB1 }} | + | Scheletul de cod este {{:pm:lab:lab4_skel.zip|aici}}. |
- | <solution> | + | **Task 0** (2 puncte) Completați scheletul de cod (fișierul “adc.c”) astfel încât sa definiți o funcție cu un comportament similar analogRead(uint8_t pin) → aceasta face o singura conversie a semnalului de pe pinul specificat și este blocanta pana la returnarea rezultatului. |
- | <hidden> | + | |
- | + | ||
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/b2Yra0sAu2J-brilliant-lappi-habbi/editel?sharecode=LfeWdU6ojyT1VzyOCdjwU3ieYR6u4bV2-lEko5iVrTc|Tinkercad TMP36]] | + | |
- | </hidden> | + | |
- | </solution> | + | |
- | + | ||
- | **Task 1** Folosind cod specific AVR, cititi valoarea potentiometrului doar atunci cand se apasa un buton. | + | |
- | + | ||
- | {{ pm:lab:PB2.png?500 | PB2 }} | + | |
- | + | ||
- | <solution> | + | |
- | <hidden> | + | |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/b2Yra0sAu2J-brilliant-lappi-habbi/editel?sharecode=LfeWdU6ojyT1VzyOCdjwU3ieYR6u4bV2-lEko5iVrTc|Tinkercad Interrupt]] | + | |
- | + | ||
- | <code> | + | |
- | void timer_setup(){ | + | |
- | // set timer A for 10ms | + | |
- | TCCR0A = 0; | + | |
- | TCCR0B = 0; | + | |
- | TCNT0 = 0; | + | |
- | + | ||
- | OCR0A = 156; // compare match -> 10ms | + | |
- | TCCR0A |= (1 << WGM01); // CTC mode | + | |
- | TCCR0B |= ((1 << CS02) | (1 << CS00)); // 1024 prescaler | + | |
- | TIMSK0 |= (1 << OCIE0A); | + | |
- | + | ||
- | // Enable timer as source | + | |
- | ADCSRB |= ((1 << ADTS0) | (1 << ADTS1)); | + | |
- | } | + | |
- | + | ||
- | void button_setup(){ | + | |
- | // Select INT0 as trigger source | + | |
- | ADCSRB = 0; | + | |
- | ADCSRB |= (1 << ADTS1); | + | |
- | + | ||
- | // Enable INT0 | + | |
- | EICRA |= (1 << ISC00); | + | |
- | EIMSK |= (1 << INT0); | + | |
- | } | + | |
- | + | ||
- | void setup() | + | |
- | { | + | |
- | + | ||
- | // disable interrupts | + | |
- | cli(); | + | |
- | + | ||
- | ADMUX = 0; | + | |
- | /* AVCC with external capacitor at AREF pin */ | + | |
- | ADMUX |= (1 << REFS0); | + | |
- | + | ||
- | ADCSRA = 0; | + | |
- | /* set prescaler at 128 */ | + | |
- | ADCSRA |= (7 << ADPS0); | + | |
- | + | ||
- | // Enable auto-trigger | + | |
- | ADCSRA |= (1 << ADATE); | + | |
- | // Enable Intrerupt | + | |
- | ADCSRA |= (1 << ADIE); | + | |
- | + | ||
- | // Set button as trigger source | + | |
- | button_setup(); | + | |
- | + | ||
- | // Select Timer as trigger source | + | |
- | //timer_setup(); | + | |
- | + | ||
- | /* enable ADC */ | + | |
- | ADCSRA |= (1 << ADEN); | + | |
- | + | ||
- | // Enable interrupts | + | |
- | sei(); | + | |
- | Serial.begin(9600); | + | |
- | } | + | |
- | + | ||
- | ISR(ADC_vect){ | + | |
- | Serial.println(ADC); | + | |
- | } | + | |
- | + | ||
- | ISR(INT0_vect) | + | |
- | { | + | |
- | Serial.println("Button Pressed!"); | + | |
- | } | + | |
- | + | ||
- | ISR(TIMER0_COMPA_vect){ | + | |
- | // Even if this does nothing. It has to be here to reset the timer interrupt flag | + | |
- | } | + | |
- | + | ||
- | void loop() | + | |
- | { | + | |
- | delay(50); | + | |
- | } | + | |
- | </code> | + | |
- | </hidden> | + | **Task 1** (1 punct) Folosind funcția anterior definită, citiți valorile de pe senzorul de temperatura (PA0). Puteti pune degetul peste el (pe proprie răspundere) și observa cum se modifica valorile. Senzorul de temperatura `MCP9701T-E/TT` are un interval de functionare de -10°C - 125°C. |
- | </solution> | + | |
- | **Task 2** Folosind cod specific AVR, cititi valoarea potentiometrului o data la 10ms. Pentru acest exercitiu trebuie sa folositi ADC-ul sa porneasca o conversie automat in functie de un timer. | + | <note warning> |
+ | AVR Libc are implicit o implementare simplistică a printf()-ului care nu știe să formateze valori floating point. Dacă doriți să meargă ''%f'' & friends, va trebui să activați o setare de bibliotecă prin linker-ul GCC, desigur, prin ''platformio.ini'': <code>build_flags = -Wl,-u,vfprintf -lprintf_flt -lm</code> | ||
+ | </note> | ||
- | <solution> | + | **Task 2** (3 puncte) Butoanele 1-6 sunt multiplexate pe același pin analogic (PA5) prin intermediul unui sistem de divizoare de tensiune (urmăriți schematicul pentru o explicație vizuala). Aflați ce valoare întoarce fiecare buton la apăsare și completați “define-urile” din cod. Completați codul astfel încât la apăsarea BTN1 sa se aprindă doar LED-ul magenta, la apăsarea BTN4 - LED-ul galben, iar la apăsarea BTN6 - LED-ul cyan. |
- | <hidden> | + | |
- | **Soluția** se găsește pe [[https://www.tinkercad.com/things/grYhoajb3sd-exquisite-hango-waasa/editel?sharecode=gNPGmOuI6oZBx3bp-q-S7NlxWoz_wRwWZm9LJK4DHbI|Tinkercad Potentiometer]] | + | |
- | Codul este similar. Vezi Task 1. | + | > Hint: culorile cerute se pot obtine prin combinarea a cate 2 leduri dintre rosu, verde si albastru |
- | </hidden> | + | **Task 3** (4 puncte) Configurați ADC-ul astfel încât conversia valorilor citite de pe senzorul de temperatura sa se întâmple in mod continuu. Configurati LED-ul RBG astfel incat sa afiseze o culoare intre albastru si rosu. (Albastru va corespunde unei temperaturi de 20°C, iar rosu unei temperaturi de 30°C). Folositi FastPWM de 8 biti pentru culorile ledurilor. NU MODIFICATI CODUL DIN FUNCTIA `task3`! |
- | </solution> | + | |
- | ===== 5. Resurse ===== | + | > Hint: folositi functia `remap_interval` pentru a calcula duty-cycle pentru cele 2 timere |
- | * {{:pm:atmel-7810-automotive-microcontrollers-atmega328p_datasheet.pdf|Datasheet Atmega 328p}} | + | **Task 4 (BONUS)** (1 punct) Configurati ADC-ul astfel incat sa aiba o rezolutie de 8 biti si observati diferenta de timp la rulare. |
- | * Arduino UNO pinout | + | ===== 5. Linkuri utile ===== |
- | {{:pm:lab:uno.jpg?200|pinout Arduino UNO}} | + | |
- | * Responsabili: [[florin.stancu@upb.ro | Florin Stancu ]] | + | |
- | <solution> | + | * [1] [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet ATmega324P]] |
- | <hidden>Arhiva cu soluțiile o puteți descărca de aici: {{:pm:lab:lab4:lab4-solved.zip}}</hidden> | + | * [2] [[https://github.com/dantudose/PM-Board|Documentatie placuta laborator]] |
- | </solution> | + | * [3] [[https://www.instructables.com/Accessing-5-buttons-through-1-Arduino-pin-Revisi|Butoane multiplexate pe un pin]] |
- | ===== 6. Linkuri Utile ===== | + | ===== 6. Responsabili laborator ===== |
- | * [[https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/|Arduino Analog Read]] | + | |
- | * [[https://www.analog.com/media/en/technical-documentation/data-sheets/TMP35_36_37.pdf|Datasheet TMP36 ]] | + | |
- | * [[https://www.ti.com/lit/ds/symlink/lm35.pdf|Datasheet LM35]] | + | |
- | * [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf|Datasheet ATmega328p]] | + | |
- | * [[https://www.tinkercad.com/things/cl7vDLkEZwF?sharecode=Ve7hoj8NLhZ_JSmV2jcoruc8lzp35D1E-pg1nTFhrgE|Tinkercad TMP36]] | + | |
+ | * Eduard Radu | ||
+ | * Alexandru Jipa |