Ceas Electronic cu Display Oled Si Microcontroler Atmel
Cuprins
Introducere
Capitolul 1 Introducere teoretică asupra tehnologiilor utilizate
1.1 Tehnologia ecranelor OLED
1.2 Circuite integrate cu funcția de Real Time Clock
1.3 Unitatea de comandă și control
1.4 Oscilatoare cu cuarț
1.5 Bateriile litiu-polimer
1.6 Limbajul de programare
1.7 Sistemele de comunicație
1.7.1 Sistemul SPI
1.7.2 Sistemul I2C
1.7.3 Sistemul TTL
1.7.4 Sistemul OneWireBUS
Capitolul 2 Proiectarea prototipului
2.1 Scopul realizării proiectului
2.2 Listă de materiale utilizate în realizarea prototipului
2.3 Diagrama bloc a componentelor electronice
2.4 Schema electrică a circuitului
2.5 Prezentarea componentelor electronice utilizate în realizarea prototipului
2.5.1 Placa de dezvoltare cu Microcontroler
2.5.2 Ecranul PMOLED
2.5.3 Modulul de Real Time Clock
2.5.4 Bateria litiu-polimer
2.5.5 TrackBall-ul – dispozitiv periferic de control al dispozitivului
2.5.6 Senzorul de temperatură
2.5.7 Senzorul de proximitate
2.5.8 Modulul de încărcare
2.5.9 Programatorul cu interfață serială FTDI
Capitolul 3 Realizarea și testarea prototipului
3.1 Carcasa prototipului
3.2 Programarea finală a dispozitivului
3.3 Poziționarea componentelor în carcasă
3.4 Testarea funcționalității dispozitivului
3.4.1 Verificarea responsivității TrackBall-ului
3.4.2 Testarea preciziei de măsurare a senzorului de temperatură
3.4.3 Testarea preciziei de măsurare a senzorului de proximitate
3.4.4 Determinarea autonomiei de funcționare a dispozitivului
Capitolul 4 Prezentarea prototipului
4.1 Prezentarea meniurilor – manual de utilizare
4.1.1 Reprezentarea orei exacte în format digital
4.1.2 Reprezentarea orei exacte în format binar
4.1.3 Reprezentarea orei exacte în format analogic
4.1.4 Meniul principal
4.1.5 Jocul
4.1.6 Programul de desenare
4.1.7 Programul de măsurare a temperaturii
4.1.8 Programul de măsurare a distanței
4.1.9 Setarea orei exacte
4.1.10 Modul de utilizare economică a ceasului
4.2 Încărcarea dispozitivului
4.3 Recomandări în utilizarea ecranelor OLED
Concluzii
Bibliografie
Anexă – Codul sursă
Lista figurilor
1.1.1 Ecran PMOLED 128×128 pixeli 1,5 inch diagonală
1.2.1 Circuit integrat de RTC Dallas Semiconductor DS3234
1.3.1 Microcontroler ATMEL ATmega328 în două forme de încapsulare
1.3.3 Placheta unui microcontroler având conectate firele de legătură
1.4.1 Oscilator cu cuarț: a) formă generală de încapsulare b) având carcasa protectoare îndepărtată
1.5.1 Baterie litiu-polimer de mici dimensiuni
1.6.1 Mediul de dezvoltare de Arduino IDE
1.7.1.1 Sistemul SPI
1.7.2.1 Sistemul I2C
1.7.3.1 Comparație semnal transmis pe interfață serială utilizând standardul RS-232 (sus) și standardul TTL (jos)
1.7.4.1 Sistemul OneWireBUS
2.3.1 Diagrama bloc de interconectare a componentelor electronice
2.4.1 Schema electrică a circuitului complet ce formează dispozitivul
2.4.2 Schema experimentală a ansamblului hardware montat pe breadboard
2.5.1.1 Placa de dezvoltare Arduino Pro Mini. Pini de conexiune
2.5.1.2 Microcontrolerul ATmega328 în packaging TQFP32
2.5.1.3 Schema electrică a plăcii de dezvoltare. Conexiunile microcontrolerului cu pinii de comunicație ale plăcii de dezvoltare
2.5.2.1 Interfața de comunicație cu microcontrolerul
2.5.2.2 Componentele ansamblului ce formează ecranul OLED
2.5.2.3 Schema electrică pentru programarea ecranului
2.5.2.4 Montajul realizat pentru programarea ecranului pe breadboard
2.5.2.5 Etapele programării ecranului drept slave serial device
2.5.3.1 PCB ce conține RTC împreună cu oscilatorul cu cuarț
2.5.3.2 Asignația pinilor pentru integratul DS1307
2.5.4.1 Dimensiunile bateriei utilizate raportate la diametrul unei monede de 50 bani
2.5.5.1 Echipamentul periferic de intrare numit TrackBall
2.5.6.1 Rolul pinilor de conexiune ai senzorului de temperatură
2.5.6.2 Forma de încapsulare a senzorului împreună cu dimensiunile acestuia
2.5.7.1 Principiul de funcționare al senzorului ultrasonic utilizat pentru măsurarea distanței
2.5.7.2 Senzorul de proximitate: a) Ansamblul componentelor pe PCB; b) Pini de conectare.
2.5.8.1 Schema electrică a sistemului de încărcare
2.5.8.2 Modulul de încărcare – PCB asamblat împreună cu dimensiunile acestuia
2.5.9.1 Programatorul cu circuitul integrat FTDI-FT232RL – dimensiuni ansamblu general
3.1.1 Modelarea 3D a carcasei – schiță formată din componetele și dimensiunile lor
3.1.2 Reprezentarea detaliilor constructive ale curelei ceasului
4.1.1.1 Captură ecran – Ceas în format digital
4.1.2.1 Captură ecran – Ceas în format binar
4.1.3.1 Captură ecran – Ceas în format analogic
4.1.4.1 Captură ecran – Meniul principal
4.1.5.1 Captură ecran – Joc – Inițiere și joc pierdut
4.1.6.1 Captură ecran – Programul de desenare
4.1.7.1 Captură ecran – Programul de măsurare a temperaturii
4.1.8.1 Captură ecran – Programul de măsurare a distanței
4.1.9.1 Captură ecran – Setarea orei exacte
4.2.1 Încărcarea bateriei dispozitivului – procedură
4.3.1 Ecran deteriorat din cauza expunerii prelungite a ecranului la imagini statice
Introducere
Progresele realizate în domeniul electronicii, circuitelor intregrate și ușurința utilizării acestora au dus la îmbunătățirea tot mai pronunțată a sistemelor de dezvoltare și prin urmare, la posibilitatea realizării unor proiecte ce erau destul de greu de executat datorită lipsei de echipamente necesare în acest scop. Sistemele de dezvoltare sunt pachete realizate atât dintr-o componentă hardware cât și una software ce permit realizarea de experimente ale diferitelor configurații de componente electronice și a sistemelor de comunicație dintre acestea, în vederea realizării unor echipamente ce pot executa un set de funcții bine definit.
Odată cu avansarea tehnologiei, a devenit posibilă dezvoltarea unor proiecte destul de complexe care să funcționeze aproape la fel de bine ca un sistem realizat de o companie ce produce un echipament asemănător celui home-made menționat anterior. Astfel, există foarte multe medii de dezvoltare disponibile în vremurile noastre, ce concurează între ele pentru ocuparea unui segment de piață cât mai ridicat, oferă foarte multe beneficii utilizatorilor și nu implică un nivel foarte ridicat de cunoștiinte pentru realizarea unor proiecte pilot, pentru a putea introduce astfel, micul dezvoltator în era tehnologică.
Prin urmare, în acest proiect se vor prezenta etapele realizării unui dispozitiv electronic, care să execute numeroase funcții. Acest dispozitiv, dezvoltat în stadiul de prototip, este un ceas electronic multisenzorial, ce oferă pe lângă informații privind la momentul de timp și detalii referitoare la parametrii mediului înconjurător, prin utilizarea unui senzor ce măsoară și afișează pe ecranul ceasului valoarea temperaturii ambientale, cât și măsurarea și afișarea pe ecran a distanței dintre ceas și primul obiect aflat în calea acestuia, fapt realizat cu ajutorul unui senzor de proximitate ultrasonic.
De asemenea, acest ceas facilitează de trei tipuri diferite de prezentarea a orei exacte utilizatorului, cât și două aplicații recreative: un joc și un program de desenare ce oferă o paletă de culori pe 16 biți.
Astfel, în primul capitol este prezentată partea teoretică ce a oferit bazele realizării acestui proiect, în care sunt prezentate diferitele tehnologii implementate, caracteristici generale ale modulelor electronice și componenta software ce a contribuit la formarea întregului bloc funcțional.
Cel de-al doilea capitol, mai amplu, este realizat pentru prezentarea ideii de la care s-a plecat în dezvoltarea acestui dispozitiv, detalierea componentelor utilizate, specificațiile de funcționare ale acestora cât și motivarea alegerii lor în comparație cu alte componente disponibile. De asemenea, în acest capitol sunt prezentate schemele bloc ale ansamblului realizat cât și cele electrice și experimentale.
Al treilea capitol face referire la realizarea efectivă a ceasului, scierea codului sursă și transferul acestuia pe microcontrolerul dispozitivului împreună cu realizarea ansamblului fizic format din carcasa și cureaua acestuia. Produsul final a fost testat în vederea funcționlității caracteristicilor disponibile pentru realizarea unei comparații între nivelul de performanță al acestuia și cel obținut prin testarea altor dispozitive ce realizează funcții asemănătoare.
În ultimul capitol s-a pus accent pe realizarea unui manual de funcționare a ceasului, prezentând fiecare aplicație disponibilă, sugestii și contraindicații în utilizarea acestuia, altături de pașii ce trebuie urmați pentru încărcarea acumulatorului inclus în dispozitiv.
Capitolul 1
Introducere teoretică asupra tehnologiilor utilizate
Pentru realizarea prezentului dispozitiv a fost necesară însușirea mai multor noțiuni teoretice referitoare la funcționarea diferitelor componente electronice cum ar fi: afișajele OLED, senzori, programatoare și a tehnologiei de comunicație dintre acestea și un microcontroler RISC ce implementează arhitectura Harvard. De asemenea, a fost necesară cunoașterea unui limbaj de programare pentru a putea realiza un cod sursă, care în urma implementării acestuia să se execute funcțiile cerute. În cele din urmă, prin confecționarea unei carcase care să înglobeze toate aceste componente și să le ofere rezistență mecanică a fost posibilă realizarea ansamblului final.
1.1 Tehnologia ecranelor OLED
Termenul de OLED provine de la organic light-emitting diode adică diodă electroluminiscentă organică, de unde reiese faptul că un dispozitiv OLED este de fapt o diodă electroluminiscentă LED în care stratul de emisie este de natură organică și că acesta emite un flux de lumină la aplicarea unui curent electric acestuia. Acest strat, ce este realizat din semiconductor organic, este situat între doi electrozi, anodul si catodul, ce oferă o conexiune fizică între stratul semiconductor și sursa de curent.
Fig. 1.1.1 Ecran PMOLED 128×128 pixeli 1.5 inch diagonală
În general, cel puțin unul dintre electrozii componenți este transparent pentru a permite transmiterea luminii prin acesta. Dispozitivele de tip OLED sunt utilizate de obicei pentru realizarea display-urilor digitale ce se înglobează în telefoane mobile, televizoare, console de joc, monitoare, etc.
Aceste dispozitive, spre deosebire de cele LCD, nu necesită un sistem de iluminare a fundalului, de tip backlight, ceea ce reprezintă un avantaj în procesul de fabricație deoarece se pot obține astfel dispozitive de dimensiuni foarte reduse ca și grosime.
Afișajele de tip OLED se pot clasifica în 2 mari tipuri din punct de vedere al tehnologiei utilizate:
-Passive Matrix OLED (PMOLED);
-Active Matrix OLED (AMOLED).
Diferența dintre display-urile cu matrice activă si cele cu matrice pasivă este că display-urile cu matrice activă utilizează un strat suplimentar în realizarea ansamblului format dintr-un film de tranzistoare care au rolul de a activa și dezactiva fiecare pixel în mod individual. Această caracteristică prezintă un avantaj față de cele cu matrice pasivă deoarece se pot reda imagini mai clare însă există dezavantajul unui cost mai mare de producție a acestora.
1.2 Circuite integrate cu funcția de Real Time Clock
Un dispozitiv RTC este un sistem de calcul ce are rolul de a monitoriza unitatea de timp, cu un anumit nivel de precizie și este de obicei înglobat într-un circuit integrat cu scopul de a fi utilizat în sisteme complexe ce necesită detalii despre noțiunea de timp.
Se va face diferențierea între aceste dispozitive și cele ce sunt utilizate pentru crearea unui semnal de clock ce servește la sincronizarea semnalelor digitale în circuitele integrate precum microcontrolerele sau microprocesoarele.
Fig. 1.2.1 Circuit integrat de RTC Dallas Semiconductor DS3234
Deși nu este absolut necesară folosirea unui astfel de dispozitiv pentru menținerea noțiunii de timp, acest lucru fiind posibil de implementat prin programarea unui microcontroler obtrozi, anodul si catodul, ce oferă o conexiune fizică între stratul semiconductor și sursa de curent.
Fig. 1.1.1 Ecran PMOLED 128×128 pixeli 1.5 inch diagonală
În general, cel puțin unul dintre electrozii componenți este transparent pentru a permite transmiterea luminii prin acesta. Dispozitivele de tip OLED sunt utilizate de obicei pentru realizarea display-urilor digitale ce se înglobează în telefoane mobile, televizoare, console de joc, monitoare, etc.
Aceste dispozitive, spre deosebire de cele LCD, nu necesită un sistem de iluminare a fundalului, de tip backlight, ceea ce reprezintă un avantaj în procesul de fabricație deoarece se pot obține astfel dispozitive de dimensiuni foarte reduse ca și grosime.
Afișajele de tip OLED se pot clasifica în 2 mari tipuri din punct de vedere al tehnologiei utilizate:
-Passive Matrix OLED (PMOLED);
-Active Matrix OLED (AMOLED).
Diferența dintre display-urile cu matrice activă si cele cu matrice pasivă este că display-urile cu matrice activă utilizează un strat suplimentar în realizarea ansamblului format dintr-un film de tranzistoare care au rolul de a activa și dezactiva fiecare pixel în mod individual. Această caracteristică prezintă un avantaj față de cele cu matrice pasivă deoarece se pot reda imagini mai clare însă există dezavantajul unui cost mai mare de producție a acestora.
1.2 Circuite integrate cu funcția de Real Time Clock
Un dispozitiv RTC este un sistem de calcul ce are rolul de a monitoriza unitatea de timp, cu un anumit nivel de precizie și este de obicei înglobat într-un circuit integrat cu scopul de a fi utilizat în sisteme complexe ce necesită detalii despre noțiunea de timp.
Se va face diferențierea între aceste dispozitive și cele ce sunt utilizate pentru crearea unui semnal de clock ce servește la sincronizarea semnalelor digitale în circuitele integrate precum microcontrolerele sau microprocesoarele.
Fig. 1.2.1 Circuit integrat de RTC Dallas Semiconductor DS3234
Deși nu este absolut necesară folosirea unui astfel de dispozitiv pentru menținerea noțiunii de timp, acest lucru fiind posibil de implementat prin programarea unui microcontroler obișnuit, dar folosirea unui RTC este recomandată deoarece are următoarele avantaje :
– Folosirea unui sistem separat eliberează procesorul principal de astfel de activități care pot deveni problematice în situații de încărcare ridicată;
– Consumul mic de curent al RTC față de un microprocesor sau microcontroler ce ar executa același task;
– Acuratețe mai mare pentru menținerea noțiunii de timp în comparație cu celelalte procedee de păstrare a orei exacte;
– Existența unui sistem de backup cu baterie externă pentru cazul în care sursa principală de tensiune cedează, astfel, după revenirea tensiunii noțiunea de timp va rămâne de actualitate fără să mai fie nevoie de reprogramarea acesteia.
1.3 Unitatea de comandă și control
Un microcontroler este un sistem de calcul de mici dimensiuni realizat pe un singur circuit integrat, numit microcircuit, care conține un procesor, memorie și periferice de intrare-ieșire programabile pentru interacțiunea acestuia cu mediul exterior. Microcontrolerele sunt realizate pentru aplicații de tip embedded, spre deosebire de microprocesoare ce sunt utilizate în calculatoarele personale.
Aceste dispozitive sunt folosite în sisteme automatizate cum ar fi calculatoare pentru automobile, dispozitive de comandă și control, periferice ce se conectează la sistemele de calcul personale, electronice, electrocasnice și multe altele. Practic, aproape orice dispozitiv din cele pe care le folosim în viața cotidiană se rezumă la această inovație numită microcontroler pentru ca ele să poată funcționa. Prin reducerea dimensiunii și a costului de fabricație a acestor circuite integrate s-a făcut posibilă integrarea lor în tot mai multe dispozitive electronice.
Unele microcontrolere pot folosi instrucțiuni cu dimensiunea de doar 4 biți și cu o frecvență a clock-ului de doar 4KHz pentru a consuma cât mai puțină energie cu putință (consum de ordinul miliwaților). Acestea au capabilitatea de a păstra activă funcționalitatea lor în timpul așteptării execuției unei comenzi (cum ar fi apăsarea unei taste), astfel având un consum de energie foarte mic pe perioada așteptării (consum de ordinul nanowați), desemnându-le potrivite pentru aplicații în care folosirea unor baterii ca sursă de energie pe termen lung este potrivită.
De asemenea, există microcontrolere care au rolul de a executa operații cât mai rapid pentru a putea oferi rezultate aproape în timp real. Acestea pot fi procesoarele digitale de semnal (Digital Signal Processor) în care consumul de energie este mare datorită clock-ului ce funcționează la frecvențe înalte și a perifericelor care necesită un nivel ridicat de energie pentru a fi alimentate.
Primul microcontroler realizat pe un singur chip a fost Intel 4004, un microcontroler pe 4 biți, oferit spre vânzare pe piața americană în anul 1971. De-a lungul anilor costul de fabricație a scăzut, devenind tot mai accesibil în zilele noastre, fiind folosite de pasionații de electronică având disponibile comunități tot mai mari de suport tehnic pentru diverse tipuri de microcontrolere.
Referitor la memoria utilizată de aceste sisteme de calcul, în viitorul apropiat, memoria de tip MRAM ar putea deveni standard ca și tip de memorie utilizată deoarece are o durată de viață ridicată și implementarea ei in procesul de fabricație pentru realizarea plachetelor este relativ scăzută. Aproximativ 55% din microcontrolerele și microprocesoarele vândute la nivel global sunt cele pe 8 biți. Se poate menționa faptul că într-o locuință obișnuită a unei țări cu nivel de dezvoltare obișnuit se regăsesc în medie 4 microprocesoare de uz general și aproximativ 12 microcontrolere. Un automobil nou din perioada noastră cotat la un preț modest utilizează aproximativ 30 de microcontrolere pentru funcționarea corespunzătoare a acestuia, oferind multe avantaje în utilizarea acestuia față de cele în care erau aplicate sistemele clasice, neasistate electric.
a) b)
Fig. 1.3.1 Microcontroler ATMEL ATmega328 în două forme de încapsulare:
a) DIP28 b) TQFP32
De obicei, programele standard realizate pentru microcontrolere trebuie să nu depășească memoria internă disponibilă de care acesta dispune deoarece ar fi costisitor să se furnizeze un sistem extern, upgradabil, de memorie. Astfel, aplicațiile numite compilator și assembler sunt utilizate pentru a converti un limbaj de programare de uz general, ce este mai ușor de înțeles și folosit de programator, într-un limbaj de programare care să ocupe puțină memorie și să fie ușor de interpretat de microcontroler. Acest tip de cod se numește cod mașină și este nivelul cel mai scăzut pe care un astfel de dispozitiv poate să îl interpreteze.
În funcție de microcontroler, memoria poate să fie volatilă sau non-volatilă. Cea volatilă se mai numește Random Acces Memory (RAM) și poate fi modificată de programator, pe când cea non-volatilă care se mai numește Read Only Memory (ROM) și este scrisă de obicei de compania producătoare și nu mai poate fi modificată de utilizator ulterior.
Multe microcontrolere pun la dispoziție pini de intrare-ieșire de uz general (GPIO). Acești pini sunt configurabili de către programator pentru a putea îndeplini diverse funcții. Pinii pot fi setați ca pini de input, output sau ambele. În momentul în care pinii sunt setați ca și pini de intrare, aceștia se folosesc pentru a prelua informații din mediul exterior cum ar fi datele primite de la senzori, iar când sunt setați ca pini de ieșire aceștia permit controlul diverselor periferice ce le sunt atașate cum ar fi afișaje, difuzoare, motoare, LED-uri. Multe sisteme înglobate se folosesc de senzori ce oferă semnale în format analogic pentru a putea funcționa. Astfel, a fost necesar să se introducă convertoarele analog-digitale (ADC). Din moment ce procesoarele sunt realizate să interpreteze doar semnale digitale, ele nu pot funcționa folosind semnale analogice și nu pot interpreta aceste semnale primite de la alte dispozitive. Din acest motiv se utilizează convertoarele digital-analogice (DAC) care permit procesorului să trimită semnalele de ieșire într-un format analogic sau nivele de tensiune.
Fig. 1.3.2 Placheta unui microcontroler având conectate firele de legătură
Pe lângă convertoare, multe sisteme înglobate folosesc o varietate de contoare de timp. Unul dintre cele mai cunoscute versiuni de astfel de cronometre este contorul de interval de timp programabil (Programable Interval Timer – PIT). Un astfel de contor poate să numere de la o anumită valoare spre zero sau să crească de la o anumită valoare, depășind capacitatea unui registru pe care îl încarcă, întorcându-se la valoarea de zero. În momentul în care acest contor a atins valoarea de zero trimite un semnal procesorului pentru a-l informa că numărătoarea a fost încheiată. Acest mecanism este foarte folositor pentru aplicații în care timpul reprezintă un aspect important în funcționarea sistemului. Un exemplu ar fi folosirea unui astfel de contor pentru prelevarea programată la un anumit interval de timp a diferitelor valori oferite de o rețea de senzori externi.
Un alt circuit care este folositor pentru un microcontroler este cel de modulație a lățimii pulsului unui semnal (Pulse Width-Modulation – PWM) care facilitează controlul acestuia asupra motoarelor electrice, convertoarelor de putere, sintetizatoare audio și altele fără a consuma resurse suplimentare.
De asemenea, există și modulul de transmisie-recepție Asincron Universal (Universal Asynchronous Receiver-Transmiter-UART) care face posibilă recepția și transmisia informației prin intermediul unei conexiuni seriale fără a necesita foarte multe resurse suplimentare procesorului.
1.4 Oscilatoare cu cuarț
Oscilatorul cu cristal este un oscilator electronic ce se folosește de efectul piezoelectric al unui cristal ce vibrează pentru a genera un impuls electric la o frecvență foarte precisă.
Aceste tipuri de oscilatoare au fost introduse pentru a înlocui circuitele RLC, având o precizie mai bună a frecvenței de rezonanță față de cele menționate anterior.
Frecvența semnalului pe care acest tip de oscilator îl generează este folositoare pentru a păstra noțiunea timpului (ceasuri de mână cu cuarț), pentru a produce un semnal de clock stabil folosit în circuitele integrate digitale și mai sunt utilizate și pentru a stabiliza frecvențele sistemelor de transmisie-recepție radio.
Cel mai des întâlnit tip de cristal folosit în acest tip de oscilatoare este cuarțul de unde a provenit și numele de oscilatoare, cu cristal însă se pot folosi și alte materiale piezoelectrice în acest scop, cum ar fi materialele ceramice policristaline.
Aceste oscilatoare cu cuarț au o gamă de lucru între câțiva zeci de kilohertzi la câteva sute de megahertzi. Anual sunt fabricate peste 2 miliarde de astfel de oscilatoare și sunt folosite cel mai des în realizarea ceasurilor de mână, radiourilor, telefoanelor mobile, calculatoarelor și dispozitivelor electrocasnice.
De asemenea, aceste oscilatoare se regăsesc și în echipamente de măsura și testare, generatoarele de semnal, numărătoare, și osciloscoape.
Un cristal este un material de natură solidă ai cărui atomi, molecule sau ioni sunt poziționați într-o formă ordonată, în modele repetitive care se aplică pe toate cele 3 axe spațiale.
Avantajul utilizării cuarțului este că varianțele constantelor sale elastice și a dimensiunilor acestuia implică o dependență foarte scăzută a frecvenței de rezonanță în raport cu temperatura.
Caracteristicile specifice ale acestuia depind de modul în care vibrează și unghiul de tăiere al cristalului (relativ la axele cristalografice ale acestuia). Acest fapt duce la un oscilator sau filtru (în funcție de necesitate) de calitate înaltă deoarece frecvența sa de rezonanță prezintă variații mici.
Modelarea electrică a unui cristal de cuarț se poate realiza ca o rețea de elemente ce au o impedanță serie mică și o impedanță paralelă ridicată.
Frecvența caracteristică a unui cristal depinde de modul și forma în care acesta a fost tăiat. Un astfel de cristal este tăiat astfel încât frecvența sa să fie definită nominală la o temperatură de 25 °C. Acest fapt înseamnă că deviațiile de frecvență se vor putea observa prin supunerea cristalului la temperaturi ce vor fi diferite de această temperatură nominală.
Matematic, impedanța acestei rețele se poate scrie folosindu-ne de transformata Laplace prin următoarele relații:
, unde este frecvența în formă complexă, , este frecvența unghiulară a rezonanței serie și este frecvența în paralel.
a) b)
Fig. 1.4.1 Oscilator cu cuarț:
a) formă generală de încapsulare b) având carcasa protectoare îndepărtată
1.5 Bateriile litiu-polimer
Bateriile litiu-polimer sunt acumulatori reîncărcabili de energie electrică compuși din multiple celule conectate în paralel. Această grupare de celule este realizată pentru a furniza un curent ridicat de descărcare și există cazuri în care se pot conecta în serie mai multe astfel de grupări de celule pentru a putea obține o tensiune mai mare de alimentare.
Tensiunea unei baterii Li-Po variază între 2,7V (descărcată) si 4,23V (încărcată). Un nivel ridicat de atenție trebuie acordat încărcării bateriilor Li-Po deoarece acestea se vor deteriora dacă tensiunea acestora depășește pragul critic de 4,235V.
Aceste baterii sunt capabile să reziste la un număr mediu de 350 de cicluri de încărcare-descărcare, după acest număr fiind posibilă diminuarea capacității de încărcare pana la 80% din valoarea inițială, dar există baterii litiu-polimer concepute să reziste până la 500 de cicluri încărcare-descărcare.
Un avantaj major al acestor baterii este că fabrica producătoare poate să le confecționeze în aproape orice formă este nevoie, ce poate fi un aspect foarte important în cazul dispozitivelor ce au spațiul destinat stocării bateriilor cu o formă specială în care o baterie obișnuită nu ar putea fi folosită pentru a obține aceeași capacitate de stocare.
De asemenea, un alt avantaj al acestor baterii este faptul că sunt relativ ușoare în comparație cu alte baterii realizate prin tehnologii asemănătoare, cum ar fi bateriile Litiu-Ion, fiind astfel preferate în aplicații unde greutatea produsului final trebuie să fie minimă.
Fig. 1.5.1 Baterie litiu-polimer de mici dimensiuni
Există câteva precauții ce trebuie să fie îndeplinite pentru a putea folosi în siguranță astfel de baterii și anume:
Supraîncărcarea acestor baterii poate duce la explozia acestora și provocarea de incendii
Trebuie avut în vedere ca tensiunea bateriei să nu scadă sub nivelul de 3V dacă aceasta furnizează energie electrică unui consumator.
Doar încărcătoarele dedicate acestor baterii trebuiesc utilizate deoarece alte tipuri ar putea supraîncărca bateriile.
Dacă bateria este scurtcircuitată există riscul ca aceasta să explodeze.
Deteriorarea sau găurirea bateriilor poate provoca incendii sau chiar explozia acestora.
1.6 Limbajul de programare
Un limbaj de programare este un limbaj artificial creat pentru a facilita furnizarea instrucțiunilor de la programator către sistemul de calcul. Prin intermediul limbajului de programare putem crea programe cu scopul de a controla unitatea de procesare sau pentru a-i cere parcurgerea unor algoritmi.
Limbajul de programare este compus de obicei din 2 componente: sintaxa și semantica.
Sintaxa limbajului de programare este formată dintr-un set de reguli ce definesc o combinație de simboluri ce sunt considerate a fi corect structurate într-un program.
Limbajului de programare este divizat din punct de vedere sintactic pe 3 nivele:
Cuvinte – nivelul lexical ce stabilește cum formează caracterele simboluri;
Fraze – nivelul gramatical ce stabilește cum simbolurile formează fraze;
Context – nivelul în care se stabilește la ce se referă obiectele sau variabilele și dacă tipul acestora este valid.
Semantica într-un limbaj de programare este importantă deoarece definește limbajul în care este scris programul.
Au fost create mai multe moduri de descriere a semanticii limbajelor de programare, bazate pe logica matematică și anume:
Semantica operațională – sensul instrucțiunilor este specificat de procesarea ce este indusă când acestea se execută pe un sistem de calcul. În acest caz ne interesează cum este produs efectul acestei procesări.
Semantica denotativă – înțelesul efectului execuției instrucțiunilor este modelat prin obiecte matematice. Astfel, doar efectul este de interes și nu modalitatea de obținere al acestuia.
Semantica axiomatică – specifică proprietățile efectului execuției unor instrucțiuni exprimate ca afirmații.
Scopul acestui limbaj este de a se scrie programe de către un programator pentru ca sistemul de calcul să proceseze calculele, să parcurgă algoritmii sau să controleze dispozitivele externe atașate acestuia cum ar fi scanere, roboți, imprimante, memorii externe. Limbajele de programare diferă de cele naturale prin faptul că cele din urmă sunt folosite doar pentru interacțiunea dintre oameni, în timp ce primele sunt utilizate de oameni pentru a interacționa cu mașinile de calcul, dându-le instrucțiuni ce trebuiesc executate.
Limbajele de programare împrumută caracteristici de la limbajele naturale prin faptul că ambele au atât o formă sintactică cât și una semantică, iar diferitele tipuri de limbaje artificiale se ramifică în diferite familii din forma sa generală. Există și diferențe majore între acestea cum ar fi faptul că limbajul de programare are o formă precisă, pe când cel natural, poate avea mai multe înțelesuri pentru același cuvânt.
Aceste limbaje artificiale au fost dezvoltate de la zero, derivând din forma generală, fiecare tip în parte fiind modificat în funcție de scopul folosirii acestuia. Deși au fost încercări de a realiza un limbaj de programare universal, acest lucru a fost imposibil până în momentul de față deoarece diversitatea domeniilor de aplicare este foarte vast și nu ar fi fost posibilă înglobarea tuturor într-un singur program.
Necesitatea realizării unei game variate de limbaje de programare a dus la realizarea mai multor clase de limbaje pentru:
Programe capabile de realizarea managementului vitezei, simplitatea și dimensiunea sistemelor pe care rulează plecând de la microcontrolere până la supercalculatoare.
Programe care cer cunoștințe de programare pornind de la nivelul începătorilor până la programatorii experți.
Programele care au o dimensiune mică ce se pot scrie de programatorii amatori până la programe foarte vaste ce necesită implicarea unor întregi echipe de dezvoltare.
Programe care pot fi scrise o singură dată, care nu sunt destinate modificărilor până la programe ce trebuie să fie in continuă posibilitate de îmbunătățire.
Programe ce necesită un anumit tip de limbaj de programare, care poate să fie preferențial unui anumit grup de programatori.
Fig. 1.6.1 Mediul de dezvoltare de Arduino IDE
1.7 Sistemele de comunicație
În interiorul sistemelor de calcul, BUS-ul de comunicație asigură transferul de informație între componentele acestuia. Acest lucru se realizează în general, atât în interiorul unui sistem de calcul, cât și între mai multe sisteme de calcul.
Astfel, există două tipuri de BUS-uri de comunicație: BUS intern, folosit pentru comunicația între componentele unui sistem de calcul cum ar fi procesorul împreună cu memoria și BUS extern, implementat pentru a facilita comunicația între sistemul de calcul și componentele periferice ale acestuia, precum tastatura, mouse-ul, imprimanta.
Din punct de vedere al metodei de implementare BUS-ul de comunicație poate fi catalogat în două mari categorii: comunicație paralelă și comunicație serială.
Comunicația paralelă realizează, după cum sugerează numele, transferul simultan de informație pe linii paralele de comunicație. Diferența față de comunicația serială este aceea că sunt folosite mai multe conexiuni fizice între interfețele de comunicație și că în stadiul inițial de implementare al acestor două tehnologii, comunicația paralelă era de n ori mai rapidă decât cea serială, unde n este numărul de canale folosite de interfața paralelă, dacă viteza clock-ului folosit pe ambele interfețe de comunicație era aceeași.
Odată cu trecerea anilor s-a pus accent pe dezvoltarea unui sistem de comunicație de mare viteză și astfel au apărut numeroase tehnologii ce au la bază comunicația serială. Mai departe vom dezbate câteva dintre aceste tehnologii, folosite de altfel, în realizarea acestui proiect.
Printre sistemele de comunicație utilizate între componentele dispozitivului se pot enumera: SPI, I2C, OneWireBus și TTL.
1.7.1 Sistemul SPI
Serial Peripheral Interface (SPI) este un sistem sincron de comunicație serială, dezvoltat de compania Motorola, ce operează în mod full duplex. Acesta este folosit pe distanțe scurte și se implementează în sisteme integrate. Dispozitivele ce comunică folosind acest protocol funcționează în regim de master-slave, master-ul inițializând data frame-ul pentru transferul de informație. Sistemul este funcțional dacă există în componența ansamblului un singur master și unul sau mai multe salve-uri. Configurația SPI mai este numită și interfață serială cu 4 fire, iar din acest motiv SPI se mai numește și Interfață Serială Sincronă (SSI).
Această interfață este caracterizată prin intermediul a patru semnale de comunicație și anume: SCLK (Serial Clock), semnalul de clock care este furnizat de interfața setată drept master, MOSI (Master Output Slave Input), ce reprezintă semnalul ce realizează transferul de informație de la master spre slave, MISO (Master Input Slave Output), care reprezintă semnalul trimis de slave către master. În cele din urmă, semnalul SS (Slave Select) este acel semnal care este trimis de master pentru a face distincția între diferitele interfețe slave disponibile la comunicația cu acesta.
Fig. 1.7.1.1 Schemă bloc de funcționare a sistemului SPI
1.7.2 Sistemul de comunicație I2C
Sistemul de comunicație I2C este dezvoltat pe baza protocolului de comunicație serială și a fost pus în aplicare de compania Philips în anii 1980. Acest sistem a fost creat pentru a facilita comunicația la viteze reduse între unitatea centrală de procesare și dispozitivele periferice ale unui sistemului de calcul. Acest sistem de comunicație folosește două canale de date, Serial Data Line (SDA) și Serial Clock Line (SCL), iar acestea necesită utilizarea unor rezistoare de tip Pull-Up.
Fig.1.7.2.1 Schema bloc a sistemului I2C. Principiul de funcționare
Acest sistem utilizează, de obicei, un spațiu de adrese între 7 și 10 biți (în funcție de dispozitivul utilizat se poate ajunge până la 16 biți) și viteza medie de transfer este de 100 kbiți/s. Viteza minimă este de 10 kbiți/s, iar cea maximă este de 3,4 Mbiți/s.
I2C este foarte răspândit, ca și implementare, în sisteme embedded de experimentare cum sunt sistemele Arduino si Raspberry Pi, deoarece nu necesită conector standard între componenta periferică și restul sistemului.
1.7.3 Sistemul TTL
Majoritatea microcontrolerelor au disponibile cel puțin un port de UART ce poate fi utilizat pentru a putea transmite informație către un alt dispozitiv prin interfața serială. Porturile UART transmit câte un bit la o anumită viteză predefinită (ex. 9600 bps) și această metodă de transmisiune serială se mai numește serial TTL (transistor-transistor logic). Comunicația serială la nivelul TTL va funcționa întotdeauna cu semnalul având variații între valorile de 0V si Vcc, unde Vcc este obicei 5V sau 3,3V.
În cazul TTL semnalul de high este reprezentat prin valoarea tensiunii lui Vcc, iar cel de low este reprezentat de 0V. Spre deosebire de TTL, comunicația serială RS-232 utilizează un standard de telecomunicații în care semnalele transmise au valori diferite față de standardul TTL. Aceste semnale sunt similare cu cele TTL utilizate de microprocesor însă există unele diferențe din punct de vedere hardware, ceea ce duce la incompatibilitatea dintre aceste două standarde. Astfel, nivelul de high la RS-232 este reprezentat de o valoare negativă a tensiunii Vcc, această tensiune fixă având valoarea setată în funcție de sistemul utilizat din intervalul de valori [-3V; -25V]. Pe de cealaltă parte, nivelul de low este reprezentat de o valoare pozitivă a tensiunii Vcc, această valoare fiind fixată din intervalul disponibil de [+3V; +25V].
De obicei, majoritatea sistemelor de calcul PC utilizează o gamă de valori pentru high, respectiv low de -13V și +13V. Setarea acestor valori pentru nivelele de semnal ce prezintă diferențe atât de ridicate este necesară pentru a avea posibilitatea de a efectua transmisiuni de date atât pe distanțe mai lungi fără degradarea semnalului cât și într-un mediu supus unui nivel de zgomot ridicat.
Fig. 1.7.3.1 Comparație semnal transmis pe interfață serială utilizând standardul RS-232 (sus) și standardul TTL (jos)
1.7.4 Sistemul OneWireBUS
În cele din urmă vom dezbate unul dintre cele mai minimaliste metode de comunicație realizate pe interfață serială folosind tehnologia de OneWireBUS, în care transferul de date se realizează pe o singură linie de comunicație. Această tehnologie este asemănătoare cu cea I2C, cu precizarea că vitezele de transfer sunt mai mici la OneWireBUS, dar cu o distanță de comunicație mai mare față de I2C. Aceasta tehnologie a fost dezvoltată de compania Dallas Semiconductor și folosește în mod normal trei pini de conexiune Vcc, GND și DATA, dar se pot folosi în anumite cazuri doar doi pini: DATA și GND.
Dispozitivele realizate cu scopul de a comunica prin intermediul acestui sistem sunt confecționate în general folosind un package de tip TO92 dar sunt utilizate și alte tipuri de carcase pentru aceste circuite integrate.
Majoritatea produselor ce funcționează pe baza acestui principiu de comunicație sunt senzorii de temperatură, umiditate, actuatori, memorii dar și altele.
Fig. 1.7.4.1 Package de tip TO92 folosit în majoritatea senzorilor și perifericelor
ce folosesc tehnologia OneWire BUS
Capitolul 2
Proiectarea prototipului
2.1 Scopul realizării proiectului
Scopul realizării acestui proiect a fost crearea unui dispozitiv handheld care să fie de ajutor persoanelor ce au deficiente senzoriale, dar și persoanelor care lucrează în medii ostile, în care un astfel de dispozitiv ar fi de ajutor pentru detectarea în avans a unor parametrii fără a pune în pericol viața celui pus într-un astfel de impediment. Câteva exemple de aplicații pentru un astfel de dispozitiv ar fi detectarea distanței de la utilizator la un perete, în condițiile în care acesta are deficiențe vizuale sau ar putea fi folositor pompierilor care urmează să acceseze un imobil, în care s-a declanșat un incendiu, aceștia reușind să măsoare în avans temperatura incintei, ca apoi sa poată lua o decizie față de accesarea sau nu în condiții de siguranță a acestuia.
Acest ceas deține posibilitatea conectării unor astfel de senzori, urmând ca informațiile furnizate de aceștia să poată fi afișate pe ecranul dispozitivului. Pe lângă aceste particularități, ceasul a fost proiectat să poată fi folosit și ca un sistem de recreere, având disponibile aplicația de desenare și jocul. Mulțumită faptului că a fost folosit un mediu de dezvoltare relativ ușor de folosit, există întotdeauna posibilitatea adăugării de aplicații și senzori interschimbabili, reușind astfel să se modeleze dispozitivul după nevoia utilizatorului.
2.2 Listă de materiale utilizate în realizarea prototipului
Pentru realizarea dispozitivului s-a ales achiziționarea individuală a fiecărui subansamblu necesar de la un furnizor local, urmând ca acestea să fie asamblate într-un bloc hardware ce v-a fi inclus în interiorul unei carcase realizate din material plastic–sticlă acrilică.
Această carcasă va conține majoritatea componentelor cu excepția senzorilor și a TrackBall-ului de control al dispozitivului, acestea din urmă fiind atașate pe cureaua ceasului.
Cureaua este realizată dintr-un material textil ce oferă rezistență ridicată la forțe externe ce ar putea deteriora-o și facilitează de un sistem de prindere cu scai pentru reglarea acesteia în mod facil, fiind capabilă de cuprinderea unei game variate de dimensiuni ale încheieturii mâinii utilizatorului.
În continuare se va prezenta lista de materiale pe baza căreia s-a asamblat dispozitivul prezentând descrierea și prețurile de achiziție ale acestora. Se va ține cont de faptul că nu au fost menționate în această listă toate elementele diverse utilizate pentru a se menține o prezentare succintă a acestora.
Tabel 2.2.1 Listă de materiale utilizate în realizarea prototipului
2.3 Diagrama bloc a componentelor electronice
Pentru schițarea componentelor electronice ce formează ansamblul hardware și a conexiunilor dintre acestea s-a recurs la realizarea unei scheme bloc pentru o mai bună prezentare a acestor detalii. Astfel, se pot observa atât conexiunile unidirecționale cât și cele bidirecționale dintre componente
De asemenea, s-a ales reprezentarea separată a conexiunilor ce asigură transferul de date alături de cele realizate doar cu rolul de alimentare cu energie electrică a circuitului.
Conexiunile de culoare roșie reprezintă circuitele de alimentare, respectiv de încărcare a bateriei, cele de culoare galbenă semnifică legăturile de comunicație serială bidirecționale, iar culoarea verde semnifică intrările digitale oferite de echipamentul periferic de control al dispozitivului. Această schemă bloc se poate observa în figura 2.3.1 de mai jos.
2.4 Schema electrică a circuitului
Pentru realizarea schemei electrice a dispozitivului s-a apelat la reprezentarea acesteia prin intermediul a două metode diferite de design, una teoretică, prezentată în figura 2.4.1, în care sunt reprezentate conexiunile dintre componentele electronice împreună cu tipul conexiunilor acestora, alături de o reprezentare experimentală în care sunt detaliate conexiunile acestor componente, la scară reală, prin poziționarea virtuală a acestora pe un breadboard, acestea observându-se în figura 2.4.2. Atât în prima, cât și în a doua reprezentare grafică au fost numerotate componentele pe baza numărului curent din lista de materiale atașată anterior pentru o mai bună detaliere a acestora.
Fig. 2.3.1 Diagrama bloc de interconectare a componentelor electronice
Fig. 2.4.1 Schema electrică a întregului circuitului ce formează dispozitivul
Fig. 2.4.2 Schema experimentală a ansamblului hardware montat pe breadboard
2.5 Prezentarea componentelor electronice utilizate în realizarea prototipului
Pentru realizarea acestui proiect s-a luat decizia achiziționării modulelor preasamblate pe PCB-uri individuale, urmând ca acestea să fie interconectate pentru realizarea produsului finit. Astfel, vom iniția cu descrierea fiecărei componente prezentând specificațiile acestora și bineînțeles ce avantajele ce s-au luat în considerare pentru alegerea acestora în raport cu altele.
2.5.1 Placa de dezvoltare Arduino Pro Mini
Cea mai importantă componentă a acestei realizări este unitatea de control, obținută prin intermediul utilizării unei plăci de dezvoltare Arduino Pro Mini 3,3V 8MHz.
Această placă de dezvoltare conține următoarele componente:
Microcontrolerul Atmel ATmega 328, versiunea ce funcționează la o tensiune de alimentare de 3,3V și are o viteză de clock de 8MHz;
Rezonatorul cu cuarț având frecvența de rezonanță de 8MHz;
Un stabilizator de tensiune, cu tensiunea de ieșire de 3,3V;
LED de status roșu, ce este aprins constant în momentul alimentării plăcii de dezvoltare;
LED programabil verde, care se poate programa să se aprindă în funcție de comenzile scrise de dezvoltator;
Buton de resetare;
Componente electronice pasive necesare funcționării și programării microcontrolerului.
Motivele alegerii acestei plăci de dezvoltare sunt fost următoarele:
Dimensiunile acesteia sunt reduse (33x18x0,8mm);
Suportă funcția de Auto-Reset, folositoare în momentul programării acesteia;
Funcționează la o tensiune de alimentare de 3,3V, acest lucru fiind absolut necesar pentru a putea utiliza o baterie litiu-polimer ce are o tensiune nominală de 3,7V. De asemenea, utilizarea unei tensiuni de 3,3V are rolul de a avea un consum redus de energie pe unitatea de timp, permițând astfel să se obțină o autonomie mai bună a dispozitivului. Combinația de tensiune de alimentare împreună cu frecvența de procesare conduce la un microcontroler cu un consum mai mic de energie față de unul ce se alimentează la o tensiune de 5V și are o frecvență de lucru de 16MHz;
Suportă alimentarea prin intermediul acesteia a mai multor dispozitive periferice cu un curent total de alimentare de maxim 150mA;
Datorită stabilizatorului de tensiune integrat utilizat, placa de dezvoltare beneficiază de protecție împotriva unor curenți de consum mai mari de 150mA;
Tensiunea de alimentare a plăcii de dezvoltare este cuprinsă într-un interval generos de la 3,3VDC până la 12VDC, ceea ce aduce posibilitatea alimentării acesteia prin intemediul unei game variate de surse de energie;
Există un număr impresionant de 14 pini digitali I/O și 8 pini analogici, ținând cont de dimensiunile efective ale plăcii;
Din cei 14 pini digitali, 6 pini pot fi utilizați ca ieșiri PWM (Pulse Width Modulation);
Programarea acesteia este facilă prin folosirea unui programator dedicat acesteia, folosindu-se de 6 pini de conexiune: BLK, GND, VCC, RXI, TXO si GRN;
În cele din urmă, greutatea acestei plăci este doar de 2 grame, facilitând la realizarea unor dispozitive cât mai ușoare cu putință.
Fig. 2.5.1.1 Placa de dezvoltare Arduino Pro Mini. Pini de conexiune
Această placă de dezvoltare a fost realizată în jurul microcontrolerului, prezentând, în mare parte, suport de montare pentru acesta. Astfel, se oferă posibilitatea de experimentare în procesul de realizare a unui produs fără a mai fi nevoie de producerea unui PCB cu acest scop, ulterior fiind posibilă realizarea unui PCB cu configurația finală.
Prin urmare, în alegerea plăcii de dezvoltare s-a ținut cont de fapt de puterea de procesare a microcontrolerului atașat acesteia, dar și de numărul pinilor de comunicație cu echipamentele periferice. Astfel, s-a ales un microcontroler care să aibă o putere scăzută, strict necesară, de procesare cu scopul obținerii unui produs cu durată de viață a bateriei de alimentare cât mai mare. Puterea de procesare a fost stabilită ca fiind suficientă în alegerea acestui microprocesor deoarece informațiile afișate pe ecranul dispozitivului nu necesită operații complexe de calcul a acestora, iar timpul de interogare a senzorilor atașați acestuia se dorește a fi mare deoarece un refresh rate ridicat ar duce la variații mari în informațiile afișate utilizatorului, introducând astfel erori de citire a senzorilor, fiind nefolositoare utilizatorului final.
Vom prezenta în continuare microcontrolerul ATMEL ATmega 328 precizând caracteristicile și avantajele folosirii acestui microcontroler.
Tabel 2.5.1.1 Caracteristici microcontroler ATMEL ATmega328
Microcontrolerul ATMEL ATmega328 face parte din categoria microcontrolerelor RISC, ce dispunde de o magistrală de date pe 8 biți, având un consum redus de energie, cu un set de 131 de instrucțiuni – majoritatea lor executabile într-o singură perioadă de clock.
Fig. 2.5.1.2 Microcontrolerul ATmega328 în packaging TQFP32 – dimensiuni efective
Acest microcontroler dispune de un număr de 32 registre pe 8 biți conectați direct la UAL (Unitatea Aritmetico-Logică), permițând astfel accesul simultan la 2 registre într-o singură instrucțiune. De asemenea, acesta dispune de o interfață serială TTL prin intermediul căreia se poate programa microcontrolerul. Alte interfețe de comunicație pe care acesta le dispune sunt următoarele:
O interfață de comunicație serială asincronă;
O interfață de comunicație serială SPI;
8 canale de comunicație analogice pe 10 biți;
14 canale comunicație digitale I/O;
2 canale analogice din cele 8 enumerate mai sus formează interfața de comunicație I2C.
După cum s-a precizat anterior, acest microcontroler beneficiază de un consum redus de energie electrică, consumul de curent al acestui microcontroler fiind descris de tabelul 2.5.1.2. Astfel, se pot observa valorile foarte scăzute, facilitând astfel la o autonomie cât mai buna a prototipului.
Tabel 2.5.1.2 Consumul de curent al microcontrolerului ATmega328
Avantajele folosirii acestui model de microcontroler sunt următoarele:
Consum redus de curent;
Număr suficient de registre disponibile;
Număr suficient de canale de comunicație digitale și analogice;
Plajă largă de temperaturi de lucru;
Curent ridicat de alimentare al perifericelor atașate;
Disponibilitatea multiplelor tehnologii de comunicație pe interfață serială;
Dimensiuni reduse ale packagingului;
Număr ridicat de instrucțiuni.
Un dezavantaj al acestui microcontroler ar putea fi spațiul relativ redus de memorie pentru încărcarea codului sursă, totuși fiind suficient în acest caz.
Fig. 2.5.1.3 Schema electrică a plăcii de dezvoltare –
Conexiunile microcontrolerului cu pinii plăcii de dezvoltare
2.5.2 Ecranul PMOLED
În continuare se va prezenta ecranul folosit în realizarea produsului finit. Acest ecran este de tip PMOLED cu o rezoluție de 128×128 pixeli și o diagonală a ecranului de 1,5 inchi fabricat de compania 4D Systems. Caracteristicile acestuia sunt prezentate în tabelul 2.5.2.1.
Tabel 2.5.2.1 Caracteristicile ecranului 4D Systems μOLED-128-G2-GFX
Acest ansamblu conține ecranul propriu-zis montat pe un PCB ce facilitează de un procesor grafic, un slot pentru cardul microSD, o interfață de conectare cu 10 pini și două stabilizatoare de tensiune: unul pentru ecranul OLED și cel de-al doilea pentru procesorul grafic. Această descriere se poate observa în figura 2.5.2.1.
Pentru conexiunea ecranului la microcontroler vom folosi doar 5 din cei 10 PINI disponibili. În figura 2.5.2.2 de mai jos putem observa această interfață și rolul fiecărui PIN din compunerea ei.
Pin-ul 1 (+5V) este folosit pentru alimentarea ecranului. Comunicația serială dintre ecran și microcontroler se realizează cu ajutorul pini-lor 3 (TX) și 5 (RX). Pentru masă se folosește pin-ul 7 (GND), iar pentru resetarea ecranului utilizăm pin-ul 9 (RES).
Fig. 2.5.2.1 Componentele ansamblului ce formează ecranul OLED
1. Ecran cu diagonala de 1,5 inchi 2. Rezoluție ecran 128×128 pixeli
3. Procesor grafic Goldelox 4. Interfață conectare 5×2 PINI
5. Canale comunicație GPIO x 2 6. Slot card microSD
7. Ramă cu găuri de montare 8. Stabilizatoare tensiune x 2
Fig.2.5.2.2 Interfața de comunicație cu microcontrolerul
Prezentul ansamblu ecran-procesor grafic poate funcționa în două moduri: modul master și modul serial slave.
La achiziționarea ecranului, acesta este programat inițial de către producător drept master, ansamblul având procesorul grafic și fiind capabil sa afișeze imagini salvate pe un card microSD.
Pentru a putea utiliza ecranul în acest proiect a fost necesară programarea acestuia drept serial slave, pentru a putea comunica cu microcontrolerul și a primi informațiile ce trebuiesc afișate pe acesta. Schema electrică de conectare a acestora este prezentată în figura 2.5.2.3, iar cea experimentală realizată pe breadboard este în figura 2.5.2.4.
Programarea ecranului a fost realizată cu ajutorul aceluiași programator USB FTDI Serial, utilizat la programarea microcontrolerului. Acțiunea efectivă de programare s-a realizat in mediul de dezvoltare a producătorului numit 4D Workshop 4 IDE.
Fig. 2.5.2.3 Schema electrică pentru programarea ecranului
Fig. 2.5.2.4 Montajul realizat pentru programarea ecranului pe breadboard
În continuare va fi prezentată procedura de programare a ecranului, folosind mediul de dezvoltare 4D Workshop 4 IDE, urmând pașii din figura 2.5.2.5 de mai jos:
Fig. 2.5.2.5 Etapele programării ecranului drept slave serial device
2.5.3 Modulul de Real Time Clock
Modulul de Real Time Clock (RTC) este una din componentele esențiale realizării acestui dispozitiv, fără de care nu s-ar putea menține ora exactă cu un consum redus de energie. Microcontrolerul poate fi programat să mențină ora exactă, dar nu este un este o opțiune pe care dorim să o realizăm deoarece s-ar mări consumul de energie și s-ar putea reseta ora exactă în momentul repornirii sau opririi alimentării dispozitivului.
Pe de cealaltă parte, modulul de RTC nu depinde de microcontroler pentru a menține ora exactă și nu necesită alimentarea acestuia cu aceeași sursă de curent folosită la alimentarea microcontrolerului. Modulul RTC facilitează de o baterie externă de backup, de mici dimensiuni, utilizată doar pentru alimentarea integratului în momentul decuplării sursei principale de energie. O baterie cu capacitatea de stocare de 48mAh este capabilă să alimenteze continuu circuitul RTC pentru o perioadă de aproximativ 10 ani, dacă acesta este păstrat la o temperatură ambientală de 25°C, integratul având un consum de curent mediu de 300nA, având variații de consum între starea de standby și starea activă. Aceste valori sunt menționate în tabelul 2.5.3.1 alături de alte caracteristici alte acestui modul. De asemenea, ansamblul realizat prin utilizarea integratului DS1307 se poate observa în figura 2.5.3.1.
Fig. 2.5.3.1 PCB ce conține RTC împreună cu oscilatorul cu cuarț
Acest integrat este realizat de compania Dallas Semiconductor și este modelul DS1307. Circuitul măsoară timpul având ca unități de măsură secundele, minutele, orele, zilele, luna și anul, ținând cont de anii bisecți până în anul 2100.
Circuitul este realizat astfel încât să țină cont de lunile care au mai puțin de 31 zile calendaristice, iar ora poate fi prezentată atât în formatul 24h cât și în formatul 12h cu indicator AM/PM. Memoria RAM are dimensiunea de 56 octeți, este nevolatilă, și este asistată de bateria de backup.
Fig. 2.5.3.2 Asignația pinilor pentru integratul DS1307
Comunicația dintre modul RTC și microcontroler se realizează prin intermediul unei conexiuni de tip I2C, iar pinii de conectare către microcontroler sunt pinul 5 (SDA) și pinul 6 (SCL). Pinii 1 (X1) și 2 (X2) sunt destinați conectării la rezonatorul cu cuarț, ce trebuie să aibă frecvența de rezonanță de 32,768 KHz. Alimentarea circuitul se realizează prin pinul 8 (VCC) la o tensiune de 3,3V, fiind alimentat de microcontroler. În momentul în care este întreruptă alimentarea de la microcontroler circuitul este comutat automat astfel încât acesta să se alimenteze de la bateria de backup, conectată la integrat prin intermediul pinul 3 (VBAT). Circuitul de alimentare al integratului este închis prin pinul de masă 4 (GND). În realizarea dispozitivului prezentat nu a fost utilizat pinul 7 (SQW/OUT), nefiindu-ne necesar acest semnal periodic dreptunghiular generat de RTC.
În lanțul de comunicație serială I2C, modulul DS1307 funcționează ca un dispozitiv de tip slave, master-ul fiind microcontrolerul. În momentul în care tensiunea Vcc scade sub valoarea de 1,25 x VBAT circuitul RTC închide conexiunea cu microcontrolerul pentru a evita transmisiunea unor informații eronate acestuia. În momentul în care VCC scade sub valoarea lui VBAT modulul RTC intră într-o stare de funcționare economică funcționând pe baza energiei furnizate de bateria de backup. Dacă sursa de alimentare principală redevine activă și tensiunea acesteia este cel puțin egală cu VBAT+0,2V atunci se va realiza comutarea alimentării înapoi la tensiunea VCC.
Caracteristicile integratului RTC DS1307 preluate din foaia de catalog a fabricantului sunt prezentate în tabelul 2.5.3.1 de mai jos:
Tabel 2.5.3.1 Caracteristicile modulul RTC Dallas DS1307
În concluzie, alegerea utilizării acestui circuit integrat pentru RTC a fost motivată de dimensiunile reduse ale modulului, consumul redus de energie al acestuia, existența unui sistem de backup pentru a nu trebui setată ora și data la fiecare resetarea a dispozitivului și precizia menținerii orei exacte.
2.5.4 Bateria litiu-polimer
Pentru alimentarea acestui dispozitiv s-a apelat la utilizarea unei baterii litiu-polimer cu tensiunea nominală de 3,7V și capacitatea de 110mAh. Motivul alegerii acestui model de acumulator a fost faptul că tehnologia litiu-polimer permite realizarea unor acumulatori ce se pot modela în forme complexe, în funcție de spațiul disponibil, față de alte tehnologii în care acest lucru nu este realizabil.
De asemenea, acumulatorii realizați prin intermediul acestui proces tehnologic au un indice de greutate mai mic față de alte tipuri de acumulatori, rezultând în final un produs mai ușor față de același produs ce ar fi utilizat o baterie Ni-MH.
În continuare se vor prezenta caracteristicile acestui acumulator în tabelul 2.5.4.1 pe baza foii de catalog publicată de producătorul acestuia.
Tabel 2.5.4.1 Parametrii acumulatorului litiu-polimer utilizat
Factorul determinant în alegerea acestui acumulator a fost dimensiunea efectivă a acestuia, după care s-a ținut cont de greutatea acestuia și în cele din urmă capacitatea de stocare.
Avantajul acestui model de acumulator este că acesta are încorporat un sistem de monitorizare împotriva supraîncărcării atât din punct de vedere al curentului cât și a tensiunii de încărcare ce l-ar putea deteriora. Se poate observa aspectul fizic al acumulatorului în comparație cu o monedă așezată lângă acesta. Imaginea este sursă proprie realizată în cadru real, ce pune în evidență dimensiunile reduse în raport cu moneda utilizată.
Fig. 2.5.4.1 Dimensiunile bateriei utilizate raportate la diametrul unei monede de 50 bani
2.5.5 TrackBall-ul – dispozitiv periferic de control al dispozitivului
În cazul interfeței de control dintre utilizator și dispozitiv s-a luat decizia utilizării unui joystick de tip TrackBall cu funcția de interpretare a unei comenzi ce poate lua forma unui cerc, nefiind astfel limitat de un set limitat de direcții, ci având o plajă disponibilă de direcții cu un unghi total de 360°. Astfel, acest periferic ne este de ajutor mai ales în cazul utilizării programului de desenare, în care realizarea unui cerc nu ne este constrânsa de libertatea de mișcare a acestuia.
TrackBall-ul funcționează pe baza a patru senzori cu efect Hall, ce au o sensibilitate crescută și măsoară efectul magnetic produs de mișcarea de rotație a patru axe ce au un strat magnetic depus pe acestea, acest strat fiind situat în extremitatea ce se situează deasupra senzorilor. Aceste axe sunt antrenate la rândul lor de mișcarea de rotație a bilei ce prin intermediul unei forțe de frecare obținut prin apăsarea acesteia pe axe angrenează întreg ansamblul. Acest dispozitiv se poate observa atât din punct de vedere al ansamblului ce îl formează cât și a dimensiunilor efective ale acestuia în figura 2.5.5.1, fiind vizibili și pinii de conectare ai acestuia la microcontroler
De asemenea, prin apăsarea cu un ordin de mărime mai ridicat a bilei, aceasta intră în contact cu un buton aflat sub ea, activând un circuit suplimentar față de cel de direcționare a cursorului pe ecran și beneficiind astfel de funcția de click necesară în operarea dispozitivului.
Senzorii cu efect Hall produc și transmit către microcontroler un set de tranziții digitale de tip high-low ce sunt interpretate de acesta și conduc la mișcarea cursorului pe ecran cu o poziție diferență în direcția mișcării realizate față de poziția curentă, iar printr-o mișcare de rotație completă a bilei într-o singură direcție duce la realizarea a 9 tranziții, ceea ce înseamnă că o rotație completă a bilei va duce la mișcarea cursorului pe ecran cu o diferență de aproximativ 9 poziții față de poziția inițială.
Caracteristicile acestui periferic de intrare cât și a componentelor ce au dus la realizarea acestuia sunt ilustrate în tabelul 2.5.5.1 de mai jos:
Tabel 2.5.5.1 Parametrii de funcționare al senzorilor cu efect Hall
Acest echipament periferic beneficiază de un set de 4 LED-uri cu următoarele culori: albastru, roșu, verde și în cele din urmă lumină albă. Acestea se pot aprinde individual prin conectarea acestora la circuitul de alimentare Vcc, dar se pot aprinde și în combinație, rezultând o culoare compusă. Pentru acest dispozitiv s-a ales ca bila echipamentului să se aprindă în lumină albă.
Fig. 2.5.5.1 Echipamentul periferic de intrare numit TrackBall-dimensiuni efective
2.5.6 Senzorul de temperatură
Motivul denumirii acestui ceas ca fiind multisenzorial este utilizarea unor senzori prin intermediul cărora utilizatorul poate monitoriza anumiți parametrii ambientali.
Unul dintre acești senzori este cel de măsurare a temperaturii realizat de compania Dallas Semiconductors, companie achiziționată de Maxim Integrated ce deține și drepturile de autor asupra tehnologiei de comunicație denumită OneWireBUS.
Acest senzor este cu ieșire digitală și are o rezoluție cuprinsă într-un interval de 9-12 biți a temperaturii citite de acesta și transmisă către microcontroler. Valorile de temperatură citite de acesta sunt cuprinse într-un interval de la -55°C până la +125°C, iar aceasta poate fi afișată atât pe scala în grade Celsius cât și cea în grade Fahrenheit utilizată în standardul US.
Principalul avantaj al acestui senzor, criteriu decizional în alegerea acestuia, a fost numărul de conexiuni minim necesare pentru utilizarea acestuia, acest fapt fiind realizabil un minim de două conexiuni față de patru în cazul utilizării unei comunicații seriale obișnuite, în acest caz utilizând o cale de mijloc prin intermediul a trei conexiuni. Este posibilă funcționarea acestui senzor prin intermediul a două conexiuni deoarece consumul de energie al acestuia este foarte scăzut, reușind să se alimenteze doar pe baza tensiunii reziduale obținute din transferul de informație realizat între senzor și microcontroler. Cu toate acestea s-a luat decizia utilizării tuturor celor 3 pini disponibili, pentru alimentarea corespunzătoare a acestuia. Configurația pinilor este disponibilă în figura 2.5.6.1. În conectarea acestuia la microcontroler s-a ținut cont de necesitatea conectării unui rezistor de tip Pull-up cu valoarea de 1kΩ între pinul de alimentare a senzorului – VDD și pinul prin intermediul căruia se realizează transferul de date – DQ pentru obținerea unei căderi de tensiune necesară funcționării acestuia.
Fig. 2.5.6.1 Rolul pinilor de conexiune ai senzorului de temperatură
Fiecare senzor realizat de această companie deține o serie unică de identificare ce permite identificarea a unui număr multiplu de senzori și separarea informațiilor transmise de fiecare senzor pe magistrala de date, fiind posibilă interogarea și afișarea unor multitudini de informații în mod separat în cazul utilizării unei matrice de senzori poziționați în diferite puncte cheie de măsurare a temperaturii.
Fig. 2.5.6.2 Forma de încapsulare a senzorului împreună cu dimensiunile acestuia
De asemenea, acest senzor beneficiază de o memorie nevolatilă ce poate fi modificată de utilizator pentru declanșarea unor alarme în cazul depășirii unor praguri de temperatură definite de acesta. În cazul prezentat a fost utilizată această funcție în care se pot declanșa două astfel de alarme, una în cazul în care temperatura citită de acesta scade sub valoarea de 10°C, eveniment marcat pe ecran cu apariția în partea inferioară a acestuia a unui dreptunghi de culoare albastră, iar cea de-a doua alarmă fiind activată în momentul depășirii valorii de 60°C, moment în care va fi vizibil pe ecran același dreptunghi, însă de culoare roșie de această dată. În cele din urmă sunt prezentate caracteristicile descrise de compania producătoare în foaia de catalog a acestuia prin intermediul tabelului 2.5.6.1.
Tabelul 2.5.6.1 – Caracteristici de funcționare a senzorului de temperatură
2.5.7 Senzorul de proximitate
Cel de-al doilea senzor utilizat în realizarea acestui ceas a fost senzorul de proximitate cu ajutorul căruia se poate măsura distanța de la ceas la primul obiect aflat în fața acestuia. Principiul de funcționare al acestui senzor este reprezentat în figura 2.5.7.1.
Fig. 2.5.7.1 Principiul de funcționare al senzorului ultrasonic utilizat pentru măsurarea distanței
Acest senzor funcționează pe baza unor pulsații de semnale acustice din gama ultrasunetelor cu frecvența de 42KHz transmise de acesta. În momentul în care aceste pulsații lovesc un obiect ce se află în calea lor se formează un ecou ce este perceput înapoi de senzor.
Distanța maximă ce poate fi măsurată de acest model de senzor este de 6,45m. Senzorul poate interpreta și transmite informația către microcontroler având o frecvență de eșantionare de 20Hz, iar informația poate fi interpretată utilizând multiple interfețe de comunicație: serială RS-232, analogică și PWM.
În acest proiect a fost utilizată ieșirea PWM a senzorului și s-a ținut cont de faptul că durata în care unda acustică parcurge 1cm este de 57,874 µs, astfel obținând valoarea distanței parcurse de undă, adică distanța măsurată de senzor.
Se poate observa forma și dimensiunile acestui senzor alături de pinii de conexiune ai acestuia către sistemul interogator în figura 2.5.7.2 de mai jos:
a) b)
Fig. 2.5.7.2 Senzorul de proximitate
a) Ansamblul componentelor pe PCB b) Pini de conectare
Avantajele utilizării acestui model de senzor sunt următoarele:
Obținerea unor măsurători precise cu un procent scăzut de citire a unor valori eronate;
Consum redus de energie, aspect important pentru fezabilitatea acestui proiect;
Viteză de măsurare ridicată, fiind capabil să realizeze măsurători continue dar și la intervale scurte de timp, până la 50 ms;
Interval generos de tensiuni de alimentare;
Are programată o funcție de autocalibrare la inițierea acestuia;
Principalele caracteristici prezentate de către fabricant în foaia de catalog referitoare la acest senzor sunt prezentate în tabelul 2.5.7.1 de mai jos:
Tabel 2.5.7.1 Parametrii de funcționare ai senzorului de proximitate
2.5.8 Modulul de încărcare
Ținând cont de faptul că pentru realizarea acestui acestui ceas a fost utilizată o baterie litiu-polimer a fost necesară utilizarea unui încărcător dedicat acestui tip de baterie, care să nu depăsească nivelul de tensiune maxim admis de baterie.
Astfel, s-a ales un circuit de încărcare cu dimensiuni constructive cât mai mici pentru a nu mări dimensiunile generale ale dispozitivului final.
Modulul de încărcare este realizat prin asamblarea pe un PCB a unui circuit integrat ce realizează această funcție, a unui LED de culoare roșie ce semnalează statusul de încărcare a bateriei și a unor elemente pasive de circuit impuse de fabricant pentru funcționarea circuitului integrat.
Se poate observa din schema electrică atașată în figura 2.5.8.1 că acest circuit poate alimenta și microcontrolerul cu o tensiune de 3,7V. De asemenea, PCB-ul asamblat împreună cu dimensiunile acestuia sunt vizibile în figura 2.5.8.2 de mai jos. Interfața de conectare ce se va folosi de către utilizator pentru încărcarea efectivă se va realiza prin intermediul unui cablu de date ce are conector microUSB.
Fig. 2.5.8.1 Schema electrică a sistemului de încărcare
Fig. 2.5.8.2 Modulul de încărcare – PCB asamblat împreună cu dimensiunile acestuia
Circuitul integrat ce formează acest modul de încărcare este configurabil pentru a putea avea un curent de încărcare ce poate avea valori între 15mA – 500mA, în cazul acestui model fiind setat la 500mA. De asemenea, circuitul beneficiază de un sistem de oprire automată a încărcării în momentul în care acumulatorul a atins pragul de tensiune necesar pentru a nu deteriora acumulatorul, iar activarea acestuia se realizează la realimentarea acestuia. Acești parametrii sunt vizibili în tabelul 2.5.8.1 de mai jos:
Tabel 2.5.8.1 Caracteristicile de funcționare a circuitului de încărcare
2.5.9 Programatorul cu interfață serială FTDI
Ultima componentă necesară realizării acestui prototip a fost programatorul cu interfață serială ce a fost utilizat atât la programarea microcontrolerului, cât și la setarea display-ului OLED drept componentă serial slave. Particularitatea acestui programator a fost tensiunea de ieșire, setată la 3,3V, aspect foarte important de care s-a ținut cont în programarea microcontrolerului, acesta necesitând o tensiune de alimentare stabilă, de valoare fixă pentru o programare corespunzătoare a acestuia. În cazul ecranului OLED, această tensiune nu a fost importantă atâta timp cât era inclusă în intervalul tensiunilor de alimentare suportate de acesta.
Programatorul este realizat dintr-un ansamblu format din circuit integrat FTDI-FT232RL, conector cu 6 pini pentru comunicația cu microcontrolerul, LED-uri de status ce funcționează în momentul în care se execută un transfer de date, componente de circuit pasive necesare funcționării integratului și conector miniUSB pentru comunicația cu sistemul de calcul utilizat pentru scrierea codului sursă.
Acest circuit integrat beneficiază de următoarele caracteristici:
Buffere de transmisiune de tip FIFO necesare în scrierea la viteze mari pe microcontroler;
Circuit de reset integrat, folositor pentru resetarea microcontrolerului după scrierea acestuia;
Consum redus de energie;
Memorie de tip EEPROM cu dimensiunea de 1024 biți;
Circuit de filtrare a curentului destinat alimentării microcontrolerului;
Sistem de generare a semnalului de clock fără necesitatea utilizării unui rezonator extern;
Ansamblul format de acest circuit alături de celelalte componente pe PCB, dar și dimensiunile PCB-ului se pot observa în figura 2.5.9.1 de mai jos:
Fig. 2.5.9.1 Programatorul cu circuitul integrat FTDI-FT232RL
– dimensiuni ansamblu general
Această componentă este singura din cele precizate anterior ce nu se va monta în interiorul carcasei dispozitivului, fiind necesară doar pentru programarea dispozitivelor componente. Exista posibilitatea integrării acestui programator în carcasă pentru eventualitatea reprogramării microcontrolerului cu un cod sursă modificat însă acest model de microcontroler nu suportă două conexiune seriale concomitente, această conexiune fiind deja utilizată pentru conexiunea cu ecranul OLED.
Se putea realiza un comutator ce ar fi anulat și comutat această conexiune de la ecran la programator și invers dar datorită spațiului restrâns s-a luat decizia excluderii programatorului din carcasă până la momentul implementării unei soluții mult mai eficiente din punct de vedere al spațiului ocupat de ansamblul electronic. Acest concept este posibil prin realizarea unui PCB ce ar conține toate elementele prezentate anterior, ceea ce ar duce la realizarea unui produs cu dimensiuni cu mult sub cele ale prototipului actual, o durată extinsă a bateriei și eventualitatea utilizării unei game variate de senzori interschimbabili în funcție de necesitatea utilizatorului.
Capitolul 3
Realizarea și testarea prototipului
În acest capitol se va pune accent pe realizarea practică a prototipului, prezentând etapele realizării acestuia, componentele utilizate alături de caracteristicile constructive ale acestora, dar și tehnica utilizată pentru realizarea finală a dispozitivului.
Prototipul a fost realizat prin îmbinarea sistemului hardware împreună cu cel software. Astfel, partea hardware a presupus realizarea unei carcase și popularea acesteia cu componentele hardware ce au fost conectate între ele în prealabil. Componenta software s-a realizat cu ajutorul mediului de dezolvtare Arduino IDE, după care a fost scrisă pe microcontrolerul dispozitivului cu ajutorul programatorului FTDI.
3.1 Carcasa prototipului
Asamblarea efectivă a ceasului multisenzorial a avut ca prim pas proiectarea și asamblarea carcasei. Schița acesteia a fost realizată folosind suita de aplicații Dassault Systems – SolidWorks, versiunea academică. În realizarea carcasei s-a ținut cont de faptul că blocul electronic ce va fi introdus în carcasă este asamblat într-o formă ce necesită un spațiu de desfășurare mai mare deoarece componetele vor fi interconectate prin intermediul unor fire de legătură.
Pe baza proiectării 3D a ansamblului a fost realizată schița componentelor ce vor forma carcasa. Primul pas executat pentru dimensionarea carcasei a fost realizarea ansamblului electronic, urmând ca pe baza dimensiunilor acestuia să se realizeze carcasa, prin introducerea unui set de toleranțe în dimensiunile finale ale carcasei.
Astfel, a fost realizată o reprezentare 3D a carcasei, aceasta observându-se în figura 3.1 de mai jos. De asemenea, se pot observa în aceeași figură și dimensiunile constructive de care s-a ținut cont în realizarea efectivă a acesteia.
Fig. 3.1.1 Modelarea 3D a carcasei – schiță formată din componetele și dimensiunile lor
Se va face mențiunea că nu toate componentele electronice utilizate vor fi introduse în carcasă, o parte din acestea urmând a fi montate pe cureaua ceasului. Această curea este realizată din material textil rezistent, ce prezintă o lungime suficientă pentru cuprinderea diverselor dimensiuni ale încheieturii mâinii și este realizată din doua sub-componente.
Aceste două secțiuni sunt de lungimi diferite, prima secțiune având atașată acesteia controlerul de tip TrackBall, iar cea de-a doua integrând cei doi senzori menționați în capitolul anterior.
În mod asemănător cu primul caz, schița acestei curele a fost realizată în același program de proiectare 3D, fiind prezentate zonele de atașare a echipamentului periferic de control, respectiv a senzorilor.
Schița acestor două componente cu dimensiunile acestora este menționată în figura 3.2, alături de modificările ce se vor realiza pentru înglobarea componentelor electronice discutate anterior.
Fig. 3.1.2 Reprezentarea detaliilor constructive ale curelei ceasului
Carcasa a fost asamblată prin utilizarea unui adeziv transparent, iar cureaua a fost perforată pentru atașarea componetelor de aceasta. De asemenea, legătura dintre carcasă și curea s-a realizat prin utilizarea unor axe subțiri realizate din două segmente metalice cu profil cilindric, ce au lungimea de 32 mm și diametrul de 1 mm. Această conexiune s-a realizat în partea superioară a carcasei pentru mascarea firelor de legătură dintre senzori, respectiv interfață de control și restul ansamblului electronic. Pentru o mai bună protecție a componentelor atașate de curea s-a luat decizia realizării unei dubluri cu același material care să înconjoare elementele atașate de aceasta, astfel elementele nefiind supuse pericolului de scurt-circuitare electrică și oferind în același timp o rezistență mecanică îmbunătățită acestora. Montarea echipamentul pe încheietura utilizatorului este realizată prin intermediul unui sistem de prindere velcro ce fixează cele două segmente de curea între ele fără a mai fi nevoie de utilizarea unui sistem de prindere cu cataramă.
3.2 Programarea finală a dispozitivului
După cum s-a menționat anterior, componenta software a fost realizată în mediul de dezvoltare Arduino IDE, iar testarea acesteia s-a realizat prin scrierea codului sursă rezultat pe microcontroler. Trebuie precizat faptul că toate testele au fost realizate în faza experimentală cu ajutorului unui breadboard, conectându-se la acesta toate componentele electronice după cum este ilustratrat în figura 2.4.2. De asemenea, trebuie reamintit faptul că nu este posibilă conectarea concomitentă a programatorului, respectiv a ecranului OLED la microcontroler deoarece acesta este limitat din punct de vedere constructiv la o singură sesiune de comunicare serială. În acest caz a fost necesară conectarea pe rând a programatorului, scrierea codului, apoi deconectarea programatorului urmată în cele din urmă de conectarea display-ului pentru verificarea funcționalității programului.
Mediul de dezvoltare Arduini IDE este un pachet software creat folosind limbajele de programare C, C++ și Java, iar compunerea codului sursă în program se realizează utilizând limbajele de programare C și C++. Acest program a fost dezvoltat cu scopul de a se putea facilita de un sistem dedicat de realizare și implementare a unui cod sursă ce se dorește a fi rulat pe o placă de dezvoltare Arduino.
Microcontrolerele montate pe aceste plăci de dezvoltare au scrise în memoria flash un bootloader ce le permite conectarea la un sistem de calcul și șcrierea mai ușoară a codului sursă pe acestea față de alte medii de dezvoltare. Interfața programului este intuitivă, iar codul sursă scris în acest program beneficiază de verificarea corectitudinii din punct de vedere sintactic în timp ce acesta este scris de programator. De asemenea, programul beneficiază de monitorizare serială ceea ce permite celui ce experimentează să primească feedback asupra unor comenzi trimise către microcontroler prin intermediul aceleiași conexiuni seriale de scriere a codului sursă.
Interfața programului este prezentată în figura 3.2.1 de mai jos. Astfel, se vor descrie aceste butoane de la stânga la dreapta în ordinea apariției acestora. Primul buton, Verify, este pentru verificarea codului sursă pentru eventuale erori apărute în realizarea acestuia. Următorul buton, de Upload, este utilizat pentru realizarea următorului set de acțiuni: verificarea corectitudinii codului sursă urmat de încărcarea acestuia pe microcontroler în cazul în care codul nu are erori de sintaxă. Al treilea buton, New, este utilizat pentru creearea unui nou fișier de scriere a codului, acest fișier având denumirea de sketch. Al patrulea buton este utilizat pentru deschiderea unui fișier salvat anterior de programator. Penultimul buton este dedicat salvării unui sketch creat de programator, iar ultimul buton este pentru inițierea monitorizării seriale. În cazul primei utilizări al acestui program se va seta portul serial de comunicație dintre sistemul de calcul și microcontoler, iar din meniul Tools, submeniul Board se va seta modelul de Arduino utilizat, în cazul nostru alegând Arduino Pro Mini 3,3V, 8MHz ATmega328. Această procedură se poate observa în figura 3.2.2.
Fig. 3.2.1 Butoanele funcționale din Arduino IDE
Pentru realizarea codului sursă au fost utilizate librăriile publicate de producătorul fiecărui modul în parte destinate acestui mediu de dezvoltare, fapt ce se aplică doar modulelor ce facilitează de comunicare serială cu microcontrolerul. Aceste librării sunt utilizate pentru comunicația cu ecranul OLED, senzorul de temperatură, senzorul de proximitate și cu modulul de RTC. Aceste librării conțin toate instrucțiunile posibile ce se pot implementa în codul sursă pentru modulele respective și ajută la conversia acestora dintr-un limbaj ce este ușor de înteles de către programator într-un limbaj mașină ce este interpretat doar de componenta pentru care a fost realizată librăria. Codul sursă este prezentat în anexa acestei lucrări, împreună cu explicarea funcționalității acestuia pentru fiecare bloc funcțional în parte.
Fig. 3.3.2 Selecția plăcii de dezvoltare în mediul Arduino IDE
3.3 Poziționarea componentelor în carcasă
Realizarea unui dispozitiv care să ocupe un spațiu cât mai mic și în același timp să deservească funcțiile pentru care a fost proiectat s-a dovedit a fi destul de dificilă deoarece a fost nevoie de asamblarea parțială a acestuia, introducerea acestei secțiuni în carcasă urmată de conectarea celorlalte periferice ce au ca puncte de prinedere cureaua ceasului.
Astfel, componentele ce au ca locație de integrare carcasa ceasului au fost așezate pe baza unei scheme de poziționare a acestora, ilustrată în figura 3.3.1 de mai jos. Ecranul OLED este descris prin fundalul albastru, prezentând restul modulelor ca fiind poziționate peste ecran, acoperind pe acesta.
Fig. 3.3.1 Poziționarea modulelor în interiorul carcasei ceasului
În cazul curelei ceasului, poziționarea elementelor rămase s-a realizat după specificațiile ce se pot observa în figura 3.3.2. Se va face precizarea că perifericul de control este situat pe segmentul de curea ce este îndreaptat către utilizator, iar pe celălalt segment sunt poziționați senzorii de temperatură și proximitate.
Fig. 3.3.2 Poziționarea modulelor pe cureaua ceasului
3.4 Testarea funcționalității dispozitivului
Următoarea etapă ce se va dezbate în acest capitol este testarea funcționalității dispozitivului. Testele urmăresc verificarea corectitudinii informației furnizate de dispozitiv, comparativ cu alte metode de obținere a acestor informații, precum și analiza referitoare la autonomia bateriei în situații de utilizare normală a dispozitivului, dar și timpii de încărcare a acestuia.
3.4.1 Verificarea responsivității TrackBall-ului
Primul test din această serie este cel verificare a responsivității perifericului de intrare numit TrackBall. Acest test s-a realizat prin executarea unor serii de mișcări aplicate echipamentului periferic cu scopul de a urmări distanța parcursă de cursor pe ecran și de comparare a acestor distanțe obținute între ele.
În urma efectuării acestui test s-au obținut următoarele rezultate, ce pot fi observate și în figura 3.4.1.1.
Fig. 3.4.1.1 Captură ecran – Test de responsivitate a perifericului de intrare TrackBall
3.4.2 Testarea preciziei de măsurare a senzorului de temperatură
Următorul experiment realizat a fost cel de comparare a valorilor de temperatură obținute și afișate pe ecranul ceasului cu valorile obținute prin supunerea unui alt senzor de temperatură, dedicat, cu un nivel de precizie ridicat, garantat de producătorul dispozitivului de măsurare.
Testul a fost realizat prin supunerea în paralel a celor două dispozitive la diverse valori de temperatură ambientală și compararea rezultatelor obținute. Rezultatele acestui test au fost menționate în graficul ilustrat în figura 3.4.2.1. Se poate observa că valorile obținute sunt apropiate cu o diferență maximă dintre aceste două dispozitive de X grade Celsius.
Fig. 3.4.2.1 Grafic reprezentând valorile obținute de senzorii de temperatură
3.4.3 Testarea preciziei de măsurare a senzorului de proximitate
Al treilea test prezentat în acest capitol este cel de verificare a corectitudinii măsurătorilor realizate prin intermediul senzorului de proximitate, comparând valorile obținute cu alte măsurători realizate cu ajutorul unui dispozitiv profesional de măsurare a distanței prin ultrasunete. Aceste valori sunt prezentate în graficul realizat în figura 3.4.3.1 și se poate observa că avem un nivel de diferență dintre aceste două echipamente de XX cm.
Fig. 3.4.3.1 Grafic reprezentând valorile obținute de senzorii de proximitate
3.4.4 Determinarea autonomiei de funcționare a dispozitivului
Ținând cont de faptul că în realizarea acestui prototip s-a utilizat un acumulator cu dimensiuni cât mai mici și prin urmare o capacitate de stocare relativ mică s-a pus problema numărului de ore de funcționare disponibile dintr-o singură încărcare a dispozitivului. Astfel, s-au realizat un număr de trei teste pentru determinarea acestei autonomii în următoarele situații:
dispozitiv în stare activă de funcționare maximizând utilizarea funcției de utilizare economică a dispozitivului;
dispozitiv în stare activă de funcționare în care s-a trecut la pornirea ecranului din starea de stand-by la un interval de 30 minute pentru o perioadă de 1 minut urmat de oprirea ecranului;
dispozitiv în stare activă de funcționare în care ecranul a fost pornit fără întrerupere.
Rezultatele testelor au fost ilustrate în tabelul 3.4.4.1 de mai jos cu mențiunea că toate cele trei teste au fost realizate pornind de la o tensiune de referință de 4,2V, tensiune menționată în acest caz drept procentaj 100% de încărcare a acumulatorului, până la atingerea unei tensiuni limită de 3,5V, considerată procentaj 0% de încărcare. Se poate preciza faptul că nu s-au realizat măsurători sub nivelul de 3,5V, deoarece regulatorul de tensiune integrat în placa de dezvoltare nu mai poate asigura o tensiune de 3,3V necesară alimentării microcontrolerului și a ecranului OLED, acest regulator intrând sub tensiunea critică de alimentare sub acest prag.
Tabel 3.4.4.1 Autonomia de funcționare a ceasului multisenzorial
Capitolul 4
Prezentarea prototipului
Ceasul multisenzorial deține, pe lângă funcțiile obișnuite ale unui ceas, opțiunea utilizării unor aplicații recreative de genul unui joc și a unui program de desenat. De asemenea, există o aplicație ce permite citirii temperaturii ambientale și de măsurare a distanței de la ceas la un obiect din planul îndepărtat.
POZA CEAS
De asemenea, ora și data, sunt afișate în mai multe moduri și anume: ceas în format digital, în format analogic și în format binar folosind un set de buline colorate pentru reprezentarea valorilor pe ecranul OLED.
În următoarele rânduri sunt prezentate modurile de reprezentare a noțiunii de timp menținută de acest ceas.
4.1.1 Reprezentarea orei exacte în format digital
Formatul digital al orei exacte este primul ecran pe care dispozitivul îl afișează. S-a folosit un font de dimensiuni reduse, de culoare verde, iar informațiile folosite sunt reprezentate pe două linii, prima reprezentând ora în formatul HH:MM:SS, iar cea de-a doua linie reprezentând data în formatul DD.MM.YYYY. Această metodă de afișare se poate observa în figura 4.1.1.1.
Fig. 4.1.1.1 Captură ecran – Ceas în format digital
4.1.2 Reprezentarea orei exacte în format binar
Cel de-al doilea ecran este reprezentat de formatul binar în figura 4.1.2.1, pe care îl putem observa prin apăsarea butonului integrat în TrackBall. Acesta este reprezentat prin apariția unor buline de diferite culori așezate pe 6 coloane, bulinele fiind de două tipuri, hașurate și nehașurate, fiecare coloană reprezentând pe rând anul, luna, ziua, ora, minutul și în cele din urmă secunda curentă. Bulinele hașurate reprezintă o un număr ce se va aduna pentru obținerea valorii finale, adică valoarea minutelor de exemplu. Anul este reprezentat prin afișarea diferenței dintre anul curent și anul de referință fixat la valoarea 2000. Prima coloană de la dreapta la stânga reprezintă secundele si este formata din 6 buline ce reprezintă puterile lui 2 de la 0 la 5. A doua coloană reprezintă minutele și este formată din același număr de buline. A treia coloană este formată doar din 5 buline și reprezintă orele. Următorul set de 3 coloane reprezintă ziua, luna și anul curent. Citirea acestei reprezentări se face prin adunarea bulinelor pline, poziția bulinei în coloană precizând astfel puterea lui 2 care se va aduna pentru a forma suma finală. Puterile lui 2 cresc în coloană de jos în sus.
Fig. 4.1.2.1 Captură ecran – Ceas în format binar
4.1.3 Reprezentarea orei exacte în format analogic
Cel de-al treilea ecran ce apare prin apăsarea TrackBall-ului este reprezentat de afișarea orei exacte prin intermediul unui ceas in format analogic. Această metodă de afișaj cuprinde toate cele 3 tipuri de reprezentare și anume: ora, minutul și secunda.
Fig. 4.1.3.1 Captură ecran – Ceas în format analogic
4.1.4 Meniul principal
După vizualizarea acestor variante de reprezentare a orei exacte, prin apăsarea butonului de TrackBall vom accesa meniul ceasului ce dispune de 6 opțiuni suplimentare. Aceste meniuri sunt aranjate sub forma a 2 coloane cu 3 rânduri.
4.1.4.1 Captură ecran – Meniul principal
4.1.5 Jocul
Mai departe vom prezenta denumirea și rolul acestor meniuri începând cu primul din partea stângă sus, aplicația de recreere. Jocul pe care acest dispozitiv îl are disponibil este de tipul unei platforme ce lansează o bilă către un perete de cărămizi. Utilizatorul trebuie să strângă cât mai multe puncte prin lovirea cărămizilor și să nu piardă bila sub nivelul platformei. Sunt disponibile un număr de 3 vieți începând cu prima rundă, acestea scăzând la fiecare pierdere a bilei. Există blocuri ce necesită lovirea multiplă a acestora pentru a le putea sparge. Prin eliminarea tuturor cărămizilor se va trece la următorul nivel al jocului. Se poate observa acest joc, precum și mesajul pe care utilizatorul îl primește în momentul pierderii tuturor celor trei vieți primite inițial.
Fig. 4.1.5.1 Captură ecran – Jocul a) formă de prezentare b) joc pierdut
4.1.6 Programul de desenare
Cel de-al doilea meniu de la stânga la dreapta este cel de Paint. Acest program poate fi folosit pentru a crea și salva desenele create de utilizator. Programul dispune un set de culori pe 16 biți. In partea de jos a programului se pot observa de la stânga la dreapta următoarele opțiuni: încărcarea salvării, salvarea ecranului, alegerea culorii de desen, golirea ecranului si ieșirea din aplicație. POZA ECRAN
4.1.7 Programul de măsurare a temperaturii
Pe al doilea rând de meniuri avem cel de-al treilea meniu, Temperatura. Cu ajutorul acestei aplicații putem citi informații despre temperatura ambientală furnizată de senzorul de temperatură atașat ceasului. Programul este scris astfel încât poate citi valorile furnizate de un număr de până la 3 senzori. În cazul în care temperatura citită de senzor scade sub 10 grade Celsius, pe ecran va apărea un dreptunghi albastru, iar în cazul în care temperatura crește peste 60 grade Celsius va apare pe ecran un dreptunghi de culoare verde. POZA ECRAN
4.1.8 Program de măsurare a distanței
Următorul meniu este cel de măsurare prin sonarul atașat dispozitivului, prin intermediul căruia se poate măsura distanța de la ceas la un obiect sau perete aflat în fața senzorului de proximitate. Afișarea valorilor se face atât in centimetri cât și în inchi. Acestui modul îi poate fi adaptat un buzer care să genereze un semnal sonor ce își modifică frecvența semnalului generat odată cu modificarea distanței citită de acesta. POZA ECRAN
4.1.9 Setarea orei exacte
Penultimul meniu pe care îl avem în partea dreaptă a ultimului rând din tabelul de meniuri este cel care ajută utilizatorul să seteze ora și data ceasului. Setarea secundelor a fost dezactivată in această formă de prezentare, dar poate fi activată prin modificarea codului sursă a programului. În rest, toți ceilalți parametri se pot modifica prin poziționarea cursorului sub aceștia (stânga-dreapta), iar apoi se pot modifica prin mișcări de tip sus-jos ale controlerului.
Fig. 4.1.9.1 Setarea orei și datei ceasului
4.1.10 Modul de utilizare economică a ceasului
În cele din urmă, s-a introdus în ultimul meniu, o funcție ce permite economisirea energiei prin stingerea ecranului, acesta fiind ușor de pornit, revenind în forma inițială prin apăsarea butonului de pe TrackBall.
Această funcție permite utilizarea unui nivel redus de energie, păstrând activă funcția de menținere a orei exacte. Pentru a nu exista probleme cu păstrarea unei ore exacte, dispozitivul se folosește de un circuit integrat ce are ca scop menținerea unei ore exacte chiar și în cazul în care este deschis circuitul de alimentare a microcontrolerului, integratul beneficiind de o baterie de backup, destinată doar funcționării acestui integrat. Funcția se activează prin deplasarea cursorului în partea de jos a ecranului, selectând astfel meniul Ecran OFF ce se poate observa în figura 4.1.4.1.
4.2 Încărcarea dispozitivului
Dispozitivul facilitează de un modul de încărcare a acumulatorului, ambele fiind încorporate în dispozitiv. Încărcarea efectivă a acumulatorului se realizează prin conectarea ceasului la o sursă externă de energie prin intermediul unui cablu având conector microUSB spre ceas, respectiv USB spre sursa externă de energie.
Modulul de încărcare facilitează de un sistem de semnalizare a stării de funcționare folosind un LED de culoare roșie ce se aprinde în momentul inițierii procesului de încărcare, acesta fiind aprins constant pe toată durata încărcării, iar în momentul în care sistemul sesizează ca bateria ceasului este încărcată acesta decuplează tensiunea de încărcare și stinge LED-ul de culoare roșie, informând astfel utilizatorul că procesul de încărcare a luat sfârșit. Procedura este prezentată în figura 4.2.1 de mai jos.
Fig. 4.2.1 Încărcarea acumulatorului încorporat în ceas
4.3 Recomandări în utilizarea ecranelor OLED
În urma numeroaselor teste realizate de producătorii de ecrane OLED și a experienței căpătate de utilizatorii dispozitivelor ce facilitează utilizarea unui astfel de ecran s-a descoperit că nu este recomandată utilizarea ecranelor în general, dar mai ales a celor de tip OLED, pentru afișarea unor imagini pe durate lungi de timp deoarece acest proces de expunere îndelungată afectează ecranul într-un mod iremediabil. Fenomenul astfel prezentat mai devreme poartă numele de burn-in și are ca efect defectarea pixelilor componenți ecranului prin blocarea acestora într-o formă ce se poate observa în momentul schimbării imaginii afișate pe respectivul ecran, iar în unele cazuri chiar și după oprirea alimentării acestuia cu energie electrică.
Din acest motiv, ținând cont de faptul că prezentul proiect utilizează un ecran de tip PMOLED, se recomandă utilizarea dispozitivului fără expunerea prelungită a acestuia la imagini statice, ba chiar se recomandă implementarea funcției de utilizare economică pentru stingerea ecranului pe durata neutilizării acestuia, fiind facilă activarea ecranului în momentul în care utilizatorul dorește să citească ora exactă menținută de dispozitiv. Este lesne de înțeles că utilizarea ecranului pe durata executării jocului sau a aplicației de desenare nu va dăuna ecranului din moment ce imaginile prezintă un nivel de animație ridicat față de alte aplicații disponibile. De asemenea, prin aplicarea funcției menționată anterior, utilizatorul beneficiază de o perioadă prelungită de autonomie de funcționare a acestuia, detaliată anterior prin ultimul test.
Se poate observa în figura 4.3.1 de mai jos, una din urmările defectării unui astfel de ecran, imagine furnizată de un producător de afișaje ce a realizat un astfel de test.
Fig. 4.3.1 Ecran deteriorat din cauza expunerii prelungite a ecranului la imagini statice
Concluzii
În această lucrare au fost prezentate etapele realizării unui ceas electronic ce a avut la bază un microcontroler Atmel Atmega328, alături de un ecran OLED și un modul RTC. De asemenea, pentru realizarea unui proiect mai complex, s-a luat decizia atașării acestuia a doi senzori și a unui periferic de intrare de tip TrackBall, ce va facilita controlul asupra dispozitivului.
Principalul sistem de dezvoltare utilizat pentru realizarea proiectului a fost Arduino IDE, alături și de alte componente software utilizate pentru realizarea design-ului 3D al carcasei și realizarea schemelor electrice și experimentale.
În urma realizării acestui proiect au reieșit următoarele concluzii bazate pe propria contribuție:
Primul pas a fost crearea unei scheme bloc pe baza căreia s-a dezvoltat ideea realizării acestui proiect. Următorul pas a fost dimensionarea fizică a dispozitivului și astfel s-au ales componentele ce vor fi utilizate, cu scopul de a ocupa un volum total cât mai mic posibil, realizând în cele din urmă o listă de materiale ce include atât componentele electronice cât și cele pe baza cărora s-a realizat ansamblul fizic al ceasului format din carcasă și curea;
Pe baza componentelor electronice enumerate în lista de materiale s-a realizat o schemă electrică a întregului bloc electronic, iar componentele au fost montate în formă experimentală prin utilizarea unui breadboard, pe baza unei scheme de această natură, schema experimentală fiind un aspect ce s-a tratat separat față de cea electrică;
După testarea funcționaliții acestui ansamblu s-a început scrierea unui cod sursă pentru microcontroler, urmată de încărcarea acestuia folosind Arduino IDE. De asemenea, a fost reprogramat și ecranul OLED pentru a activa funcția de comunicație serială cu microcontrolerul;
Pentru a se putea utiliza acest ansamblu electronic s-a schițat in pachetul software SolidWorks o carcasă și curea cu scopul de înglobare a componentelor electronice în acestea. În acest sens a fost realizată o diagramă de așezare a componentelor în carcasă și pe curea.
Finalitatea realizării efective a dispozitivului s-a menționat prin realizarea unor teste de performanță referitoare la precizia de măsurare a senzorilor, a perifericului de control, precum și a autonomiei de funcționare a prototipului;
Ultima etapă descrisă în acest proiect a fost realizarea unui manual de utilizare a dispozitivului, prin descrierea funcțiilor disponibile. De asemenea, s-a prezentat o procedură de încărcare a acumulatorului dispozitivului alături de o serie de recomandări și contraindicații referitoare la utilizarea ceasului pentru o durată de viață cât mai de durată a acestuia.
Recomandările pentru o versiune îmbunătățită ale acestui prototip ar fi următoarele:
Realizarea unei carcase ce s-a proiectat în format 3D cu scopul de printare a acesteia utilizând o imprimantă 3D;
Modificarea schemei electrice prin înglobarea unui circuit care să permită utilizarea conectorului microUSB atât pentru încarcarea acumulatorului cât și pentru realizarea transferului de date cu scopul de reprogramare a ceasului;
Proiectarea, printarea și asamblarea unui PCB cu scopul de îngloba toate componentele utilizate în realizarea acestui prototip pe un singur modul care să se instaleze în carcasa printată în plastic, obținând astfel un dispozitiv cu dimensiuni semnificativ reduse;
Utilizarea unui acumulator cu o formă geometrică specială care să permită obținerea unei capacități de încarcare mai mare prin utilizarea eficientă a spațiului disponibil rămas după instalarea modulului electronic;
Realizarea unei interfețe de comuicație universală care să permită interschimbarea senzorilor ce sunt incluși intr-o formă printată în plastic;
Adaptarea unui sistem de comunicație Bluetooth pentru transferul de date și sincronizării informațiilor dintre ceas și un telefon ce suportă aceeași tehnologie
Dezvoltarea codului sursă pentru a fi posibilă updatarea facilă a acestuia, cu scopul de a se adopta și alte versiuni de senzori, cât și pentru posibilitatea instalării unor noi aplicații.
Prin prezenta lucrare se speră trezirea interesului altor viitori ingineri întru realizarea unor astfel de proiecte, cu scopul de a dezvolta noi tehnologii, folositoare atât lor cât și întregii omeniri.
Bibliografie
– Introduction to Flat Panel Displays – Jiun-Haw Lee, David N. Liu, Shin-Tson Wu, pag.
– Physics of Organic Semiconductors – Wolfgang Brütting, pag
– https://learn.sparkfun.com/tutorials/oled-display-hookup-guide/all
– https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all
– https://learn.sparkfun.com/tutorials/what-is-an-arduino/all
–
Anexă
Codul sursă
//utilizam libraria pentru RTC
#include <Wire.h>
#include "RTClib.h"//libraria RTC
RTC_DS1307 RTC;//Sfarsit librarie RTC
//folosim libraria pentru senzorii cu un fir de comunicatie
#include <OneWire.h>//libraria pentru senzorii cu un fir
#include <DallasTemperature.h>//libraria pentru senzorul de temperatura
#define ONE_WIRE_BUS 10//senzorul de temperatura este conectat la pinul 10
OneWire oneWire(ONE_WIRE_BUS);//initiere sesiune de comunicare intre senzorul de temperatura si interfata cu un fir
DallasTemperature senzori_temperatura(&oneWire);//facem legatura intre senzorul de temperatura si interfata cu un sigur fir de comunicare
//sfarsit setup senzori cu un fir de comunicatie
//initiere librarie pentru ecran OLED
#include <uOLED.h>//libraria pentru ecranul OLED
uOLED uoled;
int pin_reset_ecran = 4;//pinul de reset pentru ecran este pin 4 //sfarsit librarie ecran OLED
//initiere variabile folosite in afisarea pe ecranul OLED
int ecran = 0;//setam tipul orientarii ecranului
int ecranRecent = 0;//cea mai recenta setare referitoare la orientarea ecranului
int schimbareEcran= 0;//dorim ca orientarea sa nu se modifice pe parcursul folosirii dispozitivului
int n=0;
#define pixeli_y 127//dimensiunea ecranului in pixeli 0-127 pe axa y
#define pixeli_x 127//dimensiunea ecranului in pixeli 0-127 pe axa x
#define ajustare_pozitie_x 16//aseaza programele pe centrul ecranului in cazul schimbarii rezolutiei
#define ajustare_pozitie_y 32
//sfarsit initiere variabile pentru ecran
//initiere variabile folosite pentru RTC
char info_data[13]; char info_timp[9]; char info_an[5]; char info_luna[4];
char info_zi[3]; char info_sec[3]; char info_min[3]; char info_ora[3];
int sec = 0; int minute = 0; int hour = 0; int year = 9999; int month = 0; int day = 0;//aceste variabile sunt resetate la momentul compilarii programului
//sfarsit initiere variabile pentru RTC
//initiere variabile afisare ora exacta
int timp_y = 1; int timp_x = 1;//sfarsit initiere variabile pentru afisarea timpului
//initiere schema de culori
unsigned int culoare = 63488; unsigned int culoareFundal = 0; unsigned int verde = 2016;//culoarea verde
unsigned int albastru = 2047;//culoarea albastru
unsigned int galben = 64768;//culoarea galben //sfarsit schema de culori
//initiere variabile pentru trackball
int pozitie_y = 30;//pozitie axa y a cursorului
int pozitie_x = 40;//pozitie axa x a cursorului
int pozitie_temp = 0;//reinitializarea cursorului dupa modificarea unei variabile
int pin_sus = 7;//cursor sus
int pin_jos = 6;//cursor jos
int pin_stanga = 9;//cursor stanga
int pin_dreapta = 8;//cursor dreapta
int pin_buton = 3;//apasarea butonului de pe trackball
int stareDreapta = 0; int stareStanga = 0; int stareSus = 0; int stareJos = 0;//initiere variabile pozitie stare trackball
int stareButon = 0; int stareRecentaButon = 0;
int pin_alimentare = 2; int pin_alimentare_2 = 12;
int pin_gnd = 13;//pin de ground //sfarsit initiere variabile trackball
//initiere variabile paint
byte culoareSelectata = 0; int culoare_x = 0; int culoare_y = 0;//incheiere detalii variabile paint
//initiere variabile temperatura
int numar_senzori_temp_initiali = 0;// numar initial de senz de temp //sfarsit variabile temp
//initiere variabile senzor ultrasonic
int pin_senzor_prox = 11; int distanta_inchi; int distanta_cm; //sfarsit variabile senzor ultrasonic
//initiere variabile meniu aplicatii
#define marime_meniu_x 50
#define marime_meniu_y 12
#define margine_meniu1_x 20
#define margine_meniu1_y 80
#define margine_meniu2_x 70
#define margine_meniu2_y 5
#define margine_meniu3_x 5
#define margine_meniu3_y 5
#define margine_meniu4_x 5
#define margine_meniu4_y 30
#define margine_meniu5_x 70
#define margine_meniu5_y 30
#define margine_meniu6_x 70
#define margine_meniu6_y 55//sfarsit variabile meniu
void setup()
{uoled.begin(pin_reset_ecran, 256000, &Serial);//initiem conexiunea cu ecranul OLED prin intermediul interfetei seriale la o viteza de transfer de 256000 bps
attachInterrupt(1, buton, FALLING);
//initiere setup afisare ora exacta
Wire.begin(); RTC.begin();
RTC.adjust(DateTime(__DATE__, __TIME__));//se va seta ora si data de la momentul compilarii programului ca si ora default la pornire //sfarsit initiere setup ora exacta
//initiere setup trackball
pinMode(pin_sus, INPUT); pinMode(pin_jos, INPUT); pinMode(pin_stanga, INPUT); pinMode(pin_dreapta, INPUT); pinMode(pin_buton, INPUT);
digitalWrite(pin_sus, LOW); digitalWrite(pin_jos, LOW); digitalWrite(pin_stanga, LOW); digitalWrite(pin_dreapta, LOW); digitalWrite(pin_buton, LOW);
pinMode(pin_alimentare, OUTPUT); digitalWrite(pin_alimentare, HIGH);//sfarsit setup trackball
pinMode(pin_alimentare_2, OUTPUT); digitalWrite(pin_alimentare_2, HIGH);
pinMode(pin_gnd, OUTPUT); digitalWrite(pin_gnd, LOW);
//initiere setup paint
uoled.AddBMPChar(1, 0xff, 0xc3, 0xa5, 0x99, 0x99, 0xa5, 0xc3, 0xff);//buton exit aplicatie
uoled.AddBMPChar(2, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7e);//buton de golire ecran
uoled.AddBMPChar(3, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);//bulina culoare aleasa
uoled.AddBMPChar(4, 0xff, 0x99, 0x99, 0x99, 0xff, 0xbd, 0x99, 0xff);//icnoita salvare
uoled.AddBMPChar(5, 0xff, 0x99, 0xbd, 0xff, 0x99, 0x99, 0x99, 0xff);//iconita incarcare //sfarsit setup paint
//initiere setup joc
uoled.AddBMPChar(6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);//iconita golire spotului
uoled.AddBMPChar(7, 0x00, 0x00, 0xff, 0x81, 0x81, 0xff, 0x00, 0x00);//patrat gol
uoled.AddBMPChar(8, 0x00, 0x00, 0xff, 0xd4, 0xab, 0xff, 0x00, 0x00);//patrat hasurat
uoled.AddBMPChar(9, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00);//patrat plin
uoled.AddBMPChar(10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x44);//patrat cu diagonale //sfarsit setup joc
//initiere setup masurare temperatura
senzori_temperatura.begin();
numar_senzori_temp_initiali = senzori_temperatura.getDeviceCount();//identificarea numarului de senzori de temperatura atasati la ceas //sfarsit setup temperatura
//initiere setup senzor ultrasonic
pinMode(pin_senzor_prox, INPUT); }//sfarsit setup senzor ultrasonic
void loop()
{ if(ecranRecent != ecran)//ne asiguram ca nu se schimba orientarea ecranului
{ uoled.Cls(); schimbareEcran = 1; }
ecranRecent = ecran; switch(ecran)
{ case 0: oraExacta(); uoled.Text(4,4, 2, 2016, info_timp,1); uoled.Text(3,6, 2, 2016, info_data,1); break;//afisarea orei exacte in format digital-text
case 1: oraExacta(); ceasBinar(); break;//afisarea orei exacte in format binar
case 2: oraExacta(); ceasAnalogic(); break;//afisarea orei exacte in format analogic
case 3: menu(); break;//afisarea meniului cu aplicatii
case 4: ecran = 0; break;//se revine la afisarea initiala a orei exacte in format digital-text
case 5: paint(); break;//pornirea aplicatiei de desen
case 6: joc(); break;//pornirea jocului
case 7: temper(); break;//pornirea aplicatiei de citire a temperaturii
case 8: range(); break;//pornirea aplicatiei de masurare a distantei
case 9: set_time(); break; } }//meniul de setare a orei si datei exacte
void oraExacta()
{ DateTime now = RTC.now(); year = now.year(); month = now.month();
day = now.day(); hour = now.hour(); minute = now.minute(); sec = now.second();
itoa(hour, info_ora, 10); itoa(minute, info_min, 10); itoa(sec, info_sec, 10); itoa(day, info_zi, 10); itoa(month, info_luna, 10); itoa(year, info_an, 10);
if(hour > 9) { info_timp[0] = info_ora[0]; info_timp[1] = info_ora[1]; }
else { info_timp[0] = '0'; info_timp[1] = info_ora[0]; }
info_timp[2] = ':'; if(minute > 9) { info_timp[3] = info_min[0]; info_timp[4] = info_min[1]; }
else { info_timp[3] = '0'; info_timp[4] = info_min[0];}
info_timp[5] = ':';
if(sec > 9) { info_timp[6] = info_sec[0]; info_timp[7] = info_sec[1]; }
else { info_timp[6] = '0'; info_timp[7] = info_sec[0]; }
//urmeaza partea pentru data in format zi:luna:an
if(day > 9) { info_data[0] = info_zi[0]; info_data[1] = info_zi[1]; }
else { info_data[0] = '0'; info_data[1] = info_zi[0]; } info_data[2] = '.';
if(month > 9) { info_data[3] = info_luna[0]; info_data[4] = info_luna[1]; }
else { info_data[3] = '0'; info_data[4] = info_luna[0]; }
info_data[5] = '.'; info_data[6] = info_an[0]; info_data[7] = info_an[1];
info_data[8] = info_an[2]; info_data[9] = info_an[3]; }
void buton()
{ ecran++; if(ecran > 4)
{ ecran = 0; } }
void trackball(int &x, int &y)
{ if(stareDreapta != digitalRead(pin_dreapta))
{ x++; stareDreapta = !stareDreapta; }//muta cursor la dreapta
if(stareStanga != digitalRead(pin_stanga))
{ x–; stareStanga = !stareStanga;//muta cursorul la stanga
if(x < 0) x = 0; }
if(stareSus != digitalRead(pin_sus))
{ y++; stareSus = !stareSus; }//muta cursorul in sus
if(stareJos != digitalRead(pin_jos))
{ y–; stareJos = !stareJos;//muta cursorul in jos
if(y < 0) y = 0; }
stareRecentaButon = stareButon; stareButon = !digitalRead(pin_buton); }
void joc()
{ int viteza_axa_x = 1; int viteza_axa_y = 1;//viteza bilei viteza_axa_x
int pozitie_bila_x = 40; int pozitie_bila_y = 40;//pozitia bilei
unsigned int culoare_bila = 0x7E0;//culoarea bilei
int activitate_bila = 0;// numar curent de cicluri activitate
int cicluri_activitate_bila = 5;//numarul de cicluri de program pentru a actualiza pozitia bilei pentru controlul vitezei de deplasare a bilei fara delay
int numar_bile = 3;//numarul de bile ramase
int marime_bila = 2;//dimensiunea bilei
char info_numar_bile[2]; int culoareFundal = 0;//culoarea fundalului
int locatie_plaftorma_x = 48;//locatia platformei
int locatie_recenta_platforma_x = 48;//ultima pozitie cunoscuta a platformei
int marime_platforma = 10;//jumatate din latimea platformei
int viteza_platforma = 3;//viteza la care putem muta platforma
int locatie_temporara;//variabila de temperatura
unsigned int scor = 0; char info_scor[6];//scorul jocului
byte schimbare_nivel = 1;//se activeaza in momentul schimbarii nivelului
byte nivel = 0;//nivelul de joc curent
byte numar_nivele = 1;//numarul de nivele
int culoare_caramida[4] = {0, galben, albastru, verde} ;//culoare caramizi
byte caramizi_ramase[1];//numarul de atingeri ale blocurilor pentru fiecare nivel, suma lor
const byte harta_nivel[1][8][12] = //harta de nivel
{ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }
, { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, } };
byte rand_caramizi[8][12];//nivel curent de joc
detachInterrupt(1); byte ruleaza_joc = 1; while(ruleaza_joc)//se activeaza cand porneste jocul
{ if(schimbare_nivel) {uoled.Cls();//initilizarea ecranului oled
for(int i = 0; i < 8; i++)
{for(int j = 0; j < 12; j++)
{ rand_caramizi[i][j] = harta_nivel[nivel][i][j];
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]);// afisarea initiala a blocurilor
caramizi_ramase[nivel] += harta_nivel[nivel][i][j]; } }// numaram numarul de blocuri din nivelul jocului
schimbare_nivel = 0; }
locatie_recenta_platforma_x = locatie_plaftorma_x; trackball(locatie_plaftorma_x, pozitie_temp); locatie_plaftorma_x = locatie_plaftorma_x + viteza_platforma * (locatie_plaftorma_x – locatie_recenta_platforma_x);//controlam viteza platformei
if(locatie_plaftorma_x + marime_platforma > 95) locatie_plaftorma_x = 95 – marime_platforma; if(locatie_plaftorma_x – marime_platforma < 0) locatie_plaftorma_x = 0 + marime_platforma; // dimensiunea plaftormei
uoled.Line(0 + ajustare_pozitie_x, 62, 95 + ajustare_pozitie_x, 62, 0);//resetarea platformei
uoled.Line((locatie_plaftorma_x – marime_platforma) + ajustare_pozitie_x, 62, (locatie_plaftorma_x + marime_platforma) + ajustare_pozitie_x, 62, 0x7E0);//afisarea platformei
activitate_bila ++; if(activitate_bila = cicluri_activitate_bila)//miscam bila, aici mentionam toate obiectele cu care aceasta interactioneaza
{ uoled.Rectangle(0 + ajustare_pozitie_x,56, 95 + ajustare_pozitie_x,61, culoareFundal, 1);// golim ecranul fara a sterge blocurile ramase in joc
uoled.Rectangle(0 + ajustare_pozitie_x,63, 95 + ajustare_pozitie_x,65, culoareFundal, 1);// golim ecranul jocului fara cu resetarea timpului activ al bilei;// resetam timp activitate bila
if(pozitie_bila_x < 8 || (pozitie_bila_x % 8 > 3 && pozitie_bila_x < 88))
{ if(pozitie_bila_y < 8 || (pozitie_bila_y % 8 > 3 && pozitie_bila_y < 56))
{ for(int j = (pozitie_bila_x / 8); j < 2 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8); i < 2 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } }//afisam blocurile
else { for(int j = (pozitie_bila_x / 8); j < 2 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8) – 1; i < 1 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } } }//afisam blocurile
else { if(pozitie_bila_y < 8 || (pozitie_bila_y % 8 > 3 && pozitie_bila_y < 56))
{ for(int j = (pozitie_bila_x / 8) – 1; j < 1 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8); i < 2 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } }//afisam blocurile
else { for(int j = (pozitie_bila_x / 8) – 1; j < 1 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8) – 1; i < 1 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } } }// afisam blocurile
pozitie_bila_x = pozitie_bila_x + viteza_axa_x;//miscam bila in directia x
pozitie_bila_y = pozitie_bila_y + viteza_axa_y;//miscam bila in directia y
uoled.Circle(pozitie_bila_x + ajustare_pozitie_x, pozitie_bila_y, marime_bila, culoare_bila, 1); // afisam bila
if(pozitie_bila_y < 55 && rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]) //bila loveste un bloc
{ scor += (4 – rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]) * 50; //incrementam scorul
rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]–;
caramizi_ramase[nivel]–;//scadem numarul total de blocuri ramase pe ecran
viteza_axa_y = ~viteza_axa_y + 1;//inversam viteza pe axa y
if(!caramizi_ramase[nivel])
{ nivel++;
pozitie_bila_x = 48; pozitie_bila_y = 40; locatie_plaftorma_x = 48;//se reseteaza pozitia bilei pentru incepere unui stagiu nou al jocului
schimbare_nivel = 1;//incarcam noul stagiu
if(nivel == numar_nivele)
{ uoled.Text(4,2, 2, 150, "Ai Castigat!",1);//Ai castigat!
delay(1000);
marime_platforma–; //scadem latimea plaformei
nivel = 0; } } }//resetam jocul la nivelul initial
locatie_temporara = pozitie_bila_x – locatie_plaftorma_x;
if(pozitie_bila_y == 62 && abs(locatie_temporara) < marime_platforma) //bila loveste platforma
{ viteza_axa_y = ~viteza_axa_y + 1;//inversam viteza pe axa y
if(locatie_temporara < -5) viteza_axa_x–;//daca lovim cu bila marginea din stanga a platformei, se lanseaza bila spre stanga
if(locatie_temporara > 5) viteza_axa_x++; }//daca lovim cu bila marginea din dreapta a platformei, se lanseaza bila spre dreapta
if(pozitie_bila_y < 1 + marime_bila)//bila atinge peretele superior
{ viteza_axa_y = ~viteza_axa_y + 1; }//inversam viteza pe axa y
if(pozitie_bila_x < 0 + marime_bila || pozitie_bila_x > 94 – marime_bila)//bila atinge un perete lateral
{ viteza_axa_x = ~viteza_axa_x + 1; }//inversam viteza bilei pe axa x
if(pozitie_bila_y == 63)
{ numar_bile–;//scadem numarul de bile ramase
if(numar_bile < 0)
{ attachInterrupt(1, buton, FALLING);//initiem fanionul de intrerupere
uoled.Text(4,2, 2, 150, "Game Over",1);//joc pierdut
delay(1000); ruleaza_joc = 0;}
else { pozitie_bila_x = 40;//scadem numarul de bile ramase
pozitie_bila_y = 40; locatie_plaftorma_x = 48; viteza_axa_x = 1; viteza_axa_y = 1; } }
itoa(scor, info_scor, 10);//actualizam scorul
uoled.Text(4, 0, 0, 150, info_scor,1);//acesta actualizare este functionala doar daca bila este activa
itoa(numar_bile, info_numar_bile, 10);//actualizam numarul de bile disponibile
uoled.Text(18, 0, 0, 150, info_numar_bile,1); } } }//aceasta actualizare este functionala doar daca exista bile disponibile
void ceasAnalogic() //initiem valorile pentru ceasul analogic
{float Pi = 3.14159; float marime_ceas = 40.0; float pozitie_cadran_x = 64.0; float pozitie_cadran_y = 64.0;//sfarsit initiere variabile ceas analogic
uoled.Circle(pozitie_cadran_x,pozitie_cadran_y, 0.85 * marime_ceas, culoareFundal,1);
uoled.Circle(pozitie_cadran_x,pozitie_cadran_y, marime_ceas, verde,0);//desenam cadranul ceasului
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.6 * marime_ceas * sin(Pi * (float(minute)/60.0 + float(hour))/6.0), pozitie_cadran_y – 0.6 * marime_ceas * cos(Pi * (float(minute)/60.0 + float(hour))/6.0), verde);//afisam linia pentru ore
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.8 * marime_ceas * sin(Pi * float(minute)/30.0), pozitie_cadran_y – 0.8 * marime_ceas * cos(Pi * float(minute)/30.0), albastru); //afisam linia pentru minute
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.8 * marime_ceas * sin(Pi * float(sec)/30.0), pozitie_cadran_y – 0.8 * marime_ceas * cos(Pi * float(sec)/30.0), galben); //afisam linia pentru secunde
for(int i = 1; i < 13; i++)
{uoled.Line(pozitie_cadran_x + 0.9 * marime_ceas * sin(Pi * float(i)/6.0), pozitie_cadran_y – 0.9 * marime_ceas * cos(Pi * float(i)/6.0), pozitie_cadran_x + marime_ceas * sin(Pi * float(i)/6.0), pozitie_cadran_y – marime_ceas * cos(Pi * float(i)/6.0), verde); } }//afisam unitatile pe marginea cadranului
void ceasBinar()
{ int spatiere_bulina_x = 16;//spatiere intre bulinele de pe ecran
if(schimbareEcran)
{ schimbareEcran = 0;
for(int i = 0; i < 6; i++)
{ uoled.Circle(5 + spatiere_bulina_x, 55-10*i, 3, verde, 1);}//afisare buline an
for(int i = 0; i < 4; i++)
{ uoled.Circle(20 + spatiere_bulina_x,55-10*i, 3, albastru, 1);}//afisare buline luna
for(int i = 0; i < 5; i++)
{ uoled.Circle(35 + spatiere_bulina_x,55-10*i, 3, galben, 1);}//afisare buline zi
for(int i = 0; i < 5; i++)
{ uoled.Circle(55 + spatiere_bulina_x,55-10*i, 3, verde, 1);}//afisare buline ora
for(int i = 0; i < 6; i++)
{ uoled.Circle(70 + spatiere_bulina_x,55-10*i, 3, albastru, 1);}//afisare buline minut
for(int i = 0; i < 6; i++)
{ uoled.Circle(85 + spatiere_bulina_x,55-10*i, 3, galben, 1); } }//afisare buline secunda
for(int i = 0; i < 6; i++)
{ if(((year – 2000) >> i) & 1) { uoled.Circle(5 + spatiere_bulina_x,55-10*i, 3, verde, 1); }
else { uoled.Circle(5 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1); } } //animatie an
for(int i = 0; i < 4; i++)
{ if((month >> i) & 1) { uoled.Circle(20 + spatiere_bulina_x,55-10*i, 3, albastru, 1); }
else { uoled.Circle(20 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie luna
for(int i = 0; i < 5; i++)
{ if((day >> i) & 1) {uoled.Circle(35 + spatiere_bulina_x,55-10*i, 3, galben, 1); }
else { uoled.Circle(35 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie zi
for(int i = 0; i < 6; i++)
{ if((hour >> i) & 1) {uoled.Circle(55 + spatiere_bulina_x,55-10*i, 3, verde, 1); }
else { uoled.Circle(55 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie ora
for(int i = 0; i < 6; i++)
{ if((minute >> i) & 1){uoled.Circle(70 + spatiere_bulina_x,55-10*i, 3, albastru, 1); }
else { uoled.Circle(70 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie minut
for(int i = 0; i < 6; i++)
{ if((sec >> i) & 1) {uoled.Circle(85 + spatiere_bulina_x,55-10*i, 3, galben, 1); }
else { uoled.Circle(85 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1); }}}//animatie secunda
void senzor_prox() //program masurare distanta cu senzor ultrasonic
{ unsigned int puls_unda_usonica;//initiere variabila
puls_unda_usonica = pulseIn(pin_senzor_prox, HIGH);
distanta_cm = distanta_inchi * 2.54;//afisare distanta in centimetri
distanta_inchi = puls_unda_usonica / 147; }//afisare distanta in inchi
void menu()
{ if(schimbareEcran)
{ pozitie_x = 64; pozitie_y = 32; schimbareEcran = 0;
uoled.TextGraphic(margine_meniu3_x + 1, margine_meniu3_y + 2, 0, 150, 1, 1, " Joc",1);
uoled.Rectangle(margine_meniu3_x, margine_meniu3_y, margine_meniu3_x + marime_meniu_x, margine_meniu3_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu2_x + 1, margine_meniu2_y + 2, 0, 150, 1, 1, " Paint",1);
uoled.Rectangle(margine_meniu2_x, margine_meniu2_y, margine_meniu2_x + marime_meniu_x, margine_meniu2_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu4_x + 1, margine_meniu4_y + 2, 0, 150, 1, 1, "Temperat",1);
uoled.Rectangle(margine_meniu4_x, margine_meniu4_y, margine_meniu4_x + marime_meniu_x, margine_meniu4_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu5_x + 1, margine_meniu5_y + 2, 0, 150, 1, 1, "Distanta",1);
uoled.Rectangle(margine_meniu5_x, margine_meniu5_y, margine_meniu5_x + marime_meniu_x, margine_meniu5_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu6_x + 1,margine_meniu6_y + 2, 0, 150, 1, 1, "Ora&Data",1);
uoled.Rectangle(margine_meniu6_x, margine_meniu6_y, margine_meniu6_x + marime_meniu_x, margine_meniu6_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu1_x + 1, margine_meniu1_y + 2, 1, 150, 1, 1, "Ecran OFF",1);
uoled.Line(0,margine_meniu1_y – 1, pixeli_y, margine_meniu1_y – 1, 0xF800); }
trackball(pozitie_x, pozitie_y); uoled.PutPixel(pozitie_x, pozitie_y, culoare);
if(pozitie_x < margine_meniu3_x + marime_meniu_x && pozitie_x > margine_meniu3_x && pozitie_y < margine_meniu3_y + marime_meniu_y && pozitie_y > margine_meniu3_y)
{ecran = 6;}
if(pozitie_x < margine_meniu2_x + marime_meniu_x && pozitie_x > margine_meniu2_x && pozitie_y < margine_meniu2_y + marime_meniu_y && pozitie_y > margine_meniu2_y)
{ecran = 5;}
if(pozitie_x < margine_meniu4_x + marime_meniu_x && pozitie_x > margine_meniu4_x && pozitie_y < margine_meniu4_y + marime_meniu_y && pozitie_y > margine_meniu4_y)
{ecran = 7;}
if(pozitie_x < margine_meniu5_x + marime_meniu_x && pozitie_x > margine_meniu5_x && pozitie_y < margine_meniu5_y + marime_meniu_y && pozitie_y > margine_meniu5_y)
{ecran = 8;}
if(pozitie_x < margine_meniu6_x + marime_meniu_x && pozitie_x > margine_meniu6_x && pozitie_y < margine_meniu6_y + marime_meniu_y && pozitie_y > margine_meniu6_y)
{ecran = 9;}
if(pozitie_y > margine_meniu1_y – 1)//desenare meniu pentru oprire ecran
{ detachInterrupt(1);//initiem starea de oprire a ecranului
uoled.SetPowerState(0);//stingem ecranul OLED
pozitie_temp = 1;//variabila declarata pentru a se executa functia while
while(pozitie_temp)
{ digitalWrite(pin_alimentare, LOW);//oprim comunicatia cu butonul de pe trackball
delay(1000); digitalWrite(pin_alimentare, HIGH);//reinitiem comunicatia cu trackbalul si asteptam apasarea butonului
delay(10);//asteptam ca butonul sa redevina activ
if(!digitalRead(pin_buton)) pozitie_temp = 0; }//verificam daca este apasat butonul pentru wakeup
attachInterrupt(1, buton, FALLING);//initiem intreruperea
uoled.SetPowerState(1); // pornim ecranul oled
pozitie_x = 48; pozitie_y = 32; } }//resetam pozitia cursorului in meniu
void paint()
{ if(schimbareEcran) //initializarea programului de paint
{ detachInterrupt(1);
schimbareEcran = 0; }
trackball(pozitie_x, pozitie_y);
if(pozitie_y > pixeli_y) pozitie_y = pixeli_y;
if(pozitie_x > pixeli_x) pozitie_x = pixeli_x;
uoled.PutBMPChar(1, 87, pixeli_y – 8, 63488);//butonul de iesire din program
uoled.PutBMPChar(2, 79, pixeli_y – 8, 150);//butonul de golire a ecranului
uoled.PutBMPChar(3, 60, pixeli_y – 8, culoare);//butonul de selectie a culorii
uoled.PutBMPChar(4, 40, pixeli_y – 8, 150);//butonul de salvare a ecranului
uoled.PutBMPChar(5, 30, pixeli_y – 8, 0x03F0);//butonul de incarcare a ecranului
if(stareButon == 1 && stareRecentaButon == 0) culoareSelectata = !culoareSelectata;
if(culoareSelectata) uoled.PutPixel(pozitie_x, pozitie_y, culoare);
if(pozitie_y > pixeli_y – 8) //activam bara de meniu cand intra cursorul in aceasta zona
{ if(pozitie_x > 60 && pozitie_x < 68 && stareButon) //activam functia de selectie a culorii
{ byte stare_selectie_culoare = 1;
while(stare_selectie_culoare)
{ trackball(culoare_x, culoare_y);
if(culoare_y > 2) culoare_y = 2;
if(culoare_y != 1) bitWrite(culoare, (15 – culoare_x), !culoare_y);//functie de activare/dezactivare selectie culoare (on y=0, off y=2)
culoare_y = 1;//ca in momentul in care schimbam culoarea
if(culoare_x > 15) culoare_x = 15;//sa nu paraseasca cursorul zona de selectie a culorii
uoled.Rectangle(96,pixeli_y – 9, pixeli_x,pixeli_y – 1, culoare, 1);//se schimba culoarea backgroundului bitilor de selectie pentru a se vedea culoarea rezultata
uoled.Line(0,pixeli_y, 29,pixeli_y, 0xF800);//subliniem bitii de culoare rosie cu o linie rosie
uoled.Line(30,pixeli_y, 65,pixeli_y, 0x7E0);//subliniem bitii de culoare verde cu o linie verde
uoled.Line(66,pixeli_y, 95,pixeli_y, 0x1F);//subliniem bitii de culoare albastra cu o linie albastra
uoled.Line(0, pixeli_y – 9, 95, pixeli_y – 9, 0);//stergem linia alba de subliniere pentru se vedea bitii de culoare
uoled.Line(6 * culoare_x, pixeli_y – 9, (6 * culoare_x) + 6, pixeli_y – 9, 0xFFFF);//creem o linie alba de subliniere pentru a stii ce bit de culoare este selectat
for(int i = 0; i < 16; i++)
{ uoled.CharacterGraphic(((culoare >> i) & 1) + 48, 90 – (i * 6), pixeli_y – 8, 0xFFFF, 1, 1, 1); }
if(stareButon == 1 && stareRecentaButon == 0)
{ stare_selectie_culoare = 0; // se iese din starea de selectie a culorii
uoled.Rectangle(0,pixeli_y – 9, pixeli_x, pixeli_y, culoareFundal, 1);//se goleste bara de meniuri fara a sterge zona de desen si se afiseaza iconitele functionale
pozitie_x = 64;//se reseteaza pozitia cursorului pentru a nu intra inapoi in optiunea de selectie a culorii
pozitie_y = pixeli_y – 15; culoareSelectata = 0; } } }
if(pozitie_x > 87 && stareButon) attachInterrupt(1, buton, FALLING);//iesire din aplicatie
if(pozitie_x < 87 && pozitie_x > 79 && stareButon) uoled.Cls();//buton de golire ecran
if(pozitie_x > 40 && pozitie_x < 48 && stareButon) { }//buton pentru salvare ecran
if(pozitie_x > 30 && pozitie_x < 38 && stareButon) { }//buton pentru incarcare ecran
uoled.PutPixel(pozitie_x, pozitie_y, 65504); } // facem cursorul vizibil pentru bara de meniu
char info_pozitie_x[3]; itoa(pozitie_x, info_pozitie_x, 10); uoled.Text(0,0, 0, 150, info_pozitie_x,1);
char info_pozitie_y[3]; itoa(pozitie_y, info_pozitie_y, 10); uoled.Text(0,1, 0, 150, info_pozitie_y,1); }
void range()
{ senzor_prox();
char info_distanta_cm[4]; itoa(distanta_cm, info_distanta_cm, 10); info_distanta_cm[3] = ' ';
if(distanta_cm < 10)
{ info_distanta_cm[2] = info_distanta_cm[0]; info_distanta_cm[1] = ' '; info_distanta_cm[0] = ' '; }
else if(distanta_cm < 100)
{ info_distanta_cm[2] = info_distanta_cm[1]; info_distanta_cm[1] = info_distanta_cm[0]; info_distanta_cm[0] = ' '; }
uoled.Text(0,2, 2, 150, info_distanta_cm,1); uoled.Text(4,2, 2, 150, "cm",1);//afisare distanta masurata in centimetri
char info_distanta_inchi[4]; itoa(distanta_inchi, info_distanta_inchi, 10); info_distanta_inchi[3] = ' ';
if(distanta_inchi < 10)
{ info_distanta_inchi[2]=info_distanta_inchi[0];info_distanta_inchi[1]=' '; info_distanta_inchi[0] = ' '; }
else if(distanta_inchi < 100)
{ info_distanta_inchi[2]= info_distanta_inchi[1]; info_distanta_inchi[1] = info_distanta_inchi[0]; info_distanta_inchi[0] = ' '; }
uoled.Text(0,0, 2, 150, info_distanta_inchi,1); uoled.Text(4,0, 2, 150, "inchi",1); }//afisare distanta masurata in inchi
void set_time()
{ byte stare_setare_ora = 1;
while(stare_setare_ora)
{ trackball(timp_x, timp_y); if(timp_x > 5) timp_x = 1; if(timp_x < 1) timp_x = 5; if(timp_y > 2) timp_y = 2;
if(timp_x < 3)
{ uoled.Line(15 * timp_x + 10 + ajustare_pozitie_x, 26 + ajustare_pozitie_y, (15 * timp_x) + 26 + ajustare_pozitie_x, 26 + ajustare_pozitie_y, 0xFFFF); }//linie alba pentru subliniere
if(timp_x > 2) {uoled.Line(15 * (timp_x – 3) + 10, 43 + ajustare_pozitie_y, (15 * timp_x) + 26, 43 + ajustare_pozitie_y, 0xFFFF); }
switch (timp_x) { case 1: if(timp_y < 1) {
hour++; // modificarea valorilor pentru ora
if(hour > 23) hour = 0; }
if(timp_y > 1) { hour–; if(hour < 0) hour = 23; } break;
case 2: if(timp_y < 1) { minute++;//modificarea valorilor pentru minute , nu modificam valoarea secundelor
if(minute > 59) minute = 0; }
if(timp_y > 1) { minute–; if(minute < 0) minute = 59; } break;
case 3: if(timp_y < 1) { month++;//modificarea valorilor pentru luna
if(month > 59) month = 0; }
if(timp_y > 1) { month–; if(month < 0) month = 59; } break;
case 4: if(timp_y < 1) { day++;//modificarea valorilor pentru zi
if(day > 31) day = 0; }
if(timp_y > 1) { day–; if(day < 0) day = 31; } break;
case 5: if(timp_y < 1) { year++;//modificarea valorilor pentru an
if(year > 2099) year = 2000; }
if(timp_y > 1) { year–; if(year < 0) year = 2099; } break; }
timp_y = 1;//resetam aceasta valoare pentru a deveni cursoul controlabil
RTC.adjust(DateTime(year, month, day, hour, minute, sec));
oraExacta();
uoled.Text(4,4, 2, 150, info_timp,1); uoled.Text(2,5, 2, 150, info_data,1);
if(stareButon) stare_setare_ora = 0;
if(timp_x < 3) {uoled.Line(0, 58, 127, 58, culoareFundal); }//trasam o linie de subliniere
if(timp_x > 2) {uoled.Line(0, 75, 127, 75, culoareFundal); }//trasam o linie de subliniere
char info_timp_x[2]; itoa(timp_x, info_timp_x, 10);
uoled.Text(0,0, 0, 150, info_timp_x,1);
char info_timp_y[2]; itoa(timp_y, info_timp_y, 10);
uoled.Text(0,1, 0, 150, info_timp_y,1);
itoa(hour, info_ora, 10); uoled.Text(0,3, 0, 150, info_ora,1);
itoa(minute, info_min, 10); uoled.Text(0,4, 0, 150, info_min,1);
itoa(sec, info_sec, 10); uoled.Text(0,5, 0, 150, info_sec,1);
itoa(year, info_an, 10); uoled.Text(0,6, 0, 150, info_an,1); } }
void temper()
{ float valori_temp[numar_senzori_temp_initiali];//valorile de temperatura
char info_temp[13];//pentru pastrarea temporara a valorile de temperatura
senzori_temperatura.requestTemperatures();//comanda pentru actualizarea valorile tempereraturii citite de la senzor
for(int i = 0; i < numar_senzori_temp_initiali; i++)
{ valori_temp[i] = senzori_temperatura.getTempCByIndex(i);//facem request la valorile de temperatura doar in grade C
itoa(valori_temp[i], info_temp, 10); uoled.Text(4, i, 2, 150, info_temp, 1); uoled.Text(7, i, 2, 150, "grd C",1); }
if(valori_temp[0] > 60.0) uoled.Rectangle(0,64, pixeli_x,pixeli_y, verde, 1);
else if(valori_temp[0] < 10.0) uoled.Rectangle(0,64, pixeli_x,pixeli_y, albastru, 1);
else uoled.Rectangle(0,64, pixeli_x,pixeli_y, 0, 1); }
Bibliografie
– Introduction to Flat Panel Displays – Jiun-Haw Lee, David N. Liu, Shin-Tson Wu, pag.
– Physics of Organic Semiconductors – Wolfgang Brütting, pag
– https://learn.sparkfun.com/tutorials/oled-display-hookup-guide/all
– https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all
– https://learn.sparkfun.com/tutorials/what-is-an-arduino/all
–
Anexă
Codul sursă
//utilizam libraria pentru RTC
#include <Wire.h>
#include "RTClib.h"//libraria RTC
RTC_DS1307 RTC;//Sfarsit librarie RTC
//folosim libraria pentru senzorii cu un fir de comunicatie
#include <OneWire.h>//libraria pentru senzorii cu un fir
#include <DallasTemperature.h>//libraria pentru senzorul de temperatura
#define ONE_WIRE_BUS 10//senzorul de temperatura este conectat la pinul 10
OneWire oneWire(ONE_WIRE_BUS);//initiere sesiune de comunicare intre senzorul de temperatura si interfata cu un fir
DallasTemperature senzori_temperatura(&oneWire);//facem legatura intre senzorul de temperatura si interfata cu un sigur fir de comunicare
//sfarsit setup senzori cu un fir de comunicatie
//initiere librarie pentru ecran OLED
#include <uOLED.h>//libraria pentru ecranul OLED
uOLED uoled;
int pin_reset_ecran = 4;//pinul de reset pentru ecran este pin 4 //sfarsit librarie ecran OLED
//initiere variabile folosite in afisarea pe ecranul OLED
int ecran = 0;//setam tipul orientarii ecranului
int ecranRecent = 0;//cea mai recenta setare referitoare la orientarea ecranului
int schimbareEcran= 0;//dorim ca orientarea sa nu se modifice pe parcursul folosirii dispozitivului
int n=0;
#define pixeli_y 127//dimensiunea ecranului in pixeli 0-127 pe axa y
#define pixeli_x 127//dimensiunea ecranului in pixeli 0-127 pe axa x
#define ajustare_pozitie_x 16//aseaza programele pe centrul ecranului in cazul schimbarii rezolutiei
#define ajustare_pozitie_y 32
//sfarsit initiere variabile pentru ecran
//initiere variabile folosite pentru RTC
char info_data[13]; char info_timp[9]; char info_an[5]; char info_luna[4];
char info_zi[3]; char info_sec[3]; char info_min[3]; char info_ora[3];
int sec = 0; int minute = 0; int hour = 0; int year = 9999; int month = 0; int day = 0;//aceste variabile sunt resetate la momentul compilarii programului
//sfarsit initiere variabile pentru RTC
//initiere variabile afisare ora exacta
int timp_y = 1; int timp_x = 1;//sfarsit initiere variabile pentru afisarea timpului
//initiere schema de culori
unsigned int culoare = 63488; unsigned int culoareFundal = 0; unsigned int verde = 2016;//culoarea verde
unsigned int albastru = 2047;//culoarea albastru
unsigned int galben = 64768;//culoarea galben //sfarsit schema de culori
//initiere variabile pentru trackball
int pozitie_y = 30;//pozitie axa y a cursorului
int pozitie_x = 40;//pozitie axa x a cursorului
int pozitie_temp = 0;//reinitializarea cursorului dupa modificarea unei variabile
int pin_sus = 7;//cursor sus
int pin_jos = 6;//cursor jos
int pin_stanga = 9;//cursor stanga
int pin_dreapta = 8;//cursor dreapta
int pin_buton = 3;//apasarea butonului de pe trackball
int stareDreapta = 0; int stareStanga = 0; int stareSus = 0; int stareJos = 0;//initiere variabile pozitie stare trackball
int stareButon = 0; int stareRecentaButon = 0;
int pin_alimentare = 2; int pin_alimentare_2 = 12;
int pin_gnd = 13;//pin de ground //sfarsit initiere variabile trackball
//initiere variabile paint
byte culoareSelectata = 0; int culoare_x = 0; int culoare_y = 0;//incheiere detalii variabile paint
//initiere variabile temperatura
int numar_senzori_temp_initiali = 0;// numar initial de senz de temp //sfarsit variabile temp
//initiere variabile senzor ultrasonic
int pin_senzor_prox = 11; int distanta_inchi; int distanta_cm; //sfarsit variabile senzor ultrasonic
//initiere variabile meniu aplicatii
#define marime_meniu_x 50
#define marime_meniu_y 12
#define margine_meniu1_x 20
#define margine_meniu1_y 80
#define margine_meniu2_x 70
#define margine_meniu2_y 5
#define margine_meniu3_x 5
#define margine_meniu3_y 5
#define margine_meniu4_x 5
#define margine_meniu4_y 30
#define margine_meniu5_x 70
#define margine_meniu5_y 30
#define margine_meniu6_x 70
#define margine_meniu6_y 55//sfarsit variabile meniu
void setup()
{uoled.begin(pin_reset_ecran, 256000, &Serial);//initiem conexiunea cu ecranul OLED prin intermediul interfetei seriale la o viteza de transfer de 256000 bps
attachInterrupt(1, buton, FALLING);
//initiere setup afisare ora exacta
Wire.begin(); RTC.begin();
RTC.adjust(DateTime(__DATE__, __TIME__));//se va seta ora si data de la momentul compilarii programului ca si ora default la pornire //sfarsit initiere setup ora exacta
//initiere setup trackball
pinMode(pin_sus, INPUT); pinMode(pin_jos, INPUT); pinMode(pin_stanga, INPUT); pinMode(pin_dreapta, INPUT); pinMode(pin_buton, INPUT);
digitalWrite(pin_sus, LOW); digitalWrite(pin_jos, LOW); digitalWrite(pin_stanga, LOW); digitalWrite(pin_dreapta, LOW); digitalWrite(pin_buton, LOW);
pinMode(pin_alimentare, OUTPUT); digitalWrite(pin_alimentare, HIGH);//sfarsit setup trackball
pinMode(pin_alimentare_2, OUTPUT); digitalWrite(pin_alimentare_2, HIGH);
pinMode(pin_gnd, OUTPUT); digitalWrite(pin_gnd, LOW);
//initiere setup paint
uoled.AddBMPChar(1, 0xff, 0xc3, 0xa5, 0x99, 0x99, 0xa5, 0xc3, 0xff);//buton exit aplicatie
uoled.AddBMPChar(2, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7e);//buton de golire ecran
uoled.AddBMPChar(3, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);//bulina culoare aleasa
uoled.AddBMPChar(4, 0xff, 0x99, 0x99, 0x99, 0xff, 0xbd, 0x99, 0xff);//icnoita salvare
uoled.AddBMPChar(5, 0xff, 0x99, 0xbd, 0xff, 0x99, 0x99, 0x99, 0xff);//iconita incarcare //sfarsit setup paint
//initiere setup joc
uoled.AddBMPChar(6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);//iconita golire spotului
uoled.AddBMPChar(7, 0x00, 0x00, 0xff, 0x81, 0x81, 0xff, 0x00, 0x00);//patrat gol
uoled.AddBMPChar(8, 0x00, 0x00, 0xff, 0xd4, 0xab, 0xff, 0x00, 0x00);//patrat hasurat
uoled.AddBMPChar(9, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00);//patrat plin
uoled.AddBMPChar(10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x44);//patrat cu diagonale //sfarsit setup joc
//initiere setup masurare temperatura
senzori_temperatura.begin();
numar_senzori_temp_initiali = senzori_temperatura.getDeviceCount();//identificarea numarului de senzori de temperatura atasati la ceas //sfarsit setup temperatura
//initiere setup senzor ultrasonic
pinMode(pin_senzor_prox, INPUT); }//sfarsit setup senzor ultrasonic
void loop()
{ if(ecranRecent != ecran)//ne asiguram ca nu se schimba orientarea ecranului
{ uoled.Cls(); schimbareEcran = 1; }
ecranRecent = ecran; switch(ecran)
{ case 0: oraExacta(); uoled.Text(4,4, 2, 2016, info_timp,1); uoled.Text(3,6, 2, 2016, info_data,1); break;//afisarea orei exacte in format digital-text
case 1: oraExacta(); ceasBinar(); break;//afisarea orei exacte in format binar
case 2: oraExacta(); ceasAnalogic(); break;//afisarea orei exacte in format analogic
case 3: menu(); break;//afisarea meniului cu aplicatii
case 4: ecran = 0; break;//se revine la afisarea initiala a orei exacte in format digital-text
case 5: paint(); break;//pornirea aplicatiei de desen
case 6: joc(); break;//pornirea jocului
case 7: temper(); break;//pornirea aplicatiei de citire a temperaturii
case 8: range(); break;//pornirea aplicatiei de masurare a distantei
case 9: set_time(); break; } }//meniul de setare a orei si datei exacte
void oraExacta()
{ DateTime now = RTC.now(); year = now.year(); month = now.month();
day = now.day(); hour = now.hour(); minute = now.minute(); sec = now.second();
itoa(hour, info_ora, 10); itoa(minute, info_min, 10); itoa(sec, info_sec, 10); itoa(day, info_zi, 10); itoa(month, info_luna, 10); itoa(year, info_an, 10);
if(hour > 9) { info_timp[0] = info_ora[0]; info_timp[1] = info_ora[1]; }
else { info_timp[0] = '0'; info_timp[1] = info_ora[0]; }
info_timp[2] = ':'; if(minute > 9) { info_timp[3] = info_min[0]; info_timp[4] = info_min[1]; }
else { info_timp[3] = '0'; info_timp[4] = info_min[0];}
info_timp[5] = ':';
if(sec > 9) { info_timp[6] = info_sec[0]; info_timp[7] = info_sec[1]; }
else { info_timp[6] = '0'; info_timp[7] = info_sec[0]; }
//urmeaza partea pentru data in format zi:luna:an
if(day > 9) { info_data[0] = info_zi[0]; info_data[1] = info_zi[1]; }
else { info_data[0] = '0'; info_data[1] = info_zi[0]; } info_data[2] = '.';
if(month > 9) { info_data[3] = info_luna[0]; info_data[4] = info_luna[1]; }
else { info_data[3] = '0'; info_data[4] = info_luna[0]; }
info_data[5] = '.'; info_data[6] = info_an[0]; info_data[7] = info_an[1];
info_data[8] = info_an[2]; info_data[9] = info_an[3]; }
void buton()
{ ecran++; if(ecran > 4)
{ ecran = 0; } }
void trackball(int &x, int &y)
{ if(stareDreapta != digitalRead(pin_dreapta))
{ x++; stareDreapta = !stareDreapta; }//muta cursor la dreapta
if(stareStanga != digitalRead(pin_stanga))
{ x–; stareStanga = !stareStanga;//muta cursorul la stanga
if(x < 0) x = 0; }
if(stareSus != digitalRead(pin_sus))
{ y++; stareSus = !stareSus; }//muta cursorul in sus
if(stareJos != digitalRead(pin_jos))
{ y–; stareJos = !stareJos;//muta cursorul in jos
if(y < 0) y = 0; }
stareRecentaButon = stareButon; stareButon = !digitalRead(pin_buton); }
void joc()
{ int viteza_axa_x = 1; int viteza_axa_y = 1;//viteza bilei viteza_axa_x
int pozitie_bila_x = 40; int pozitie_bila_y = 40;//pozitia bilei
unsigned int culoare_bila = 0x7E0;//culoarea bilei
int activitate_bila = 0;// numar curent de cicluri activitate
int cicluri_activitate_bila = 5;//numarul de cicluri de program pentru a actualiza pozitia bilei pentru controlul vitezei de deplasare a bilei fara delay
int numar_bile = 3;//numarul de bile ramase
int marime_bila = 2;//dimensiunea bilei
char info_numar_bile[2]; int culoareFundal = 0;//culoarea fundalului
int locatie_plaftorma_x = 48;//locatia platformei
int locatie_recenta_platforma_x = 48;//ultima pozitie cunoscuta a platformei
int marime_platforma = 10;//jumatate din latimea platformei
int viteza_platforma = 3;//viteza la care putem muta platforma
int locatie_temporara;//variabila de temperatura
unsigned int scor = 0; char info_scor[6];//scorul jocului
byte schimbare_nivel = 1;//se activeaza in momentul schimbarii nivelului
byte nivel = 0;//nivelul de joc curent
byte numar_nivele = 1;//numarul de nivele
int culoare_caramida[4] = {0, galben, albastru, verde} ;//culoare caramizi
byte caramizi_ramase[1];//numarul de atingeri ale blocurilor pentru fiecare nivel, suma lor
const byte harta_nivel[1][8][12] = //harta de nivel
{ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }
, { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
, } };
byte rand_caramizi[8][12];//nivel curent de joc
detachInterrupt(1); byte ruleaza_joc = 1; while(ruleaza_joc)//se activeaza cand porneste jocul
{ if(schimbare_nivel) {uoled.Cls();//initilizarea ecranului oled
for(int i = 0; i < 8; i++)
{for(int j = 0; j < 12; j++)
{ rand_caramizi[i][j] = harta_nivel[nivel][i][j];
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]);// afisarea initiala a blocurilor
caramizi_ramase[nivel] += harta_nivel[nivel][i][j]; } }// numaram numarul de blocuri din nivelul jocului
schimbare_nivel = 0; }
locatie_recenta_platforma_x = locatie_plaftorma_x; trackball(locatie_plaftorma_x, pozitie_temp); locatie_plaftorma_x = locatie_plaftorma_x + viteza_platforma * (locatie_plaftorma_x – locatie_recenta_platforma_x);//controlam viteza platformei
if(locatie_plaftorma_x + marime_platforma > 95) locatie_plaftorma_x = 95 – marime_platforma; if(locatie_plaftorma_x – marime_platforma < 0) locatie_plaftorma_x = 0 + marime_platforma; // dimensiunea plaftormei
uoled.Line(0 + ajustare_pozitie_x, 62, 95 + ajustare_pozitie_x, 62, 0);//resetarea platformei
uoled.Line((locatie_plaftorma_x – marime_platforma) + ajustare_pozitie_x, 62, (locatie_plaftorma_x + marime_platforma) + ajustare_pozitie_x, 62, 0x7E0);//afisarea platformei
activitate_bila ++; if(activitate_bila = cicluri_activitate_bila)//miscam bila, aici mentionam toate obiectele cu care aceasta interactioneaza
{ uoled.Rectangle(0 + ajustare_pozitie_x,56, 95 + ajustare_pozitie_x,61, culoareFundal, 1);// golim ecranul fara a sterge blocurile ramase in joc
uoled.Rectangle(0 + ajustare_pozitie_x,63, 95 + ajustare_pozitie_x,65, culoareFundal, 1);// golim ecranul jocului fara cu resetarea timpului activ al bilei;// resetam timp activitate bila
if(pozitie_bila_x < 8 || (pozitie_bila_x % 8 > 3 && pozitie_bila_x < 88))
{ if(pozitie_bila_y < 8 || (pozitie_bila_y % 8 > 3 && pozitie_bila_y < 56))
{ for(int j = (pozitie_bila_x / 8); j < 2 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8); i < 2 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } }//afisam blocurile
else { for(int j = (pozitie_bila_x / 8); j < 2 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8) – 1; i < 1 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } } }//afisam blocurile
else { if(pozitie_bila_y < 8 || (pozitie_bila_y % 8 > 3 && pozitie_bila_y < 56))
{ for(int j = (pozitie_bila_x / 8) – 1; j < 1 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8); i < 2 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } }//afisam blocurile
else { for(int j = (pozitie_bila_x / 8) – 1; j < 1 + (pozitie_bila_x / 8); j++)
{ for(int i = (pozitie_bila_y / 8) – 1; i < 1 + (pozitie_bila_y / 8); i++)
{ uoled.PutBMPChar(6, (j * 8) + ajustare_pozitie_x, i * 8, 0);//golim punctul
uoled.PutBMPChar(rand_caramizi[i][j] + 6, (j * 8) + ajustare_pozitie_x, i * 8, culoare_caramida[rand_caramizi[i][j]]); } } } }// afisam blocurile
pozitie_bila_x = pozitie_bila_x + viteza_axa_x;//miscam bila in directia x
pozitie_bila_y = pozitie_bila_y + viteza_axa_y;//miscam bila in directia y
uoled.Circle(pozitie_bila_x + ajustare_pozitie_x, pozitie_bila_y, marime_bila, culoare_bila, 1); // afisam bila
if(pozitie_bila_y < 55 && rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]) //bila loveste un bloc
{ scor += (4 – rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]) * 50; //incrementam scorul
rand_caramizi[pozitie_bila_y / 8][pozitie_bila_x / 8]–;
caramizi_ramase[nivel]–;//scadem numarul total de blocuri ramase pe ecran
viteza_axa_y = ~viteza_axa_y + 1;//inversam viteza pe axa y
if(!caramizi_ramase[nivel])
{ nivel++;
pozitie_bila_x = 48; pozitie_bila_y = 40; locatie_plaftorma_x = 48;//se reseteaza pozitia bilei pentru incepere unui stagiu nou al jocului
schimbare_nivel = 1;//incarcam noul stagiu
if(nivel == numar_nivele)
{ uoled.Text(4,2, 2, 150, "Ai Castigat!",1);//Ai castigat!
delay(1000);
marime_platforma–; //scadem latimea plaformei
nivel = 0; } } }//resetam jocul la nivelul initial
locatie_temporara = pozitie_bila_x – locatie_plaftorma_x;
if(pozitie_bila_y == 62 && abs(locatie_temporara) < marime_platforma) //bila loveste platforma
{ viteza_axa_y = ~viteza_axa_y + 1;//inversam viteza pe axa y
if(locatie_temporara < -5) viteza_axa_x–;//daca lovim cu bila marginea din stanga a platformei, se lanseaza bila spre stanga
if(locatie_temporara > 5) viteza_axa_x++; }//daca lovim cu bila marginea din dreapta a platformei, se lanseaza bila spre dreapta
if(pozitie_bila_y < 1 + marime_bila)//bila atinge peretele superior
{ viteza_axa_y = ~viteza_axa_y + 1; }//inversam viteza pe axa y
if(pozitie_bila_x < 0 + marime_bila || pozitie_bila_x > 94 – marime_bila)//bila atinge un perete lateral
{ viteza_axa_x = ~viteza_axa_x + 1; }//inversam viteza bilei pe axa x
if(pozitie_bila_y == 63)
{ numar_bile–;//scadem numarul de bile ramase
if(numar_bile < 0)
{ attachInterrupt(1, buton, FALLING);//initiem fanionul de intrerupere
uoled.Text(4,2, 2, 150, "Game Over",1);//joc pierdut
delay(1000); ruleaza_joc = 0;}
else { pozitie_bila_x = 40;//scadem numarul de bile ramase
pozitie_bila_y = 40; locatie_plaftorma_x = 48; viteza_axa_x = 1; viteza_axa_y = 1; } }
itoa(scor, info_scor, 10);//actualizam scorul
uoled.Text(4, 0, 0, 150, info_scor,1);//acesta actualizare este functionala doar daca bila este activa
itoa(numar_bile, info_numar_bile, 10);//actualizam numarul de bile disponibile
uoled.Text(18, 0, 0, 150, info_numar_bile,1); } } }//aceasta actualizare este functionala doar daca exista bile disponibile
void ceasAnalogic() //initiem valorile pentru ceasul analogic
{float Pi = 3.14159; float marime_ceas = 40.0; float pozitie_cadran_x = 64.0; float pozitie_cadran_y = 64.0;//sfarsit initiere variabile ceas analogic
uoled.Circle(pozitie_cadran_x,pozitie_cadran_y, 0.85 * marime_ceas, culoareFundal,1);
uoled.Circle(pozitie_cadran_x,pozitie_cadran_y, marime_ceas, verde,0);//desenam cadranul ceasului
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.6 * marime_ceas * sin(Pi * (float(minute)/60.0 + float(hour))/6.0), pozitie_cadran_y – 0.6 * marime_ceas * cos(Pi * (float(minute)/60.0 + float(hour))/6.0), verde);//afisam linia pentru ore
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.8 * marime_ceas * sin(Pi * float(minute)/30.0), pozitie_cadran_y – 0.8 * marime_ceas * cos(Pi * float(minute)/30.0), albastru); //afisam linia pentru minute
uoled.Line(pozitie_cadran_x, pozitie_cadran_y, pozitie_cadran_x + 0.8 * marime_ceas * sin(Pi * float(sec)/30.0), pozitie_cadran_y – 0.8 * marime_ceas * cos(Pi * float(sec)/30.0), galben); //afisam linia pentru secunde
for(int i = 1; i < 13; i++)
{uoled.Line(pozitie_cadran_x + 0.9 * marime_ceas * sin(Pi * float(i)/6.0), pozitie_cadran_y – 0.9 * marime_ceas * cos(Pi * float(i)/6.0), pozitie_cadran_x + marime_ceas * sin(Pi * float(i)/6.0), pozitie_cadran_y – marime_ceas * cos(Pi * float(i)/6.0), verde); } }//afisam unitatile pe marginea cadranului
void ceasBinar()
{ int spatiere_bulina_x = 16;//spatiere intre bulinele de pe ecran
if(schimbareEcran)
{ schimbareEcran = 0;
for(int i = 0; i < 6; i++)
{ uoled.Circle(5 + spatiere_bulina_x, 55-10*i, 3, verde, 1);}//afisare buline an
for(int i = 0; i < 4; i++)
{ uoled.Circle(20 + spatiere_bulina_x,55-10*i, 3, albastru, 1);}//afisare buline luna
for(int i = 0; i < 5; i++)
{ uoled.Circle(35 + spatiere_bulina_x,55-10*i, 3, galben, 1);}//afisare buline zi
for(int i = 0; i < 5; i++)
{ uoled.Circle(55 + spatiere_bulina_x,55-10*i, 3, verde, 1);}//afisare buline ora
for(int i = 0; i < 6; i++)
{ uoled.Circle(70 + spatiere_bulina_x,55-10*i, 3, albastru, 1);}//afisare buline minut
for(int i = 0; i < 6; i++)
{ uoled.Circle(85 + spatiere_bulina_x,55-10*i, 3, galben, 1); } }//afisare buline secunda
for(int i = 0; i < 6; i++)
{ if(((year – 2000) >> i) & 1) { uoled.Circle(5 + spatiere_bulina_x,55-10*i, 3, verde, 1); }
else { uoled.Circle(5 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1); } } //animatie an
for(int i = 0; i < 4; i++)
{ if((month >> i) & 1) { uoled.Circle(20 + spatiere_bulina_x,55-10*i, 3, albastru, 1); }
else { uoled.Circle(20 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie luna
for(int i = 0; i < 5; i++)
{ if((day >> i) & 1) {uoled.Circle(35 + spatiere_bulina_x,55-10*i, 3, galben, 1); }
else { uoled.Circle(35 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie zi
for(int i = 0; i < 6; i++)
{ if((hour >> i) & 1) {uoled.Circle(55 + spatiere_bulina_x,55-10*i, 3, verde, 1); }
else { uoled.Circle(55 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie ora
for(int i = 0; i < 6; i++)
{ if((minute >> i) & 1){uoled.Circle(70 + spatiere_bulina_x,55-10*i, 3, albastru, 1); }
else { uoled.Circle(70 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1);} }//animatie minut
for(int i = 0; i < 6; i++)
{ if((sec >> i) & 1) {uoled.Circle(85 + spatiere_bulina_x,55-10*i, 3, galben, 1); }
else { uoled.Circle(85 + spatiere_bulina_x,55-10*i, 2, culoareFundal, 1); }}}//animatie secunda
void senzor_prox() //program masurare distanta cu senzor ultrasonic
{ unsigned int puls_unda_usonica;//initiere variabila
puls_unda_usonica = pulseIn(pin_senzor_prox, HIGH);
distanta_cm = distanta_inchi * 2.54;//afisare distanta in centimetri
distanta_inchi = puls_unda_usonica / 147; }//afisare distanta in inchi
void menu()
{ if(schimbareEcran)
{ pozitie_x = 64; pozitie_y = 32; schimbareEcran = 0;
uoled.TextGraphic(margine_meniu3_x + 1, margine_meniu3_y + 2, 0, 150, 1, 1, " Joc",1);
uoled.Rectangle(margine_meniu3_x, margine_meniu3_y, margine_meniu3_x + marime_meniu_x, margine_meniu3_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu2_x + 1, margine_meniu2_y + 2, 0, 150, 1, 1, " Paint",1);
uoled.Rectangle(margine_meniu2_x, margine_meniu2_y, margine_meniu2_x + marime_meniu_x, margine_meniu2_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu4_x + 1, margine_meniu4_y + 2, 0, 150, 1, 1, "Temperat",1);
uoled.Rectangle(margine_meniu4_x, margine_meniu4_y, margine_meniu4_x + marime_meniu_x, margine_meniu4_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu5_x + 1, margine_meniu5_y + 2, 0, 150, 1, 1, "Distanta",1);
uoled.Rectangle(margine_meniu5_x, margine_meniu5_y, margine_meniu5_x + marime_meniu_x, margine_meniu5_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu6_x + 1,margine_meniu6_y + 2, 0, 150, 1, 1, "Ora&Data",1);
uoled.Rectangle(margine_meniu6_x, margine_meniu6_y, margine_meniu6_x + marime_meniu_x, margine_meniu6_y + marime_meniu_y, verde, 0);
uoled.TextGraphic(margine_meniu1_x + 1, margine_meniu1_y + 2, 1, 150, 1, 1, "Ecran OFF",1);
uoled.Line(0,margine_meniu1_y – 1, pixeli_y, margine_meniu1_y – 1, 0xF800); }
trackball(pozitie_x, pozitie_y); uoled.PutPixel(pozitie_x, pozitie_y, culoare);
if(pozitie_x < margine_meniu3_x + marime_meniu_x && pozitie_x > margine_meniu3_x && pozitie_y < margine_meniu3_y + marime_meniu_y && pozitie_y > margine_meniu3_y)
{ecran = 6;}
if(pozitie_x < margine_meniu2_x + marime_meniu_x && pozitie_x > margine_meniu2_x && pozitie_y < margine_meniu2_y + marime_meniu_y && pozitie_y > margine_meniu2_y)
{ecran = 5;}
if(pozitie_x < margine_meniu4_x + marime_meniu_x && pozitie_x > margine_meniu4_x && pozitie_y < margine_meniu4_y + marime_meniu_y && pozitie_y > margine_meniu4_y)
{ecran = 7;}
if(pozitie_x < margine_meniu5_x + marime_meniu_x && pozitie_x > margine_meniu5_x && pozitie_y < margine_meniu5_y + marime_meniu_y && pozitie_y > margine_meniu5_y)
{ecran = 8;}
if(pozitie_x < margine_meniu6_x + marime_meniu_x && pozitie_x > margine_meniu6_x && pozitie_y < margine_meniu6_y + marime_meniu_y && pozitie_y > margine_meniu6_y)
{ecran = 9;}
if(pozitie_y > margine_meniu1_y – 1)//desenare meniu pentru oprire ecran
{ detachInterrupt(1);//initiem starea de oprire a ecranului
uoled.SetPowerState(0);//stingem ecranul OLED
pozitie_temp = 1;//variabila declarata pentru a se executa functia while
while(pozitie_temp)
{ digitalWrite(pin_alimentare, LOW);//oprim comunicatia cu butonul de pe trackball
delay(1000); digitalWrite(pin_alimentare, HIGH);//reinitiem comunicatia cu trackbalul si asteptam apasarea butonului
delay(10);//asteptam ca butonul sa redevina activ
if(!digitalRead(pin_buton)) pozitie_temp = 0; }//verificam daca este apasat butonul pentru wakeup
attachInterrupt(1, buton, FALLING);//initiem intreruperea
uoled.SetPowerState(1); // pornim ecranul oled
pozitie_x = 48; pozitie_y = 32; } }//resetam pozitia cursorului in meniu
void paint()
{ if(schimbareEcran) //initializarea programului de paint
{ detachInterrupt(1);
schimbareEcran = 0; }
trackball(pozitie_x, pozitie_y);
if(pozitie_y > pixeli_y) pozitie_y = pixeli_y;
if(pozitie_x > pixeli_x) pozitie_x = pixeli_x;
uoled.PutBMPChar(1, 87, pixeli_y – 8, 63488);//butonul de iesire din program
uoled.PutBMPChar(2, 79, pixeli_y – 8, 150);//butonul de golire a ecranului
uoled.PutBMPChar(3, 60, pixeli_y – 8, culoare);//butonul de selectie a culorii
uoled.PutBMPChar(4, 40, pixeli_y – 8, 150);//butonul de salvare a ecranului
uoled.PutBMPChar(5, 30, pixeli_y – 8, 0x03F0);//butonul de incarcare a ecranului
if(stareButon == 1 && stareRecentaButon == 0) culoareSelectata = !culoareSelectata;
if(culoareSelectata) uoled.PutPixel(pozitie_x, pozitie_y, culoare);
if(pozitie_y > pixeli_y – 8) //activam bara de meniu cand intra cursorul in aceasta zona
{ if(pozitie_x > 60 && pozitie_x < 68 && stareButon) //activam functia de selectie a culorii
{ byte stare_selectie_culoare = 1;
while(stare_selectie_culoare)
{ trackball(culoare_x, culoare_y);
if(culoare_y > 2) culoare_y = 2;
if(culoare_y != 1) bitWrite(culoare, (15 – culoare_x), !culoare_y);//functie de activare/dezactivare selectie culoare (on y=0, off y=2)
culoare_y = 1;//ca in momentul in care schimbam culoarea
if(culoare_x > 15) culoare_x = 15;//sa nu paraseasca cursorul zona de selectie a culorii
uoled.Rectangle(96,pixeli_y – 9, pixeli_x,pixeli_y – 1, culoare, 1);//se schimba culoarea backgroundului bitilor de selectie pentru a se vedea culoarea rezultata
uoled.Line(0,pixeli_y, 29,pixeli_y, 0xF800);//subliniem bitii de culoare rosie cu o linie rosie
uoled.Line(30,pixeli_y, 65,pixeli_y, 0x7E0);//subliniem bitii de culoare verde cu o linie verde
uoled.Line(66,pixeli_y, 95,pixeli_y, 0x1F);//subliniem bitii de culoare albastra cu o linie albastra
uoled.Line(0, pixeli_y – 9, 95, pixeli_y – 9, 0);//stergem linia alba de subliniere pentru se vedea bitii de culoare
uoled.Line(6 * culoare_x, pixeli_y – 9, (6 * culoare_x) + 6, pixeli_y – 9, 0xFFFF);//creem o linie alba de subliniere pentru a stii ce bit de culoare este selectat
for(int i = 0; i < 16; i++)
{ uoled.CharacterGraphic(((culoare >> i) & 1) + 48, 90 – (i * 6), pixeli_y – 8, 0xFFFF, 1, 1, 1); }
if(stareButon == 1 && stareRecentaButon == 0)
{ stare_selectie_culoare = 0; // se iese din starea de selectie a culorii
uoled.Rectangle(0,pixeli_y – 9, pixeli_x, pixeli_y, culoareFundal, 1);//se goleste bara de meniuri fara a sterge zona de desen si se afiseaza iconitele functionale
pozitie_x = 64;//se reseteaza pozitia cursorului pentru a nu intra inapoi in optiunea de selectie a culorii
pozitie_y = pixeli_y – 15; culoareSelectata = 0; } } }
if(pozitie_x > 87 && stareButon) attachInterrupt(1, buton, FALLING);//iesire din aplicatie
if(pozitie_x < 87 && pozitie_x > 79 && stareButon) uoled.Cls();//buton de golire ecran
if(pozitie_x > 40 && pozitie_x < 48 && stareButon) { }//buton pentru salvare ecran
if(pozitie_x > 30 && pozitie_x < 38 && stareButon) { }//buton pentru incarcare ecran
uoled.PutPixel(pozitie_x, pozitie_y, 65504); } // facem cursorul vizibil pentru bara de meniu
char info_pozitie_x[3]; itoa(pozitie_x, info_pozitie_x, 10); uoled.Text(0,0, 0, 150, info_pozitie_x,1);
char info_pozitie_y[3]; itoa(pozitie_y, info_pozitie_y, 10); uoled.Text(0,1, 0, 150, info_pozitie_y,1); }
void range()
{ senzor_prox();
char info_distanta_cm[4]; itoa(distanta_cm, info_distanta_cm, 10); info_distanta_cm[3] = ' ';
if(distanta_cm < 10)
{ info_distanta_cm[2] = info_distanta_cm[0]; info_distanta_cm[1] = ' '; info_distanta_cm[0] = ' '; }
else if(distanta_cm < 100)
{ info_distanta_cm[2] = info_distanta_cm[1]; info_distanta_cm[1] = info_distanta_cm[0]; info_distanta_cm[0] = ' '; }
uoled.Text(0,2, 2, 150, info_distanta_cm,1); uoled.Text(4,2, 2, 150, "cm",1);//afisare distanta masurata in centimetri
char info_distanta_inchi[4]; itoa(distanta_inchi, info_distanta_inchi, 10); info_distanta_inchi[3] = ' ';
if(distanta_inchi < 10)
{ info_distanta_inchi[2]=info_distanta_inchi[0];info_distanta_inchi[1]=' '; info_distanta_inchi[0] = ' '; }
else if(distanta_inchi < 100)
{ info_distanta_inchi[2]= info_distanta_inchi[1]; info_distanta_inchi[1] = info_distanta_inchi[0]; info_distanta_inchi[0] = ' '; }
uoled.Text(0,0, 2, 150, info_distanta_inchi,1); uoled.Text(4,0, 2, 150, "inchi",1); }//afisare distanta masurata in inchi
void set_time()
{ byte stare_setare_ora = 1;
while(stare_setare_ora)
{ trackball(timp_x, timp_y); if(timp_x > 5) timp_x = 1; if(timp_x < 1) timp_x = 5; if(timp_y > 2) timp_y = 2;
if(timp_x < 3)
{ uoled.Line(15 * timp_x + 10 + ajustare_pozitie_x, 26 + ajustare_pozitie_y, (15 * timp_x) + 26 + ajustare_pozitie_x, 26 + ajustare_pozitie_y, 0xFFFF); }//linie alba pentru subliniere
if(timp_x > 2) {uoled.Line(15 * (timp_x – 3) + 10, 43 + ajustare_pozitie_y, (15 * timp_x) + 26, 43 + ajustare_pozitie_y, 0xFFFF); }
switch (timp_x) { case 1: if(timp_y < 1) {
hour++; // modificarea valorilor pentru ora
if(hour > 23) hour = 0; }
if(timp_y > 1) { hour–; if(hour < 0) hour = 23; } break;
case 2: if(timp_y < 1) { minute++;//modificarea valorilor pentru minute , nu modificam valoarea secundelor
if(minute > 59) minute = 0; }
if(timp_y > 1) { minute–; if(minute < 0) minute = 59; } break;
case 3: if(timp_y < 1) { month++;//modificarea valorilor pentru luna
if(month > 59) month = 0; }
if(timp_y > 1) { month–; if(month < 0) month = 59; } break;
case 4: if(timp_y < 1) { day++;//modificarea valorilor pentru zi
if(day > 31) day = 0; }
if(timp_y > 1) { day–; if(day < 0) day = 31; } break;
case 5: if(timp_y < 1) { year++;//modificarea valorilor pentru an
if(year > 2099) year = 2000; }
if(timp_y > 1) { year–; if(year < 0) year = 2099; } break; }
timp_y = 1;//resetam aceasta valoare pentru a deveni cursoul controlabil
RTC.adjust(DateTime(year, month, day, hour, minute, sec));
oraExacta();
uoled.Text(4,4, 2, 150, info_timp,1); uoled.Text(2,5, 2, 150, info_data,1);
if(stareButon) stare_setare_ora = 0;
if(timp_x < 3) {uoled.Line(0, 58, 127, 58, culoareFundal); }//trasam o linie de subliniere
if(timp_x > 2) {uoled.Line(0, 75, 127, 75, culoareFundal); }//trasam o linie de subliniere
char info_timp_x[2]; itoa(timp_x, info_timp_x, 10);
uoled.Text(0,0, 0, 150, info_timp_x,1);
char info_timp_y[2]; itoa(timp_y, info_timp_y, 10);
uoled.Text(0,1, 0, 150, info_timp_y,1);
itoa(hour, info_ora, 10); uoled.Text(0,3, 0, 150, info_ora,1);
itoa(minute, info_min, 10); uoled.Text(0,4, 0, 150, info_min,1);
itoa(sec, info_sec, 10); uoled.Text(0,5, 0, 150, info_sec,1);
itoa(year, info_an, 10); uoled.Text(0,6, 0, 150, info_an,1); } }
void temper()
{ float valori_temp[numar_senzori_temp_initiali];//valorile de temperatura
char info_temp[13];//pentru pastrarea temporara a valorile de temperatura
senzori_temperatura.requestTemperatures();//comanda pentru actualizarea valorile tempereraturii citite de la senzor
for(int i = 0; i < numar_senzori_temp_initiali; i++)
{ valori_temp[i] = senzori_temperatura.getTempCByIndex(i);//facem request la valorile de temperatura doar in grade C
itoa(valori_temp[i], info_temp, 10); uoled.Text(4, i, 2, 150, info_temp, 1); uoled.Text(7, i, 2, 150, "grd C",1); }
if(valori_temp[0] > 60.0) uoled.Rectangle(0,64, pixeli_x,pixeli_y, verde, 1);
else if(valori_temp[0] < 10.0) uoled.Rectangle(0,64, pixeli_x,pixeli_y, albastru, 1);
else uoled.Rectangle(0,64, pixeli_x,pixeli_y, 0
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Ceas Electronic cu Display Oled Si Microcontroler Atmel (ID: 162079)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
