This shows you the differences between two versions of the page.
pm:prj2021:avaduva:functiongenerator [2021/05/30 00:41] andrei.biu [Testare & Demo] |
pm:prj2021:avaduva:functiongenerator [2021/06/18 19:33] (current) andrei.biu [Download & Resurse aditionale] |
||
---|---|---|---|
Line 3: | Line 3: | ||
===== Introducere ===== | ===== Introducere ===== | ||
- | Scopul acestui proiect este explorarea capacitatii placii de dezvoltare Arduino UNO de a functiona ca un generator de functii - un astfel de aparat este foarte util in dezvolatrea circuitelor electronice. Astfel produsul rezultat va trebuii sa fie capabil sa produca functii de semnal (de exemplu sinusoide) si PWM. | + | Scopul acestui proiect este explorarea capacitatii placii de dezvoltare Arduino UNO de a functiona ca un generator de functii - un astfel de aparat este foarte util in dezvoltarea circuitelor electronice. Astfel, produsul rezultat va trebui sa fie capabil sa produca functii de semnal (de exemplu sinusoide) si PWM. |
<note important> | <note important> | ||
Fata de alte placi Arduino, UNO nu are un DAC. | Fata de alte placi Arduino, UNO nu are un DAC. | ||
- | Astfel este necesar sa se foloseasca alternative (de exemplu un DAC extern). | + | Astfel este necesar sa se foloseasca alternative (de exemplu, un DAC extern). |
</note> | </note> | ||
- | Proiectul este gandit astfel incat sa poate fi transformat intr-un shield Arduino care sa fie relativ accesibil din punct de vedere financiar (astfel sa se foloseasca cat mai putie componente externe si cat mai ieftine) si usor de realizat (chiar si acasa in principiu) avand capacitati si performante satisfacatoare pentru un hobbyist (nu pentru uz intens) si o interfata usor de folosit (dar in aceasi spirit de a folosi putine componente). | + | Proiectul este gandit astfel incat sa poate fi transformat intr-un shield Arduino care sa fie relativ accesibil din punct de vedere financiar (astfel sa se utilizeze cat mai putie componente externe si cat mai ieftine) si usor de realizat (chiar si acasa, in principiu) avand capacitati si performante satisfacatoare pentru un hobbyist (nu pentru uz intens) si o interfata usor de folosit (dar in acelasi spirit de a folosi putine componente). |
===== Descriere ===== | ===== Descriere ===== | ||
- | Proiectul este un generator de functii capabil sa genereze sinusoide, semnale trapezoidale, triunghiulare si dinte de fierastrau ("sawtooth") cu frecventa de 1Hz pana la 4.5kHz ajustabila cu pasi de 1Hz, amplitudie intre 1 si 5V cu pasi de 100mV, respectiv PWM cu unul sau doua canale cu frecventa comuna intre 1Hz si 100kHz ajustabila cu pasi tot de 1Hz si un factor de umplere setabil per canal de la 0% la 99% in pasi de 1%, cu o amplitudine data de tensiunea de alimentare. Astfel exista 3 iesiri, una de functie de semnal, si doua pentru cele doua canale de PWM. Aparatul poate functiona fie in modul waveform, fie in modul PWM (nu poate genera ambele in acelasi timp). | + | Proiectul este un generator de functii capabil sa genereze sinusoide, semnale trapezoidale, triunghiulare si dinte de fierastrau ("sawtooth") cu frecventa de 1Hz pana la 4.5kHz ajustabila cu pasi de 1Hz, amplitudine intre 1 si 5V cu pasi de 100mV, respectiv PWM cu unul sau doua canale cu frecventa comuna intre 1Hz si 100kHz ajustabila cu pasi tot de 1Hz si un factor de umplere setabil per canal de la 0% la 99% in pasi de 1%, cu o amplitudine data de tensiunea de alimentare. Astfel exista 3 iesiri, una de functie de semnal si doua pentru cele doua canale de PWM. Aparatul poate functiona fie in modul waveform, fie in modul PWM (nu poate genera ambele in acelasi timp). |
{{ :pm:prj2021:avaduva:blockdiagram_functiongenerator.png |}} | {{ :pm:prj2021:avaduva:blockdiagram_functiongenerator.png |}} | ||
- | Iesirile, spre deosebire de un generator de functii normal sunt amplificate in putere. Etajul de filtrare pentru functii de semnal poate amlimenta fara perturbatii rezistente de 400Ω la amplitudinea maxima, iar partea de PWM este amplificata de un MOSFET driver deci poate fi direct conectata la sarcini inductive mari (util pentru testarea circuitelor ce contin tranzistori de putere). | + | Iesirile, spre deosebire de un generator de functii normal sunt amplificate in putere. Etajul de filtrare pentru functii de semnal poate alimenta fara perturbatii rezistente de 400Ω la amplitudinea maxima, iar partea de PWM este amplificata de un MOSFET driver, deci poate fi direct conectata la sarcini inductive mari (util pentru testarea circuitelor ce contin tranzistori de putere). |
Toate setarile sunt introduse printr-o interfata alcatuita dintr-un LCD 16x2 si 5 butoane push (ce au functiile de up, down, left, right si select/ok) folosite pentru a naviga pe ecran si a selecta / introduce valori. | Toate setarile sunt introduse printr-o interfata alcatuita dintr-un LCD 16x2 si 5 butoane push (ce au functiile de up, down, left, right si select/ok) folosite pentru a naviga pe ecran si a selecta / introduce valori. | ||
<note important> | <note important> | ||
- | Chiar daca intervalul de frecvente este ajustabil intr-un spectru continuu cu pasi de 1Hz nu toate frecventele sunt disponibile din cauza limitarilor software si hardware. Daca este introdusa o valoare care nu este disponibila, se va aplica si afisa cea mai apropiata valoare disponibia automat. | + | Chiar daca intervalul de frecvente este ajustabil intr-un spectru continuu cu pasi de 1Hz, nu toate frecventele sunt disponibile din cauza limitarilor software si hardware. Daca este introdusa o valoare care este indisponibila, se va aplica si afisa cea mai apropiata valoare disponibia automat. |
</note> | </note> | ||
Line 27: | Line 27: | ||
Lista de componente folosite: | Lista de componente folosite: | ||
* Arduino UNO R3 | * Arduino UNO R3 | ||
- | * Resiztor 2.2kΩ x24 (THT, ±1%, 0.25W) | + | * Rezistor 2.2kΩ x24 (THT, ±1%, 0.25W) |
- | * Resiztor 1kΩ x2 (THT, ±1%, 0.25W) | + | * Rezistor 1kΩ x2 (THT, ±1%, 0.25W) |
- | * Resiztor 400Ω (THT, ±1%, 0.25W) (doar pentru testare) | + | * Rezistor 400Ω (THT, ±1%, 0.25W) (doar pentru testare) |
* Condensator electrolitic 1μF (50V, THT) | * Condensator electrolitic 1μF (50V, THT) | ||
- | * Condenator ceramic 571pF x2 (THT) | + | * Condensator ceramic 571pF x2 (THT) |
* Push button x5 (THT) | * Push button x5 (THT) | ||
* MCP602 OpAmp (THT, DIP) [[https://ww1.microchip.com/downloads/en/DeviceDoc/21314g.pdf|Datasheet]] | * MCP602 OpAmp (THT, DIP) [[https://ww1.microchip.com/downloads/en/DeviceDoc/21314g.pdf|Datasheet]] | ||
Line 42: | Line 42: | ||
{{:pm:prj2021:avaduva:schematicschematic_2_functiongenerator.png.png?800|}} | {{:pm:prj2021:avaduva:schematicschematic_2_functiongenerator.png.png?800|}} | ||
- | Solutia gasita pentru a suplini lipsa unui DAC intern a fost utilizarea unei solutii software pe Arduino + realizarea unui DAC R2R. Alternativa aceasta a fost aleasa in primul rand pentru ca aceasta este tema proiectului - explorarea capacitatiilor placii Arduino dar si pentru costul foarte redus. DAC-ul are o rezolutie de 8 biti si este conectat la pinii 0-7 aferenti portului PD al μC-ului Atmega328P (si atfel se realizeaza transformarea in tensiune a valorii scrise pe port in registrul aferet din software). Pentru partea de PWM lucrurile sunt mai simple deoarece exista suport hardware din partea μC-ului. | + | Solutia gasita pentru a suplini lipsa unui DAC intern a fost utilizarea unei solutii software pe Arduino + realizarea unui DAC R2R. Aceasta alternativa a fost aleasa in primul rand pentru ca este cea mai potrivita raportata la tema proiectului - explorarea capacitatilor placii Arduino - dar si pentru costul foarte redus. DAC-ul are o rezolutie de 8 biti si este conectat la pinii 0-7 aferenti portului PD al μC-ului Atmega328P (si atfel se realizeaza transformarea in tensiune a valorii scrise pe port in registrul aferent din software). Pentru partea de PWM lucrurile sunt mai simple deoarece exista suport hardware in μC. |
- | In final, pentru partea de funtie de semnal s-a folosit un filtru activ Sallen-Key cu factor de amplificare unitar pentru imbunatatirea calitatii formei de unda rezultate la iesirea DAC-ului, iar pentru PWM IC-ul specificat. Alegerea unui LCD I2C este data de utilizarea extensiva a pinilor placii Arduino UNO in cadrul acestui proiect. | + | In final, pentru partea de functie de semnal s-a folosit un filtru activ Sallen-Key cu factor de amplificare unitar pentru imbunatatirea calitatii formei de unda rezultate la iesirea DAC-ului, iar pentru PWM IC-ul specificat. Alegerea unui LCD I2C este data de utilizarea extensiva a pinilor placii Arduino UNO in cadrul acestui proiect. |
<note important> | <note important> | ||
Line 52: | Line 52: | ||
===== Software Design ====== | ===== Software Design ====== | ||
- | Realizarea partii de software urmareste cele doua parti principale (vizibile atat in schema bloc cat si in schema electrica): partea de generare de semnale si partea de interfata cu utilizatorul. | + | Realizarea laturii software urmareste cele doua parti principale (vizibile si in schema bloc si in cea electrica): partea de generare de semnale si partea de interfata cu utilizatorul. |
==== Signal ==== | ==== Signal ==== | ||
Line 58: | Line 58: | ||
Clasa Signal expune urmatoarea structura: | Clasa Signal expune urmatoarea structura: | ||
- | * ''void waveformSetup()'' Initializeaza registrii si date interne pentru a putea genera functii de semnal. Aceasta functie trebuie mereu apelata inainte de orice alta operatie legata de partea de waveform. Orice alte configuratii prealabile de orice fel sunt sterse. | + | * ''void waveformSetup()'' Initializeaza registrii si date interne pentru a putea genera functii de semnal. Aceasta functie trebuie mereu apelata inainte de orice alta operatie legata de partea de waveform. Orice alte configuratii prealabile, indiferent de tip, sunt sterse. |
- | * ''byte waveformLoad(const byte* wave, byte amplitude = WAVEFORM_MAX_AMPL)'' Incarca in memoria interna datele functiei de semnal data cu aplitudinea specificata ca valori intregi intre 10 si 50 reprezentand sute de mV. Pentru schimbarea amplitudinii trebuie facuta o reincarcare totala a datelor functiei de semnal. In plus pentru ca programul sa functioneze corect trebuie ca datele sa fie declarate cu API - ul oferit ce va fi detaliat ulterior. Valoarea de retur este amplitudinea aplicata pe semnal (care poate diferi de valoarea ceruta daca aceasta este invalida). | + | * ''byte waveformLoad(const byte* wave, byte amplitude = WAVEFORM_MAX_AMPL)'' Incarca in memoria interna datele functiei de semnal furnizata cu amplitudinea specificata ca valori intregi intre 10 si 50 reprezentand sute de mV. Pentru schimbarea amplitudinii trebuie facuta o reincarcare totala a datelor functiei de semnal. In plus pentru ca programul sa functioneze corect trebuie ca datele sa fie declarate cu API - ul oferit ce va fi detaliat ulterior. Valoarea de retur este amplitudinea aplicata pe semnal (care poate diferi de valoarea ceruta daca aceasta este invalida). |
* ''int waveformSetFrequency(int frequency)'' Seteaza frecventa functiei de semnal la cea mai apropiata valoare posibila de cea data (valoarea aplicata fiind returnata) in intervalul 1 - 4500Hz. | * ''int waveformSetFrequency(int frequency)'' Seteaza frecventa functiei de semnal la cea mai apropiata valoare posibila de cea data (valoarea aplicata fiind returnata) in intervalul 1 - 4500Hz. | ||
* ''void waveformEnable()'' / ''void waveformDisable()'' / ''void waveformToggleState()'' Functii care activeaza sau dezactiveaza temporar generarea de semnal pastrand toate configuratiile intacte. | * ''void waveformEnable()'' / ''void waveformDisable()'' / ''void waveformToggleState()'' Functii care activeaza sau dezactiveaza temporar generarea de semnal pastrand toate configuratiile intacte. | ||
- | * ''void pwmSetup(bool dualChannel = false)'' Initializeaza registrii si date interne pentru a putea genera PWM. Aceasta functie trebuie mereu apelata inainte de orice alta operatie legata de partea de PWM. Orice alte configuratii prealabile sde orice fel unt sterse. Se sepcifica daca se doreste generarea pe unul sau ambele canale de PWM, iar schimbarea acestei setari necesita un nou apel la aceasta functie. | + | * ''void pwmSetup(bool dualChannel = false)'' Initializeaza registrii si date interne pentru a putea genera PWM. Aceasta functie trebuie mereu apelata inainte de orice alta operatie legata de partea de PWM. Orice alte configuratii prealabile, indiferent de tip, sunt sterse. Se specifica daca se doreste generarea pe unul sau ambele canale de PWM, iar schimbarea acestei setari necesita un nou apel la aceasta functie. |
* ''long pwmWrite(long frequency, byte dutyCycleChannelA = 50, byte dutyCycleChannelB = 0)'' generaza semnalul(le) de PWM cu frecventa (intre 1Hz si 100kHz) si factorul de umplere dat per canal (intre 0 si 99 in procente). Frecventa aplicata este returnata si reprezinta cea mai apropiata valoare posibila de cea data. | * ''long pwmWrite(long frequency, byte dutyCycleChannelA = 50, byte dutyCycleChannelB = 0)'' generaza semnalul(le) de PWM cu frecventa (intre 1Hz si 100kHz) si factorul de umplere dat per canal (intre 0 si 99 in procente). Frecventa aplicata este returnata si reprezinta cea mai apropiata valoare posibila de cea data. | ||
- | Generarea funtiei de semnal se face prin iterarea in tabloul de valori al functiei de semnal prin pargurgerea ciruluara element cu element - trecerea de la o iteratie la alta se face printr-o intrerupere la interbale precise cu ajutorul Timer/Counter1 - si scrierea valorii pe portul D. | + | Generarea functiei de semnal se face prin iterarea in tabloul de valori al functiei de semnal prin parcurgerea circulara element cu element - trecerea de la o iteratie la alta se face printr-o intrerupere la intervale precise cu ajutorul Timer/Counter1 - si scrierea valorii pe portul D. |
Generarea PWM se face cu acelasi timer configurat in modul Fast PWM. | Generarea PWM se face cu acelasi timer configurat in modul Fast PWM. | ||
- | Datele unei functii de semal sunt reprezentate de un tablou unidimenional de 64 de octeti avand valori de la 0 la 255 corespunzator amplitudinii instantanee din acel moment intre 0 si 5V. Tabloul este stocat in memoria de program pentru a nu lua din memoria SRAM limitata. | + | Datele unei functii de semnal sunt reprezentate de un tablou unidimenional de 64 de octeti avand valori de la 0 la 255 corespunzator amplitudinii instantanee din acel moment intre 0 si 5V. Tabloul este stocat in memoria de program pentru a nu lua din memoria SRAM limitata. |
Pentru a declara o functie de semnal (waveform) se foloseste API - ul folosit, de exemplu pentru declararea unei functii "CastleWave": | Pentru a declara o functie de semnal (waveform) se foloseste API - ul folosit, de exemplu pentru declararea unei functii "CastleWave": | ||
<code cpp> | <code cpp> | ||
Line 75: | Line 75: | ||
==== LCDInterface ==== | ==== LCDInterface ==== | ||
- | Cea de-a doua biblioteca cu care vine partea de software este cea care se ocupa de interfata cu utilizatorul. Bilioteca LCDInterface are rolul de a creea o interfata virtuala (logica) peste un API de comunicare cu un LCD I2C si 5 butoane de selectie / navigare (up, down, left, right, ok/select). | + | Cea de-a doua biblioteca cu care vine partea de software este cea care se ocupa de interfata cu utilizatorul. Bilioteca LCDInterface are rolul de a crea o interfata virtuala (logica) peste un API de comunicare cu un LCD I2C si 5 butoane de selectie / navigare (up, down, left, right, ok/select). |
- | Biblioteca introduce 3 clase / structuri / enitati care reaizeaza interfata logica: | + | Biblioteca introduce 3 clase / structuri / entitati care realizeaza interfata logica: |
- | * ''Page'' un alias catre un tablou bidimenional de dimeniuni fixe continand caracterele / simbolurile care alcatuiesc o pagina - o suprafata logica de dimensiunea display-ului in care sunt afisate informatii. Continutul paginii va fi continutul fix afisat pe display casuta cu casuta. | + | * ''Page'' un alias catre un tablou bidimensional de dimensiuni fixe continand caracterele / simbolurile care alcatuiesc o pagina - o suprafata logica de dimensiunea display-ului in care sunt afisate informatii. Continutul paginii va fi continutul fix afisat pe display casuta cu casuta. |
* ''Cell'' o celula este o unitate de informatie / continut modificabila de catre utilizator. Aceasta are un tip, o pozitie, o valoare minima si maxima si este asociata unei pagini printr-un index de pagina. Implementarea este sub forma de clasa care contine un numar de metode publice insa acestea nu sunt facute pentru a fi folosite din exterior. Importante sunt cele trei tipuri / moduri de functionare ale unei celule: | * ''Cell'' o celula este o unitate de informatie / continut modificabila de catre utilizator. Aceasta are un tip, o pozitie, o valoare minima si maxima si este asociata unei pagini printr-un index de pagina. Implementarea este sub forma de clasa care contine un numar de metode publice insa acestea nu sunt facute pentru a fi folosite din exterior. Importante sunt cele trei tipuri / moduri de functionare ale unei celule: | ||
* ''OnOffSwitch'' o celula care prin apasarea select trece de la valoarea minima sau maxima si viceversa | * ''OnOffSwitch'' o celula care prin apasarea select trece de la valoarea minima sau maxima si viceversa | ||
- | * ''MultiSwitch'' o celula care trece prin apasarea select ciclic valoare cu valoare de la valoarea minima la cea maxima | + | * ''MultiSwitch'' o celula care prin apasarea select trece ciclic valoare cu valoare de la valoarea minima la cea maxima |
- | * ''DataBox'' o celula care prin apasarea select intra in modul de introducere de valoare al care interval este dat de cele doua valori ale celulei, iar prin apasarea up / down se face trecerea pas cu pas intre ele; pentru salvarea valorii se apasa din nou ok | + | * ''DataBox'' o celula care prin apasarea select intra in modul de introducere de valoare al carei interval este dat de cele doua valori proprii celulei, iar prin apasarea up / down se face trecerea pas cu pas intre ele; pentru salvarea valorii se apasa din nou ok |
- | * ''LCDInterface'' clasa principala care alcatuieste interfata virtuala si este facuta pentru a fi folosita extern. Clasa este un accepta valorile fixe ale paginilor corespunzatoare dimeniunii LCD - ului, adresa sa I2C, tablourile de pagini si celule definiti in prealabil impreuna cu dimeniunea lor. Exista o serie de limitari de dimensiuni: pot fi maxim 32 de pagini si 127 de celule. Prin aceasta clasa se vine cu logica de navigare intre pagini si in pagini cu ajutorul unui cursor ce apare in josul casutei curente si cu logica de interactiune cu celulele. Merodele oferite de aceasta clasa sunt: | + | * ''LCDInterface'' clasa principala care alcatuieste interfata virtuala si este facuta pentru a fi folosita extern. Clasa este un sablon care accepta valorile fixe ale paginilor corespunzatoare dimeniunii LCD - ului, (ca parametrii de sablon), adresa sa I2C, tablourile de pagini si celule definite in prealabil impreuna cu dimensiunea lor. Exista o serie de limitari de dimensiuni: pot fi maxim 32 de pagini si 127 de celule. Prin aceasta clasa se vine cu logica de navigare intre pagini si in pagini cu ajutorul unui cursor ce apare in josul casutei curente si cu logica de interactiune cu celulele. Metodele oferite de aceasta clasa sunt: |
- | * ''void initialize()'' Initializeaza instanta curenta. Aceaasta metoda trebuie chemata intotdeauna apelata inainte de folosirea instantei pentru prima oara. | + | * ''void initialize()'' Initializeaza instanta curenta. Aceaasta metoda trebuie apelata intotdeauna inainte de folosirea instantei pentru prima oara. |
* ''void nextPage()'' Incarca urmatoarea pagina pe ecranul LCD. | * ''void nextPage()'' Incarca urmatoarea pagina pe ecranul LCD. | ||
* ''void pressLeft()'' Apasa butonul virtual / logic de left. | * ''void pressLeft()'' Apasa butonul virtual / logic de left. | ||
Line 89: | Line 89: | ||
* ''void pressUp()'' Apasa butonul virtual / logic de up. | * ''void pressUp()'' Apasa butonul virtual / logic de up. | ||
* ''void pressDown()'' Apasa butonul virtual / logic de down. | * ''void pressDown()'' Apasa butonul virtual / logic de down. | ||
- | * ''void pressSelect(Handler<const Cell&> handler = nullptr)'' Apasa butonul virtual / logic de select. Primeste un handler (functie care nu returneza nimic) ce contine logica furnizata de utilizatorul clasei ce trebuie sa se execute la apasare dupa ce se executa logica interna legata de celula curenta. Un exemplu de logica aditionala este aprinderea unui led, trimiterea de date sab suprascrierea de casute fixe pe ecran. | + | * ''void pressSelect(Handler<const Cell&> handler = nullptr)'' Apasa butonul virtual / logic de select. Primeste un handler (functie care nu returneza nimic) ce contine logica furnizata de utilizatorul clasei ce trebuie sa se execute la apasare dupa ce se executa logica interna legata de celula curenta. Un exemplu de logica aditionala este aprinderea unui led, trimiterea de date sau suprascrierea de casute fixe pe ecran. |
- | * ''void registerCustomChar(char value, const byte* points)'' Realizeaza redirectarea catre functia corespunzatoare din biblioteca utilizata in spate pentru LCD-ul I2C. Se da un tablou de 8 octeti in care doar primii cinci biti sunt folositi pentru a crea o matrice ce descrie simbolul definit. Simbolul va surascrie valoarea ASCII a caracterului furnizat. | + | * ''void registerCustomChar(char value, const byte* points)'' Realizeaza redirectarea catre functia corespunzatoare din biblioteca utilizata in spate pentru LCD-ul I2C. Se da un tablou de 8 octeti in care doar primii cinci biti sunt folositi pentru a crea o matrice ce descrie simbolul definit. Simbolul va suprascrie valoarea ASCII a caracterului furnizat. |
* ''String read(Position position, byte length)'' Citeste incepand cu pozitia data valorile din numarul de casutele / celulele furnizat intr-un String. Daca lungimea ceruta depaseste randul curent se va returna un string mai scurt. | * ''String read(Position position, byte length)'' Citeste incepand cu pozitia data valorile din numarul de casutele / celulele furnizat intr-un String. Daca lungimea ceruta depaseste randul curent se va returna un string mai scurt. | ||
* ''String readReverse(Position position, byte length)'' La fel ca 'read', doar ca ordinea de citire e inversata. Util pentru citirea de numere. | * ''String readReverse(Position position, byte length)'' La fel ca 'read', doar ca ordinea de citire e inversata. Util pentru citirea de numere. | ||
- | * ''void write(Position position, String str, bool cellOverride = false)'' Scrie string-ul furnizat pe interfata virtuala si pe ecranul fizic incepand pe pozitia data pana la termiarea striungului sau a randului. Prin ultimul paramentru se controleaza corelarea datelor intre cele oferite si cele prezente in celule. Pentru valoarea 'false' se pun datele din celule pe ecran si de ignora cele date, altfel se sprascriu datele din celule cu cele date. | + | * ''void write(Position position, String str, bool cellOverride = false)'' Scrie string-ul furnizat pe interfata virtuala si pe ecranul fizic incepand cu pozitia data pana la termiarea stringului sau a randului. Prin ultimul paramentru se controleaza corelarea datelor intre cele oferite si cele prezente in celule. Pentru valoarea 'false' se pun datele din celule pe ecran si se ignora cele date, altfel se sprascriu datele din celule cu cele furnizate. |
- | Prin "apasarea" butoanelor virtuale se muta cursorul care indica casuta curenta de pe ecran. Acest lucru nu este insa valabil cand este selecata o celula de tip 'DataBox' pentru introducre de date. Atunci apelurile catre functiile de butoane nu mai muta cursorul in schimb functioneaza doar cele de 'up' si 'down' care realizeaza ciclarea prin valorile pe celula. | + | Prin "apasarea" butoanelor virtuale se muta cursorul care indica casuta curenta de pe ecran. Acest lucru nu este insa valabil cand este selectata o celula de tip 'DataBox' pentru introducere de date. Atunci apelurile catre functiile de butoane nu mai muta cursorul; in schimb functioneaza doar cele de 'up' si 'down' care realizeaza ciclarea prin valorile celulei. |
Toate pozitiile din biblioteca sunt specificate prin structura: | Toate pozitiile din biblioteca sunt specificate prin structura: | ||
Line 102: | Line 102: | ||
</code> | </code> | ||
- | In afara de functii built-in din mediul Arduino am folosit biblioteca LiquidCrystal_I2C [[https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library|Link Github]] | + | In afara de functii built-in din mediul Arduino am folosit biblioteca LiquidCrystal_I2C: [[https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library|Link Github]] |
==== FunctionGenerator ==== | ==== FunctionGenerator ==== | ||
- | Acesta este fisierul .ino in care este cod specific proiectului, construit pe baza celor doua biblioteci anterior descrise. Aici este pastrata starea aparatului, este gestionata apasarea butoanelor (prin functia ''loop'' specifica Arduino si intreruperi de tip pin change - PCINT; mai precis, in ISR - uri se detecteaza si se salveaza ce buton a fost apasat iar apoi in ''loop'' se face pooling pentru a apela metoda corespunzatoare de ''press'' din ''LCDInterface''; in final toata logica suplimentara la selectia diferitelor elemente de pe ecran este tratata prin handlerul dat ca paramentru metodei ''LCDInterface::pressSelect'') si sunt realizate initializarile necesare (functia ''setup'' specifica Arduino). | + | Acesta este fisierul .ino in care este cod specific proiectului, construit pe baza celor doua biblioteci anterior descrise. Aici este pastrata starea aparatului, este gestionata apasarea butoanelor (prin functia ''loop'' specifica Arduino si intreruperi de tip pin change - PCINT; mai precis, in ISR - uri se detecteaza si se salveaza ce buton a fost apasat, iar apoi in ''loop'' se face pooling pentru a apela metoda corespunzatoare de ''press'' din ''LCDInterface''; in final toata logica suplimentara la selectia diferitelor elemente de pe ecran este tratata prin handlerul dat ca paramentru metodei ''LCDInterface::pressSelect'') si sunt realizate initializarile necesare (functia ''setup'' specifica Arduino). |
===== Utilizare ===== | ===== Utilizare ===== | ||
- | Utlizatorul aparatului trebuie doar sa seteze modul dorit si parametrii specifici fiecarui mod de functionare (waveform, PWM). Acest lucru se face prin navigarea si selectia pe ecran cu ajutorul celor 5 butoane. Intotdeauna exista o casuta curenta pe ecran (similar cu un element de interfata cu utilizatorul dintr-un GUI - de exemplu un buton - atunci cand se face navigarea cu tab) care este evidentiata printr-un cursor de tip underscore ("_") ce este miscat prin cele 4 taste de directie. | + | Utilizatorul aparatului trebuie doar sa seteze modul dorit si parametrii specifici fiecarui mod de functionare (waveform, PWM). Acest lucru se face prin navigarea si selectia pe ecran cu ajutorul celor 5 butoane. Intotdeauna exista o casuta curenta pe ecran (similar cu un element de interfata cu utilizatorul dintr-un GUI - de exemplu un buton - atunci cand se face navigarea cu tab) care este evidentiata printr-un cursor de tip underscore ("_") ce este miscat prin cele 4 taste de directie. |
<note tip> | <note tip> | ||
- | Dupa pornirea aparatului cursorul nu este afisat. | + | Dupa pornirea aparatului, cursorul nu este afisat. |
- | Este necesar sa se apase o tasta de directie pentru a fi mutat cursorul pentru prima data si a fi afisat. Acesta este situat le pornire mereu in casuta din coltul stanga-sus al ecranului. | + | Este necesar sa se apese o tasta de directie pentru a fi mutat cursorul pentru prima data si a fi afisat. Acesta este situat le pornire mereu in casuta din coltul stanga-sus al ecranului. |
</note> | </note> | ||
Introducerea parametrilor / setarilor se face in casutele corespunzatoare astfel: | Introducerea parametrilor / setarilor se face in casutele corespunzatoare astfel: | ||
- | * Pentru cele de tip switch (''OnOffSwitch'' sau ''MultiSwitch'') se apasa tasta select pentru trececerea ciclica intre valori atunci cand cursoarul este pe casuta aferenta acelei setari. Schimbarea efectiva a parametrului setat se face imediat fara alte comenzi suplimentare. Daca setarea are valori ale caror nume necesita mai multe casute pentru afisare, casuta care este activa - care are comportamentul descris anterior - este mereu (si doar) prima | + | * Pentru cele de tip switch (''OnOffSwitch'' sau ''MultiSwitch'') se apasa tasta select pentru trecerea ciclica intre valori atunci cand cursorul este pe casuta aferenta acelei setari. Schimbarea efectiva a parametrului setat se face imediat fara alte comenzi suplimentare. Daca setarea are valori ale caror nume necesita mai multe casute pentru afisare, casuta care este activa - care are comportamentul descris anterior de switch - este intotdeauna doar prima casuta din totalul celor necesare. |
- | * Pentru cele in care se pot introduce date - in cazul aparatului valori numerice (de tip ''DataBox'') trebuie mai intai selectate prin apasarea select; atunci se blocheaza cursorul pentru a mai fi mutat si acesta este inlocuit cu unul de tip blinking box si se poate cicla prin valorie disponibile prin abasarea butoanlor up si down; pentru salvarea valorii introduse si intoarcerea la cursorul normal care permite navigarea pe ecran trebuie apasat din nou select. | + | * Pentru cele in care se pot introduce date - in cazul aparatului valori numerice (de tip ''DataBox'') - acestea trebuie mai intai selectate prin apasarea select; atunci se blocheaza cursorul (nu mai poate fi mutat) si acesta este inlocuit cu unul de tip blinking box si se poate cicla prin valorile disponibile prin apasarea butoanlor up si down; pentru salvarea valorii introduse si intoarcerea la cursorul normal care permite navigarea pe ecran trebuie apasat din nou select. |
<note tip> | <note tip> | ||
- | Casutele alaturate care permit introducerea de cifre fromeaza impreuna un numar. Chiar daca se poate schimba doar valoarea unei cifre la un moment dat, valoarea citita de aparat este formata din toate cifrele. | + | Casutele alaturate care permit introducerea de cifre formeaza impreuna un numar. Chiar daca se poate schimba doar valoarea unei cifre la un moment dat, valoarea citita de aparat este formata din toate cifrele. |
- | Daca este introdusa o valoare invalida sau indisponibila, se considera si afisa cea mai apropiata valoare valida. | + | Daca este introdusa o valoare invalida sau indisponibila, se considera si afiseaza cea mai apropiata valoare valida. |
</note> | </note> | ||
Line 129: | Line 129: | ||
{{ :pm:prj2021:avaduva:functiongenerator_lcdinterfacediagarm.png |}} | {{ :pm:prj2021:avaduva:functiongenerator_lcdinterfacediagarm.png |}} | ||
- | In imagine e prezentata structura ecranului cand modul este Waveform, outputul este dezactivat (O arata ca prin apasare se activeaza semnalul, X arata dezactivarea), iar tipul de semnal este Sawtooth (SAW - Sawtooth wave, SIN - Sine wave, TRI - triangle wave, TPZ - trapezoidal wave). | + | In imagine e prezentata structura ecranului cand modul este Waveform, outputul este dezactivat (O arata ca prin apasare se activeaza semnalul, X semnifica dezactivarea), iar tipul de semnal este Sawtooth (SAW - Sawtooth wave, SIN - Sine wave, TRI - triangle wave, TPZ - trapezoidal wave). |
{{ :pm:prj2021:avaduva:functiongenerator_lcdinterfacediagarm2.png |}} | {{ :pm:prj2021:avaduva:functiongenerator_lcdinterfacediagarm2.png |}} | ||
- | In imagine e prezentata structura ecranului cand modul este PWM, outputul este activat (O arata ca prin apasare se activeaza semnalul, X arata dezactivarea), si este activ un singur canal (SCH - Single channel mode, DCH - dual channel mode). | + | In imagine e prezentata structura ecranului cand modul este PWM, outputul este activat (O arata ca prin apasare se activeaza semnalul, X semnifica dezactivarea) si este activ un singur canal (SCH - Single channel mode, DCH - dual channel mode). |
===== Testare & Demo ===== | ===== Testare & Demo ===== | ||
- | Pentru testarea proiectului am realizat un prototip pe breadboard utilizand exact componentele specificate in sectiunea de design hardware. Pe langa asta am utilzat urmatoarele instrumente pentru testare: | + | Pentru testarea proiectului am realizat un prototip pe breadboard utilizand exact componentele specificate in sectiunea de design hardware. In plus am utilzat urmatoarele instrumente pentru testare: |
* Sursa de alimentare reglabila | * Sursa de alimentare reglabila | ||
* Multimetru | * Multimetru | ||
Line 145: | Line 145: | ||
{{:pm:prj2021:avaduva:functiongenerator_capture_3.jpeg?300|}} | {{:pm:prj2021:avaduva:functiongenerator_capture_3.jpeg?300|}} | ||
- | Exemple de modaliati de functionare ale dispozitivului: | + | Exemple de moduri de functionare ale dispozitivului: |
* Triangular Wave, 3.5V, 100Hz | * Triangular Wave, 3.5V, 100Hz | ||
{{:pm:prj2021:avaduva:functiongenerator_capture_9.jpeg?300|}} {{:pm:prj2021:avaduva:functiongenerator_capture_8.jpeg?800|}} | {{:pm:prj2021:avaduva:functiongenerator_capture_9.jpeg?300|}} {{:pm:prj2021:avaduva:functiongenerator_capture_8.jpeg?800|}} | ||
Line 159: | Line 159: | ||
Live demo pentru modul Waveform: [[https://ctipub-my.sharepoint.com/:v:/g/personal/andrei_biu_stud_acs_upb_ro/ETsWX5p0IIVOj58VhsXtT0QB490XeUBBohJbZ1HQzZ6_Yg?e=TK9w8y| Video]] | Live demo pentru modul Waveform: [[https://ctipub-my.sharepoint.com/:v:/g/personal/andrei_biu_stud_acs_upb_ro/ETsWX5p0IIVOj58VhsXtT0QB490XeUBBohJbZ1HQzZ6_Yg?e=TK9w8y| Video]] | ||
===== Concluzii & Future Work ===== | ===== Concluzii & Future Work ===== | ||
- | Proiectul poate primi o serie de imbunatatiri fata de forma descrisa / deja implementata pentru a extinde capacitatiile acestuia: | + | Proiectul poate primi o serie de imbunatatiri fata de forma descrisa / deja implementata pentru a extinde capacitatile acestuia: |
- | - Frecventa maxima obtinuta in modul waveform este limitata in primul rand de software. Overheadul unei intreruperi este mare pentru astfel de aplicatii, mai ales in contextul in care codul dat de compilator nu este prea eficient pentru ISA-uri. In particular este pesimist in ceea ce priveste utilizarea registrilor si simte nevoia sa faca prea multe salvari pe stiva. Schimbarea codului din ISA-ul pentru waveform cu unul in limbaj de asamblare (inline assembly + ISR_NAKED) poate creste frecventa pana la 5kHz (acest lucru inca nu a fost realizat deoarce programul functiona incorect cu toate variantele de cod incercat). Mai departe rezervarea unor registrii globali poate aduce o dublare pana la 10kHz, dar acest lucru presupune abandonarea mediului Arduino si programarea in C fara a folosi nicio bibioteca externa (totul de la zero), inclusiv multe functii din implementarea libc pentru AVR (dintre cele precompilate). | + | - Frecventa maxima obtinuta in modul waveform este limitata in primul rand de software. Overheadul unei intreruperi este mare pentru astfel de aplicatii, mai ales in contextul in care codul dat de compilator nu este prea eficient pentru ISA-uri. In particular este pesimist in ceea ce priveste utilizarea registrilor si simte nevoia sa faca prea multe salvari pe stiva. Schimbarea codului din ISA-ul pentru waveform cu unul in limbaj de asamblare (inline assembly + ISR_NAKED) poate creste frecventa pana la 5kHz (acest lucru inca nu a fost realizat deoarece programul functiona incorect cu toate variantele de cod incercat). Mai departe, rezervarea unor registrii globali poate aduce o dublare pana la 10kHz, dar acest lucru presupune abandonarea mediului Arduino si programarea in C fara a folosi nicio biblioteca externa (totul de la zero), inclusiv multe functii din implementarea libc pentru AVR (dintre cele precompilate). |
- | - Filtrul Salem-Key nu are un efect de filtrare sufiient de bun pentru netezirea frecventelor mici. Ar fi nevoie de un filtru realizat cu trimmer programabil. Exista astfel dd IC-uri, insa tind sa aiba o plaja mica de capacitante. In cazul aparatului ar fi nevoie de ceva in intervalul de cativa μF - sute de pF. Acest lucru poate fi realizat cu un decodor pe 3 biti (ultimii 3 pini liberi ai placii), de exemplu 74HC237 care sa comande MOSFET-uri de joasa putere precum 2N7000 care la randul lor sa cupleze condensatorii necesari. Asta poate permite o reducere a numarului de valori necesare pentru reconstruirea semnalului, deci la crestera frecventei maxime (o limita realista este in jurul a 20kHz). | + | - Filtrul Sallen-Key nu are un efect de filtrare suficient de bun pentru netezirea frecventelor mici. Ar fi nevoie de un filtru realizat cu trimmer programabil. Exista astfel de IC-uri, insa tind sa aiba o plaja mica de capacitante. In cazul aparatului ar fi nevoie de ceva in intervalul de cativa μF - sute de pF. Acest lucru poate fi realizat cu un decodor pe 3 biti (ultimii 3 pini liberi ai placii), de exemplu 74HC237 care sa comande MOSFET-uri de joasa putere precum 2N7000 care la randul lor sa cupleze condensatorii necesari. Aceasta poate permite o reducere a numarului de valori necesare pentru reconstruirea semnalului, deci la cresterea frecventei maxime (o limita realista este in jurul a 20kHz). |
- | Cu toate acestea raman suficiente limitari pe partea de generare de waveform care pot fi prea mari pentru un alt uz decat cel ocazional in regim de hobby-ist. Pentru o performanta mult mai buna trebuie inlocuita intreaga parte de generare de functii de unda (hardware + parte din software) cu un DAC cu memorie interna (cu o interfata I2C sau SPI), sau chiar cu un IC dedicat pentru generare de semnale. | + | Cu toate acestea, raman suficiente limitari pe partea de generare de waveform care pot fi prea mari pentru un alt uz decat cel ocazional in regim de hobbyist. Pentru o performanta mult mai buna trebuie inlocuita intreaga parte de generare de functii de unda (hardware + parte din software) cu un DAC cu memorie interna (cu o interfata I2C sau SPI), sau chiar cu un IC dedicat pentru generare de semnale. |
<note> | <note> | ||
- | Dintre acestea, cel mai probabil varianta cu DAC-ul este mai avantajoasa din punct de vedere al costului si inca ofera flexibilitatea de a genera semnale oarecare definite in soft. Totusi aceste alternative ies intr-o anumita masura din scopul initial al proiectului - acela de a testa capacitatiile intrinseci ale placii Arduino UNO de a functiona ca generator de functii de semnal. | + | Dintre acestea, cel mai probabil varianta cu DAC-ul este mai avantajoasa din punct de vedere al costului si continua sa ofere flexibilitatea de a genera semnale oarecare definite in soft. Totusi aceste alternative ies intr-o anumita masura din scopul initial al proiectului - acela de a testa capacitatile intrinseci ale placii Arduino UNO de a functiona ca generator de functii de semnal. |
</note> | </note> | ||
Line 182: | Line 182: | ||
[[https://www.arduino.cc/reference/en]] | [[https://www.arduino.cc/reference/en]] | ||
+ | |||
+ | Prezentarea pentru PM Fair: {{:pm:prj2021:avaduva:functiongenerator.pptx| Function Generator}} | ||