ublo
bogdan's (micro)blog

bogdan » arduino: multimetru digital

07:14 pm on Nov 25, 2018 | #more | tags:

în urma rugăminții profesorului Stamatin, de câțiva ani țin un curs la Facultatea de Fizică din Măgurele. dacă inițial numele «modelare și simulare» ascundea ecuații matematice și metode numerice, recent am înlocuit diferențialele cu Arduino, în ovațiile celor câtorva studenți care frecventează cursul. dotările limitate m-au făcut să devin creativ cu materialele de curs, iar rezultatul mi s-a părut suficient de interesant pentru a-l reproduce aici. așa că:

lucrul care m-a fascinat prima data când am descoperit Arduino a fost capacitatea lui de a conecta lumea reală prin software, în primul rând folosind informații culese prin senzori. în majoritatea lor, senzorii transformă o mărime fizică oarecare într-una electrică: tensiune, curent, rezistență, capacitate sau inductanță, de unde și ideea transformării unui Arduino într-un dispozitiv pentru măsurărea acestor mărimi – într-un cuvânt, multimetru.

cum măsor tensiune electrică?

toate versiunile de Arduino pot măsura tensiuni continue implicit folosind ca terminale de măsură una dintre conexiunile analogice, notate cu A0, A1 etc. și conexiunea GND (de la ”ground”, adică ”împământare”) – în realitate potențialul de referință pentru 0V al plăcuței. intervalul în care un Arduino poate măsura direct tensiuni electrice este cuprins între 0 și 5V pentru versiunile cele mai comune de Arduino – Duemillanove, Uno R3, Leonardo, Nano, LilyPad, LilyTiny, Pro Mini/Micro 5V sau Mega, sau 0 și 3,3V pentru versiunile Pro Mini 3V3, Zero și Due.

Arduino - Direct Measure Voltage

la curs am folosit de cele mai multe ori Arduino UNO și Leonardo, așa că în continuare, dacă nu specific explicit, mă refer la versiunile care pot măsura între 0 și 5V implicit.

un Arduino poate măsura tensiuni cu o rezoluție de 10 biți. mai exact, va împărți intervalul 0 – 5V în 210 = 1024 de sub-intervale egale și va verifica în care dintre cele 1024 de sub-intervale se regăsește tensiunea aplicată la intrare. lungimea unui sub-interval este de 5V / 1024 = 0,004882V, primul sub-interval fiind 0 – 0,004882V, următorul 0,004883V – 0,009765V, urmat de 0,009766V – 0,014648V ș.a.m.d. pentru a respecta convenția utilizată în majoritatea limbajelor de programare, sub-intervalele sunt numerotate începând cu 0.

void setup() {
}

void loop() {
  // functia analogRead primeste ca parametru conexiunea
  // pentru vei masura tensiunea, intorcand sub-intervalul in care
  // se gaseste aceasta
  int interval = analogRead (A0);
  // pentru conversia in tensiune,
  // poti lua capatul din stanga al sub-intervalului:
  float voltage_left = 0.004882 * interval;
  // sau mijlocul sub-intervalului:
  float voltage_center = 0.002441 + 0.004882 * interval;
  // sau capatul din dreapta al sub-intervalului:
  float voltage_right = 0.004882 * (interval + 1);
}

în micul program de mai sus, analogRead este o funcție care are ca parametru identificatorul terminalului Arduino pentru care vrei să măsori tensiunea, întorcând un număr întreg – specificat de cuvântul cheie int – care corespunde numărului de ordine al sub-intervalului în intervalul de măsură. pentru conversia intr-un numar real e suficient să-l incluzi în operații aritmetice cu numere reale, iar rezultatul să-l atribui unui loc în memorie declarat ca fiind real prin cuvântul cheie float.

o eroare pe care am întâlnit-o destul de des o reprezintă folosirea numerelor întregi în operațiile aritmetice care ar trebui să producă numere reale. Arduino va face automat conversia în ultimul moment posibil, astfel că următoarea secvență va produce ca rezultat numere întregi intre 0 si 4:

void loop() {
  // analogRead intoarce un numar intreg
  int interval = analogRead (A0);
  // operatiile se efectueaza in ordine, pastrand tipul cel mai convenabil
  // 5 * interval va fi un numar intreg intre 0 si 5115, care ulterior va fi
  // impartit ca numar intreg (cu rest) la 1024, rezultand un numar intreg
  // intre 0 si 4, care abia apoi va fi convertit intr-un numar real
  float voltage_left = 5 * interval / 1024;
}

notă
numărul de zecimale care pot fi folosite din tensiunea obținută este dat de numărul de zerouri după virgulă din lungimea unui sub-interval de măsură. în cazul anterior, pot folosi 2 zecimale deoarece lungimea sub-intervalului este 0,004882V

așa cum unul dintre studenți mei a aflat experimental, aplicând tensiuni mai mari decât tensiunea de alimentare la intrarea Arduino de cele mai multe ori va strica ireversibil conexiunea unde a fost aplicată. pentru a evita problemele de acest tip și pentru a putea măsura totuși tensiuni electrice mai mari, metoda cea mai la îndemână este ”divizorul rezistiv”.

Arduino - Voltage Divisor

un divizor rezistiv este alcătuit din doi rezistori, R1 și R2 conectați în serie, ale căror terminale libere devin terminalele de măsură ale multimetrului, în timp ce Arduino va măsura căderea de tensiune doar pe unul dintre rezistorii divizorului, R2.

$$U_{arduino} = U_{necunoscuta} \times \frac{R_2}{R_1 + R_2} \\ U_{necunoscuta} = U_{arduino} \times \frac{R_1 + R_2}{R_2}$$

pentru R2 o valoarea bună este 10kΩ, bazată pe caracteristica circuitului de intrare a Arduino. în funcție de intervalul în care estimezi că se va afla tensiunea necunoscută, poți calcula valoarea rezistorului R1. să presupunem că vrei să măsori tensiunea unui acumulator LiPo 3S – adică, cu trei celule. tensiunea unei celule variază în intervalul 2,8 – 4,3V, făcând tensiunea acumulatorului să varieze în intervalul 8,4 – 12,9V. considerând o marjă de siguranță, capătul superior al intervalului devine 15V. în situația asta, valoarea lui R1 va fi:

$$ R_1 = (\frac{U_{max}}{U_{arduino_max}} – 1) \times R_2 \\ R_1 = (\frac{15V}{5V} – 1) \times 10k\Omega = 20k\Omega $$

notă
știi sigur că o formulă fizică e corectă atunci când unitățile de măsură din stânga egalului sunt aceleași cu cele din dreapta, aplicând regulile aritmetice. în situația de mai sus, R1 se măsoară în ohmi, prima paranteză după egal nu are unitate de măsură (volt se ”simplifică” cu volt), iar factorul rămas se măsoară în ohmi, rezumând formula la ohmi = ohmi.

în același timp, lungimea unui sub-interval de măsură va deveni 0,014648V

void loop() {
  int interval = analogRead (A0);
  float voltage_left = 0.014648 * interval;
  float voltage_center = 0.007324 + 0.014648 * interval;
  float voltage_right = 0.014648 * (interval + 1);
}

din nefericire, 20kΩ nu e o valoare standard pentru un rezistor, însă poate fi ușor replicată cu două rezistoare înseriate de câte 10kΩ. în cazul în care vrei să alegi o valoare standard, cea mai apropiată e 22kΩ. în această situație, tensiunea maximă devine:

$$ U_{max} = U_{arduino_max} \times \frac{R_1 + R_2}{R_2} \\ U_{max} = 5V \times \frac{22k\Omega + 10k\Omega}{10k\Omega} = 16V $$

iar formulele pentru calculul tensiunii electrice folosind Arduino sunt:

void loop() {
  int interval = analogRead (A0);
  float voltage_left = 0.015625 * interval;
  float voltage_center = 0.007812 + 0.015625 * interval;
  float voltage_right = 0.015625 * (interval + 1);
}

notă
recomand măsurarea tensiunilor mari cu extrem de mare atenție. tot ce depășește 32V poate fi extrem de periculos. în nicio situație nu încerca să măsori tensiunea rețelei de curent electric!

o nouă problemă în măsurarea unei tensiuni electrice o reprezintă polaritatea. aparatele de măsură comerciale o detectează automat, afișând semnul corespunzător pe ecran. în cazul Arduino, aplicarea unei tensiuni electrice negative – potențialul conexiunii analogice mai jos decât potențialul de referință 0V (GND) – va distruge circuitul de intrare al terminalului respectiv.

o metodă pentru evitarea acestei situații este simularea unui potențial de referință virtual mai sus, în așa fel încât aplicarea unei tensiuni negative să nu coboare potențialul terminalului de intrare analog sub nivelul 0V (GND). poți stabili un astfel de potențial folosind un divizor rezistiv, care să înjumătățească tensiunea de alimentare de 5V pentru a crea un punct de potențial 2,5V față de 0V, care va fi folosit ca terminal negativ al multimetrului pe care-l vei construi, în timp ce terminalul pozitiv va fi una dintre intrările analogice ale Arduino.

Arduino - Floating Voltage

notă
dezavantajele acestui artificiu sunt consumul suplimentar de energie: pentru a obține un potențial stabil, curentul care trece prin divizor trebuie să fie relativ mare; o variantă posibilă îl reprezintă utilizarea unui divizor alcătuit din doi rezistori de 220 de Ω, asigurând un curent de aproximativ 10mA.
un al doilea dezavantaj de care trebuie ținut cont este că intervalul de măsură al multimetrului a fost translatat cu 2,5V. mai exact, a devenit -2,5V – +2,5V. în aceste condiții formulele trebuie ajustate corespunzător – introducând termenul de translație de -2,5V, iar tensiumea maximă care poate fi aplicată la intrare nu poate depăși 2,5V. în cazul în care o tensiune mai mare este necesară, se poate aplica metoda divizorului rezistiv de mai sus.

ultima situație pe care vrei să o ai acoperită este măsurarea tensiunilor mult mai mici. Arduino pune la dispoziție două metode pentru rezolvarea problemei, una software și una hardware. varianta software nu implică componente suplimentare. folosind funcția analogReference poți seta capătul superior al intervalului în care se poate afla tensiunea necunoscută.

void setup() {
  analogReference (INTERNAL); // <- capatul intervalului devine 1,1V
}

lungimea unui sub-interval de măsură devine în această situație 0,001074V transformând formulele pentru derivarea tensiunii electrice în:

void loop() {
  int interval = analogRead (A0);
  float voltage_left = 0.001074 * interval;
  float voltage_center = 0.000537 + 0.001074 * interval;
  float voltage_right = 0.001074 * (interval + 1);
}

dacă ai nevoie să măsori tensiuni mult mai mici, poți apela la varianta unei referințe fizice. folosind un divizor rezistiv cu ieșirea conectată la terminalul AREF poți stabili valoarea tensiunii capăt de interval de măsură. activarea acestei referințe externe se face prin apelarea funcției analogReference cu parametrul EXTERNAL.

Arduino - External Referrence

în exemplul din imagine, valorile pentru divizorul rezistiv sunt R1 = 1,8kΩ și R2 = 220Ω și stabilesc capătul intervalului tensiunilor măsurate la 0,544544V în timp ce lungimea sub-intervalul de măsură este de 0,000531V.

void setup() {
  // deoarece am conectat AREF la valoare 5V * 220 ohm / (1800 ohm + 220 ohm)
  analogReference (EXTERNAL); // <- capatul intervalului devine 0,5445V
}
void loop() {
  int interval = analogRead (A0);
  float voltage_left = 0.000531 * interval;
  float voltage_center = 0.000265 + 0.000531 * interval;
  float voltage_right = 0.000531 * (interval + 1);
}

cum măsor curent electric?

deși sunt puțini senzori care convertesc mărimi fizice în curent electric, măsurarea acestuia este importantă, cel puțin prin prisma monitorizării energiei consumate într-un circuit. voi porni de la un exemplu simplu: cât curent consumă un LED?

notă
LED-urile sunt dispozitive semiconductoare care conduc curentul electric cu precădere într-o singură direcție și sunt caracterizate de doi parametrii importanți: căderea de tensiune în conducție directă și curentul direct maxim. căderea de tensiune în conducție directă poate fi înțeleasă simplu ca tensiunea necesară aprinderii LED-ului, orice tensiune mai mică păstrând LED-ul stins, în timp ce orice tensiune mai mare îl va face să lumineze, cu observația că LED-ul va încerca să mențină tensiunea aplicată constantă. acest lucru e imposibil, fiind principala cauză pentru ”arderea” LED-urilor. tensiunea în conducție directă variază în funcție de culoarea LED-ului, de la 1,9V pentru cele roșii, la peste 3V pentru cele albastre și albe.
curentul direct maxim îl reprezintă curentul maxim care poate trece prin LED, atunci când acesta este aprins în așa fel încât durata de viață a LED-ului să fie maximă. spre deosebire de alte dispozitive, LED-urile își variază intensitatea luminoasă direct proporțional cu curentul care le străbate.
din aceste motive, LED-urile vor avea nevoie întotdeauna de un circuit care să limiteze curentul maxim prin circuit. un exemplu este un simplu rezistor înseriat cu acesta.

am în vedere cel mai simplu circuit cu LED: un rezistor R în serie cu un LED, conectate între terminalele GND (0V) și 5V (+5V) ale Arduino.

Arduino - Current Measuring

în mod normal vei conecta un rezistor cu o valoare întâlnită des în astfel de circuite, 220 de Ω. curentul prin circuit va depinde de căderea de tensiune în conducție directă pe LED și va respecta legea lui Ohm:

$$U_{arduino,5V} = U_{LED,direct} + R \times I_{circuit} \\ I_{circuit} = \frac{U_{arduino,5V} - U_{LED,direct}}{R} \\ I_{circuit} = \frac{U_{rezistor}}{R}, U_{rezistor} = U_{arduino,5V} - U_{LED,direct}$$

ultima formulă este cea mai convenabilă, mai ales dacă rezistorul are un terminal conectat la GND (0V), situație în care poți măsura direct căderea de tensiune pe acesta folosind experiența câștigată anterior în măsurarea tensiunii. dacă celălalt terminal al rezistorului este conectat la A0, curentul prin circuit poate fi măsurat direct astfel:

void setup() {
}

void loop() {
  // găsim sub-intervalul în care se află tensiunea pe rezistorul R
  int interval = analogRead (A0);
  // estimăm tensiunea pe rezistor ca fiind centrul sub-intervalului de măsură
  float voltage_rezistor = 0.002441 + 0.004882 * interval;
  // aplicăm legea lui Ohm pentru a afla curentul, direct în A
  float current = voltage_rezistor / 220.0;
}

notă
cu un Arduino nu poți măsura direct curentul electric într-un circuit, având în vedere că intrările analogice ale acestuia funcționează ca niște mici aparate care măsoară tensiunea electrică. în această situație, soluția cea mai la îndemână este conversia curentului în tensiune folosind un simplu rezistor cu valoare cunoscută. variante alternative, care se pot adapta în funcție de situație, sunt utilizarea unor alte fenomene fizice care convertesc curentul electric într-o tensiune sau variația acesteia: efectul Hall, folosit în special pentru izolarea circuitului care va fi măsurat de cel care îl măsoară sau variația curbei de încărcare a unui capacitor cu valoare cunoscută.

cum măsor rezistență electrică?

asemănător cazului anterior al curentului electric, nu poți măsura direct rezistența electrică și va trebui să te bazezi pe formula pe care-am menționat-o des până acum, legea lui Ohm. în cazul în care prin rezistorul necunoscut trece un curent cunoscut, diferența de potențial între terminale va fi direct proporțională cu rezistența electrică. soluția se complică atunci când îți dorești o sursă de curent constant. circuitul electronic care se comportă ca o astfel de sursă e complex și costisitor, metoda fiind folosită în unele aparate din laboratoarele cu bugete serioase. cum nu e cazul, următoarea soluție este o sursă de curent predictibil, pentru care poți aplica legea lui Ohm. vei folosi în acest sens sursa de tensiune constantă a Arduino disponibilă între terminalul 5V și GND (0V) și un rezistor cu valoare cunoscută în serie cu cel necunoscut, acesta din urmă având unul dintre terminale conectat la GND (0V), în timp ce Arduino v-a fi folosit pe post de voltmetru, măsurând prin A0 potențialul conexiunii comune a celor doi rezistori.

Arduino - Rezistence Measuring

$$\begin{cases}U_{constant,5V} = (R_{cunoscuta} + R_{necunoscuta}) \times I_{circuit} \\ U_{comun} = R_{necunoscuta} \times I_{circuit}\end{cases} \Rightarrow \\ R_{necunoscuta} = R_{cunoscuta} \times \frac {U_{comun}}{U_{constant,5V} - U_{comun}} $$

tensiunile electrice din formule pot fi convertite direct în valori numerice obținute prin intermediul Arduino astfel: 5V va fi 1023 în timp ce valoarea lui Ucomun va fi rezultatul aplicării funcției analogRead pentru terminalul A0.

$$R_{necunoscuta} = R_{cunoscuta} \times \frac {N_{analogRead(A0)}}{1023 - N_{analogRead(A0)}} (\Omega)$$

// valoare rezistorului cunoscut, in Ohmi
float R = 100000.0;
void setup() {
}

void loop() {
  // in n_comun citim numarul sub-intervalului de masura
  int n_comun = analogRead (A0);
  // in unele situatii, mai exact atunci cand nu este conectat un
  // rezistor, valoarea lui n_comun va fi 1023, generand o eroare
  // rezultata in urma diviziunii cu zero; utilizand operatorul
  // ternar (denumire pompoasa pentru conditionarea atribuirii)
  // poti verifica daca n_comun e mai mic decat 1023 (mai mare
  // e imposibil sa fie) si in situatia asta vei aplica formula,
  // iar in cazul in care n_comun este 1023, valoarea rezistorului
  // va fi -1 (valoare imposibila fizic, dar reprezentand infinit)
  float rezistenta = n_comun < 1023 ?
    R * (float) n / (1023.0 - n) :
    -1;
}

in micul program anterior, (float) urmat de un identificator de variabilă forțează variabila respectivă să fie interpretată ca fiind de tipul specificat între paranteze. parantezele sunt obligatorii. în ceea ce privește secvența

, aceasta va fi evaluată de Arduino ca fiind valoare1 atunci când condiția este îndeplinită și ca valoare2 în caz contrar.

altfel, vei mai observa declararea unui loc în memorie ca număr real - float, în afara celor două blocuri, setup și loop. declarat în acest fel, R poate fi accesat fără nicio problemă din orice parte a programului, în limbaj tehnic numindu-se variabilă globală.

cum măsor capacitatea electrică?

în cazul multimetrelor comerciale, măsurarea capacității electrice se găsește la modelele mai costisitoare. cu ajutorul dispozitivelor hardware pe care un Arduino le conține, capacitatea poate fi măsurată relativ facil.

puțină teorie. formula care vine în ajutor este chiar definiția capacității electrice, ca fiind raportul între sarcina stocată într-un capacitor și diferența de potențial între terminalele acestuia, o formulă ușor de reținut fonetic:

$$Q = C \times U \\ \frac{dQ}{dt} = I$$

unde:
Q este sarcina electrică exprimată în Coulombi; poate puțin abstractă, însă cu o proprietate extrem de interesantă: viteza de variație a sarcinii electrice este chiar curentul electric;
C este capacitatea electrică a capacitorului și se măsoară în Farazi (Farad, la singular); în practică, subunitățile sunt frecvent întâlnite, în timp ce valori de ordinul Farazilor sunt specifice supercapacitorilor;
U este diferența de potențial între terminalele capacitorului, exprimată în volți;
t este timpul, măsurat în secunde, iar;
I este curentul, măsurat în amperi; așa cum îmi atrăgea atenția o studentă (profesoară de fizică), în mod obișnuit, în limbajul de lemn al manualelor școlare, se folosește pentru această mărime litera i (mic). nu-mi plac convențiile, așa că peste tot, curentul este notat cu I (mare, de la intensitate imporantă).

dacă în paralel cu un capacitor necunoscut încărcat la o diferență de potențial inițială U0 conectezi un rezistor R, cu valoare cunoscută, capacitorul se va descărca prin intermediul rezistorului, transformând energia stocată în căldură.

Arduino - Capacitance Measuring

ecuațiile implicate sunt următoarele:

$$ \begin{cases} Q(t) = C \times U(t) \\ U(t) = R \times - \frac{dQ(t)}{dt} \\ U(t=0) = U_{0} \end{cases} \Rightarrow \begin{cases} U(t) = -RC \times \frac{dU(t)}{dt} \\ U(t=0) = U_{0} \end{cases} $$

ultima formulă este o ecuație diferențială ordinară, pentru care e suficient să găsim o soluție particulară. dacă am reușit asta, soluția va fi unică, mulțumită teoremei Cauchy-Lipschitz. semnul minus din a doua ecuație îmi spune că nu am nicio sursă de tensiune în circuit și că rezistorul consumă sarcina din capacitor. interpretarea asta naivă, când e formalizată are denumirea de lege a lui Kirchhoff. având în vedere că în stânga egalului avem funcția, iar în dreapta derivata ei multiplicată cu o constantă, o soluție posibilă este o funcție exponențială, de forma eαt + β.

$$ e^{\alpha t + \beta} = -RC \frac{d}{dt} (e^{\alpha t + \beta}) \Rightarrow \\ e^{\alpha t + \beta} = -RC \alpha e^{\alpha t + \beta} \Rightarrow \alpha = -\frac{1}{RC} $$

parametrul β poate fi dedus din condiția inițială a diferenței de potențial

$$ U(t=0) = U_{0} \Rightarrow e^{-\frac{1}{RC}(t=0) + \beta} = U_{0} \Rightarrow \beta = ln (U_{0}) \\ U(t) = U_{0} e^{-\frac{1}{RC}t} $$

Capacitor Discharge

ultima formulă vine și cu ideea măsurării capacității necunoscute: încărcarea capacitorul până la o tensiune cunoscută, apoi descărcarea acestuia pentru un timp determinat t1, urmată de măsurarea diferenței de potențial între terminalele capacitorului, U1.

$$ U_{1} = U_{0} e^{-\frac{1}{RC}t_1} \Rightarrow C = \frac{t_1}{R}\frac{1}{ln(\frac{U_{0}}{U_{1}})} $$

sau folosind identificatorul sub-intervalului de măsură obținut folosind analogRead și luând în considerare că U0 va fi 5V, formula devine:

$$ C = \frac{t_1}{R}\frac{1}{ln(\frac{1023}{N_{analogRead(A0)}})} $$

terminalele Arduino sunt flexibile și pot fi configurate în funcție de nevoie, chiar în timpul rulării programului. mai exact, poți configura terminalul A0 ca ieșire și să-i stabilești un potențial de 5V față de GND, urmat de configurarea acestuia ca intrare și citirea tensiunii după descărcare.

// timpul de asteptare pentru descarcarea capacitorului, in microsecunde
long t_1 = 100000;
// valoarea rezistorului de descarcare, in ohmi
float rezistenta = 100000.0;

void setup() {
}

void loop() {
  // stabilesc terminalul A0 ca terminal de iesire
  pinMode (A0, OUTPUT);
  // conectam terminalul A0 la +5V pentru a incarca capacitorul
  digitalWrite (A0, HIGH);
  // astept ~1s pentru a fi siguri de incarcarea acestuia
  delay (1000);
  // stabilesc terminalul A0 ca terminal de intrare
  pinMode (A0, INPUT);
  // astept t_1 microsecunde pentru a descarca capacitorul prin rezistorul cunoscut
  // am ales microsecunde, deoarece in formula, capacitatea este direct proportionala
  // cu timpul, iar capacitatile obisnuite sunt de ordinul micro-farazilor
  delayMicroseconds (t_1);
  // citesc identificatorul sub-intervalului de masura
  int n = analogRead (A0);
  // in cazul in care n este 0, adica in acest timp capacitorul s-a descarcat de tot,
  // capacitatea este 0, altfel folosesc formula
  float capacitate = n > 0 ?
    ((float) t_1 / rezistenta) * log (1023.0 / n) :
    0;
}

notă
scala de măsură a capacității nu mai este liniară de această dată, majoritatea valorilor aflându-se în primii 20% din lățimea intervalului de măsură. parametrul pe care-l poți controla atunci când măsori capacități este raportul între timpul de descărcare și valoarea rezistorului de descărcare. cu ajutorul acestui raport poți stabili o scală potrivită valorilor pe care urmează să le măsori.

pentru a vedea cum sunt distribuite valorile măsurate în funcție de rezultatul aplicării analogRead am folosit GNU Octave.

Capacity vs AnalogRead

n = 5:10:1000; # creez un vector cu valori consecutive intre 5 si 1000, din 10 in 10.
plot(n,1./log(1023./n),'+r') # desenez graficul formulei in raport cu n, folosind + si culoarea rosie (r)
xlabel('analogRead(A0)') # pun legenda pentru axa ordonatelor
ylabel('capacitate(uF)') # pun legenda pentru axa absciselor
grid on # afisez un caroiaj pentru observarea mai simpla a valorilor
text (50,31,'max(capacitate) = 31.4660 uF') # afisez un text la pozitia 50 (ordonata) si 31 (abscisa)
text (50,32,'min(capacitate) = 0.1443 uF')

și totuși, cum citesc datele?

deja apreciez că ai citit până aici. a fost lung, dar cred că a meritat. tot ce-am făcut a fost să-ți arăt cum poți măsura, însă fără a putea citi undeva valoarea măsurată. pentru a putea face acest lucru, Arduino pune la dispoziție o conexiune care poate fi accesată prin intermediul cablului USB, interfața serială. așa cum îi spune și numele, prin intermediul ei poți trimite și recepționa secvențial biți. circuitele au de obicei nevoie de 3 fire pentru a putea face acest schimb de informații: unul comun (GND), unul prin care trimit date (TX) și unul prin care recepționează date (RX). pe plăcuța Arduino există un mic circuit care convertește semnalul USB în cele două de care are nevoie Arduino, RX și TX. semnalele sunt disponibile la terminalele digitale 0 (RX) și 1 (TX). viteza de transmitere a informațiilor poate varia între 1200 și 115200 de caractere pe secundă. în cele mai multe cazuri, recomand 9600 ca viteză de comunicație. și calculatorul și Arduino trebuie configurate cu aceeași viteză pentru a putea comunica.

în cele ce urmează vei folosi doar partea prin care Arduino poate trimite date către calculator. bucata de cod care trimite datele din oricare dintre programele de mai sus către calculator este următoarea:

void setup() {
  Serial.begin (9600);
}

void loop() {
  // aici vine codul programului de masura
  // ...
  // urmat de:
  // trimiterea catre interfata seriala a valorii, urmata de un sfarsit de rand
  Serial.println (valoare);
  // si o mica pauza de 1s sa poti citi informatiile mai usor
  delay (1000);
}

instrucțiunile folosite mai sus sunt Serial.begin care inițializează conexiunea serială și stabilește viteza de comunicare care fiind 9600 de caractere pe secundă și care în majoritatea situațiilor trebuie să fie prezentă în blocul setup. instrucțiunea Serial.println care trimite prin interfața serială parametrul dat urmat de un sfârșit de linie, pentru creșterea lizibilității.

ultimul pas e citirea valorii recepționate prin apăsarea butonului care deschide programul de monitorizare al interfeței seriale, în care se pot citi direct valorile:

Arduino - Serial Monitor

bogdan » arduino: termometru

09:21 am on Nov 7, 2018 | #more | tags:

în urma rugăminții profesorului Stamatin, de câțiva ani țin un curs la Facultatea de Fizică din Măgurele. dacă inițial numele «modelare și simulare» ascundea ecuații matematice și metode numerice, recent am înlocuit diferențialele cu Arduino, în ovațiile celor câtorva studenți care frecventează cursul. dotările limitate m-au făcut să devin creativ cu materialele de curs, iar rezultatul mi s-a părut suficient de interesant pentru a-l reproduce aici. așa că:

temperatura este una dintre mărimile fizice pe care o conștientizezi imediat: e prea frig afară, e prea fierbinte supa, oare ai febră? pe lângă conștientizarea acestei mărimi, este foarte simplu să achiziționezi un termometru cu care să poți cuantifica aceste senzații. dar unde e farmecul dacă nu e făcut de tine și nu poți înregistra periodic datele pentru a urmări procesele în timp real? în cele ce urmează îți voi prezenta o variantă de termometru pe care o poți realiza cu Arduino.

termistor

un termistor este un dispozitiv electronic în care temperatura modifică modul în care conduce curentul electric: dacă temperatura crește, rezistența pe care acesta o opune trecerii curentului electric se micșorează și invers. un Arduino nu poate măsura rezistența direct. dispozitivele cele mai potrivite din interiorul acestuia pentru o astfel de operație sunt convertoarele analog-digitale, care transformă o tensiune într-un număr. mai exact, pentru fiecare 0,004882V aplicați la intrare, Arduino va înregistra câte o unitate, în așa fel încât pentru 0V va înregistra 0, iar pentru 5V numărul 1023, variația fiind liniară (ex. 1,5V → 307, 3,3V → 676). acest lucru nu te ajută prea mult direct, mărimea care variază cu temperatura fiind rezistența dispozitivului. ajutorul vine din partea legii lui Ohm:

$$U = R_{termistor} I$$

unde:
U este tensiunea electrică la bornele termistorului, în volți (V),
Rtermistor este rezistența acestuia, în ohmi (Ω), iar
I este curentul care trece prin circuit, în amperi (A).

Arduino pune prin conectorii săi mai multe tensiuni pe care le poți utiliza ca referință: 3,3V (3V3), 5V sau Vin. cum Arduino poate măsura tensiuni între 0 și 5V, 3,3V e o tensiune prea mică față de capătul intervalului, pierzând astfel din precizie, Vin poate fi cu mult peste cei 5V și are și dezavantajul că nu este stabilă, rămânând astfel opțiunea 5V.

notă
3,3V poate fi folosit destul de ușor, conectând un fir între terminalul AREF și 3,3V, stabilind în acest fel capătul intervalului la valoarea 3,3V. acest lucru poate fi făcut cu orice sursă de tensiune, cuprinsă între 0 și 5V. trebuie să ții cont însă, că valoarea unei unități se modifică corespunzător. în cazul 3,3V, o unitate va însemna 0,003222V (ex. 1,5V → 465, 3,3V → 1023).

alegând U = 5V, în legea lui Ohm rămân totuși două necunoscute, rezistența termistorului și curentul prin circuit. pentru curent însă putem să aplicăm încă o dată legea lui Ohm, introducând în circuit un rezistor cu valoare cunoscută, în serie cu termistorul. tensiunea la bornele acestui rezistor de referință este direct proporțională cu curentul prin circuit, tensiune pe care o poți măsura direct folosind Arduino.

Simple Thermometer Animation

fie Rreferință valoarea în ohmi a rezistorului de referință și cu Ureferință valoarea măsurată cu ajutorul Arduino:

$$\begin{cases}5V = (R_{termistor} + R_{referinta}) I \\ U_{referinta} = R_{referinta} I\end{cases} \Rightarrow \\ R_{termistor} = R_{referinta} (\frac{5V}{U_{referinta}} – 1)$$

dependența de temperatură a rezistenței termistorului este dată de ecuația Steinhart-Hart, puțin prea complexă pentru nevoi obișnuite. drept urmare îți recomand să folosești ecuația beta, o formă simplificată a ecuației anterioare, dar utilizată de producători în caracterizarea termistorilor comercializați:

$$\beta = \frac{ln(R_{termistor}) – ln(R_{25})}{\frac{1}{T} – \frac{1}{T_{25}}}$$

ecuația anterioară descrie dependența de temperatura absolută T, în Kelvin, a rezistenței termistorului Rtermistor, în ohmi, folosind trei constante: R25, în ohmi, care este rezistența termistorului la 25°C – de altfel și valoarea sub care termistorul se comercializează, T25, în Kelvin, fiind temperatura absolută care corespunde 25°C, adică 298,15K și β care este o constantă proprie fiecărui termistor și care se măsoară tot în Kelvin.

ecuația anterioară poate fi aranjată într-o formă mai prietenoasă pentru calculul direct al temperaturii, cu mențiunea că temperatura obținută se măsoară în Kelvin, astfel:

$$T = \frac{1}{\frac{1}{\beta}ln(\frac{R_{termistor}}{R_{25}}) + \frac{1}{T_{25}}}$$

următorul pas în rezolvarea problemei este identificarea constantelor lipsă. pentru a determina facil aceste constante, îți recomand să achiziționezi termistorul dintr-o sursă care pune la dispoziție și datele de catalog. la curs am ales un termistor cu valoarea R25 de 100KΩ. raționamentul e simplu: 100KΩ deoarece puterea disipată prin trecerea curentului electric prin termistor nu-l va încălzi suficient pentru a afecta măsurătorile, iar în foaia de catalog vei găsi direct valoarea lui β. pentru termistorul pe care l-am ales, β=4600K.

Termistor Beta Characteristic

notă
pentru rezistorul de referință am ales o valoare egală cu R25. raționamentul e simplu, atunci când rezistenețele sunt egale, tensiunea în punctul median este jumătate din tensiunea de alimentare, plasând astfel temperatura de 25°C în centrul scalei. din cauza neliniarității funcției de conversie, îmi convine să am această valoare situată central deoarece este o valoare de interes pentru activitatea umană și măsurătorile din vecinătatea ei vor avea o precizie mai mare. în general, e bine să aleg rezistorul de referință în așa fel încât temperatura medie a intervalului de interes să corespundă jumătății tensiunii de alimentare.

programare

în acest moment ai toate informațiile necesare pentru a putea scrie un mic program Arduino care să citească temperatura cu ajutorul unui termistor conectat în configurația descrisă mai sus. pentru început, orice program Arduino conține o funcție setup și o funcție loop.

conținutul funcției setup este rulat de Arduino atunci când acesta este inițializat, fie după reset, fie atunci când este alimentat, o singură dată. în această funcție se trec de obicei instrucțiuni pentru a inițializa perifericele Arduino. în cazul de față, convertorul analog-digital care poate măsura tensiuni este inițializat automat.

funcția loop este cea care ne interesează aproape întotdeauna. proprietatea care o face interesantă este că atunci când lista de instrucțiuni pe care le conține a fost epuizată, loop se va reseta și o va lua de la început. Arduino va face acest lucru până când este apăsat butonul reset, se încarcă un program nou sau alimentarea plăcuței este întreruptă.

în fragmentul de cod de mai jos apare și funcția analogRead cu parametrul A0. această funcție primește ca parametru eticheta unuia dintre pinii analogici ai Arduino, de la A0 la A5 și întoarce un număr întreg cuprins între 0 și 1023, număr care este proporțional cu tensiunea aplicată intrării A0. având în vedere că numărul întors este întreg, pentru a forța zecimale în calculele realizate de Arduino, am ales să reprezint toate numerele în format zecimal (”cu virgulă”).

cuvântul cheie float din fața etichetei U_referinta anunță Arduino să rezerve memorie în care să stocheze un număr zecimal care poate fi apelat întotdeauna folosind eticheta U_referinta. același lucru se aplică și pentru R_termistor, T și t. vei observa că eticheta acestor fragmente de memorie ține cont de tipul literelor (mici sau mari), astfel încât T și t vor face referire la fragmente separate, deci valori diferite.

am mai utilizat încă două funcții, log, care corespunde logaritmului natural, luând ca parametru un număr zecimal și întorcând tot un număr zecimal și delay, care suspendă execuția listei de instrucțiuni pentru numărul de milisecunde furnizate drept parametru. dacă nu folosești această funcție, operațiile vor fi efectuate extrem de rapid, furnizând o cantitate mare de date, oarecum irelevantă, mai ales datorită vitezei relativ mici de variație a rezistenței termistorului cu temperatura.

void setup() {
}

void loop() {
  // măsor tensiunea în volți înmulțind valoarea citită prin
  // conectorul A0 cu factorul 0.004882V (= 5V / 1024)
  float U_referinta = 0.004882 * analogRead (A0);
  // din U_referință și valoarea lui R_referință = 100k ohmi
  // calculez R_termistor
  float R_termistor = 100000.0 * (5.0 / U_referinta - 1.0);
  // folosim ecuația temperaturii, în care beta = 4600K și
  // R_25 = 100k ohmi, T_25 = 298.15K și obținem temperatura în
  // Kelvin
  float T = 1.0 /
  (1.0 / 4600.0 * log (R_termistor / 100000.0) + 1.0 / 298.15);
  // pentru a afla temperatura în grade Celsius, scădem din
  // temperatura în Kelvin 273.15
  float t = T - 273.15;
  // fac o pauză de 1 secundă, după care repet instrucțiunile
  delay (1000);
}

micul program de mai sus poate fi compilat și încărcat pe plăcuța ta Arduino folosind Arduino IDE. conectezi Arduino prin cablul USB la calculator și aștepți ca sistemul de operare să instaleze automat uneltele pentru conectare. apoi deschizi aplicația Arduino și vei alege utilizând meniul Tools → Boards → modelul de Arduino pe care îl ai și folosind meniul Tools → Port → portul la care ai conectat plăcuța. te prinzi ușor despre ce port e vorba. dacă nu, le poți încerca fără probleme pe toate, până reușești.

în fereastra care s-a deschis, copiezi codul de mai sus, sau mai bine, îți recomand să-l scrii de mână. poți sări peste liniile care încep cu // și sunt colorate cu albastru. ele reprezintă comentarii și nu influențează programul. după ce ai terminat, vei apăsa butonul Verify, așteptând ca în bara de stare a ferestrei să apară cuvintele Done compiling.

Arduino - Verify - Upload

în situația în care au apărut erori, verifică în ordine următoarele lucruri:

  • ai pus ; (punct și virgulă) după fiecare instrucțiune? din experiența cu studenții, e de departe cea mai frecvent întâlnită eroare;
  • fiecare paranteză deschisă, fie că este paranteză rotundă sau acoladă, trebuie să se și închidă la un moment dat, fix ca la matematică, în ordinea inversă deschiderii lor. adică {…(…)…} este corect, în timp ce sunt greșite: {…(…}…), {…(…)…, {…)…}
  • felul literelor contează mult, așa că verifică dacă ai scris cu litere mari și mici ca în exemplul de mai sus; etichetele, cum sunt U_referinta, R_termistor, T și t le poți modifica după plac, cu singura mențiune să le modifici pe peste tot;
  • cu excepția liniilor cu comentarii, în rest nu ai voie să folosești diacritice; știu, nu e așa comun, dar am întâlnit și eroarea asta;

Arduino Done Compiling

ultimul pas este cel de încărcare al programului pe plăcuța Arduino, apăsând butonul Upload. în caz de erori, cele mai întâlnite sunt:

  • nu ai selectat corect portul la care este conectat Arduino;
  • nu ai selectat corect tipul de plăcuță Arduino; pentru a te asigura, tipul plăcuței este scris pe ea, nu ai cum să greșești;
  • portul USB la care ai conectat plăcuța nu funcționează corect și va trebui să alegi altul;
  • cablul USB nu este de calitate și va trebui să-l schimbi sau să folosești unul mai scurt;

note

  • în jargonul programatorilor, loop și setup poartă denumirea de proceduri, pentru că nu returnează nimic. cuvântul cheie void care alcătuiește definiția unei funcții specifică fix acest lucru: că respectiva bucată de cod întoarce ”vid” (nimic). prefer să folosesc denumirea de funcție, care provine din matematică, pentru a simplifica asimilarea noțiunilor.
  • în teorie funcția log are nevoie de o bibliotecă de funcții să funcționeze. din fericire, Arduino știe să o adauge implicit, așa că micul program va funcționa fără probleme așa cum este scris.
  • în ceea ce privește tipul de variabile pe care lucrează implicit log, care se numește double, pentru majoritatea plăcuțelor Arduino, acesta este doar un sinonim pentru float. chiar dacă nu ar fi așa, Arduino se ocupă de conversia implicită între cele două formate.
  • spațiile nu sunt relevante, însă ele asigură lizibilitate programului scris, așa că dacă ți-e lene, le poți omite.

lcd

până acum, Arduino știe ce temperatură măsoară, însă o ține pentru el. pentru a o putea afișa, are nevoie de un dispozitiv extern, cum ar fi un ecran LCD cu 2 rânduri a câte 16 caractere, foarte des întâlnit (și ieftin). în plus, mai ai nevoie de un mic potențiometru semiregrabil necesar în ajustarea contrastului, cu valoarea de 10KΩ, o rezistență de 220 de Ω, câteva fire de conexiune mai lungi, colorate și o plăcuță pentru experimente (breadboard). tot ce ai de făcut în continuare pe partea fizică este să replici construcția din desenul următor, după ce ai deconectat Arduino de la portul USB:

Arduino Thermometer with LCD

sfatul meu este să începi cu firele roșii și negre (alimentarea), plasând apoi rezistența de 100KΩ, cea de 220 de Ω, termistorul și potențiometrul semiregrabil pe plăcuța pentru experimente, urmate de firele mov, galben, portocaliu și roz, iar într-un final de cele verzi. verifici de două ori așezarea firelor și conexiunile, ții degetele încrucișate și conectezi din nou Arduino la portul USB. nu-ți face griji, portul USB este protejat în caz de probleme, așa că nu ai ce strica la calculator. un semn bun, că totul merge, îl reprezintă luminarea ecranului LCD. ajustând potențiometrul semiregrabil, ar trebui să vezi la unul dintre capete 2 rânduri cu câte 16 pătrățele negre alcătuite din pixeli, pe ecran. dacă nu funcționează, verifică din nou conexiunile.

vei modifica acum micul program de mai sus pentru a include ecranul LCD folosind biblioteca inclusă în aplicația Arduino, LiquidCrystal.h. aceasta definește un tip de obiect LiquidCrystal care poate fi folosit pentru a controla ecranul LCD. pentru început, vei ințializa obiectul dându-i o denumire și specificând conexiunile către Arduino. pentru a inițializa ecranul, vei adăuga instrucțiunea de inițializare a acestuia în funcția setup: lcd.begin. inițializarea se face specificând dimensiunile ecranului. Arduino știe prin intermediul LiquidCrystal.h să comunice cu ecrane de mai multe dimensiuni.

// am nevoie de o bibliotecă care știe să comunice cu ecranul LCD
#include <LiquidCrystal.h>
// inițializez un obiect de tip LiquidCrystal pe care îl denumesc
// lcd, căruia îi spun la ce conectori Arduino am conectat firele
// 12 = galben, 11 = portocaliu, 5, 4, 3, 2 = cele 4 fire verzi
LiquidCrystal lcd (12, 11, 5, 4, 3, 2);

void setup() {
  // inițializez ecranul și îi spun că are 2 rânduri cu 16 caractere
  lcd.begin (2, 16);
}

după ce ai calculat temperatura, vei curăța ecranul pentru a te asigura că nu e nimic pe el folosind lcd.clear. vei muta cursorul pe coloana 0, linia 0 (colțul stânga-sus) folosind lcd.setCursor, cu parametri coloană (de la 0 la 15) urmat de linie (de la 0 la 1), după care vei tipări diferite lucruri, în ordine, folosind lcd.print. lcd.print poate primi ca parametri șiruri de caractere delimitate de ghilimele, numere zecimale sau întregi, dar și caractere speciale, prin codul lor, cum este simbolul °, dar pe care trebuie să-l diferențiezi de un număr întreg obișnuit, folosind sintaxa (char). această operație se numește conversia tipului (cast în engleză) și îi spune Arduino să trateze numărul 223 ca un caracter (char).

notă
lcd este o etichetă pe care am ales-o eu în vederea accesării obiectului LiquidCrystal. dacă ai altă preferință, cum ar fi ecran, o poți folosi fără probleme. trebuie să ții cont că funcțiile apelate se vor modifica corespunzător: lcd.begin devine ecran.begin, lcd.clear devine ecran.clear, lcd.setCursor devine ecran.setCursor și lcd.print devine ecran.print. acest tip de funcții, care depind de obiectul folosit, în jargonul programatorilor se numesc metode și se folosesc de starea internă a obiectului de care sunt anexate pentru a-și îndeplini rolul. fără inițializarea unui astfel de obiect, ele nu pot fi folosite, așa că să nu uiți bucata anterioară funcției setup în care alegem o etichetă pentru un obiect de tip LiquidCrystal.

void loop() {
  // ...
  // bucata de până aici rămâne neschimbată
  float t = T - 273.15;
  // dacă e ceva scris pe ecranul LCD, îl șterg
  lcd.clear ();
  // îi spun ecranului LCD că vreau să scrie începând cu colțul stânga-sus
  // primul 0 îl reprezintă coloana (0-15), al doilea rândul (0-1)
  lcd.setCursor (0,0);
  // pornind de la cursor, afiseaza T = 
  lcd.print ("T = ");
  // apoi temperatura în grade Celsius
  lcd.print (t);
  // urmată de simbolul grad
  lcd.print ((char) 223);
  // și apoi de litera C
  lcd.print ("C");
  // fac o pauză de 1 secundă, după care repet instrucțiunile
  delay (1000);
}

după încărcarea programului pe plăcuța Arduino, singurul lucru pe care îl mai ai de făcut este să ajustezi contrastul în așa fel încât literele și cifrele să fie lizibile.

bogdan » arduino: lucruri necesare

05:24 pm on Oct 31, 2018 | #more | tags:

am descoperit Arduino în 2009, într-o reclamă Google. ce m-a uimit e că pe o mică plăcuță am regăsit ceva asemănător primului calculator pe care l-am văzut în viața mea, CIP-03, o clonă de ZX-Spectrum. un calculator care mi-a gravat în minte așteptările pe care trebuie să le am de la o mașină de felul ăsta: să pot să o programez și să interacționeze cu lumea din exterior. Arduino le face pe-amândouă, lucru pentru care l-am inclus în cursul meu de modelare și simulare pe care-l țin periodic la Facultatea de Fizică. recent, am primit la curs întrebarea: ce-ar însemna un set minim cu care să pot experimenta cu Arduino? așa că răspunsul vine în continuare.

arduino

Arduino UNO R3 – prefer varianta cu USB-type-B (conector USB pentru imprimantă) și AtMega328-PU (cip cu piciorușe într-un soclu); raționamentul e simplu: așa cum am văzut în propriul buzunar, când faci experimente cu Arduino poți să-l strici; un cip separat e numai o fracțiune din preț și e majoritar componenta care se strică cel mai ușor; alt motiv este că în timp, vrei să incluzi Arduino în proiecte mai mici și mai statice, iar un Arduino cu soclu îți permite să programezi mai multe cipuri fără bătăi de cap. când ai avansat, poți trece la variantele cu cip miniatură lipit, în diferite forme, dar primul Arduino ar trebui să fie UNO R3 clasic; (29 de lei, 30 de lei, 146 de lei)
LED-uri – pentru că primul lucru pe care-l vei face cu el e să aprinzi luminițe; e simplu și oferă satisfacții imediate; recomand LED-uri de 5mm, cât mai multe, cât mai colorate (49 de lei); câteva IR nu strică (3,5 lei / 5 bucăți);
fire de conexiune – Arduino e făcut să folosească fire de conexiune; dacă LED-urile se pot pur și simplu ”înfige” în sloturile Arduino, celelalte componente sunt mult mai greu de conectat așa că două seturi de fire de conexiune (un set are 10 fire), unul cu pini la ambele capete (”tată-tată”), celălalt cu pini și socluri (”mamă-tată”) sunt valoroase (3,5 lei / 10 bucăți / 15 cm / tată-tată și 4,5 lei / 10 bucăți / 15 cm / tată-mamă);
placă de conexiune (breadboard) – pentru a putea crea mici circuite ai nevoie de o placă de conexiune; recomand una medie (half-size), cu linii pentru alimentare – acestea sunt linii perpendiculare pe rândurile conectate ale plăcii, care pot fi folosite pentru alimentarea circuitului (5 lei, 5 lei, 33 de lei (calitate mai bună));
ecran LCD – după ce ai aprins LED-uri și te-ai jucat puțin cu interfața serială, vei fi uimit că poți scrie mesaje pe un mic ecran LCD; îl recomand pe cel ieftin, cu conexiune paralelă; necesită în plus un potențiometru de 10KΩ și destul de multe fire, dar are avantajul că e ieftin (11 lei, 19 lei, 35 de lei); o variantă mai bună e versiunea I2C a acestuia, dar ceva mai scumpă (18 lei, 29 de lei, 76 de lei);
butoane – știi să afișezi lucruri, deci să obții informație din Arduino; e momentul să și introduci și ce e cel mai simplu decât să conectezi butoane cu contact momentan la el (push-buttons); un simplu meniu are nevoie de minimum 3 butoane: sus/jos pentru a naviga în el și un buton pentru a selecta opțiunea (4,5 lei / 3 bucăți, 6 lei / 3 bucăți);
potențiometre – când butoanele nu te mulțumesc, vei vrea să folosești un potențiometru; la un Arduino poți conecta între 1 și 6 (9 lei / 6 bucăți, 15 lei / 3 bucăți);
rezistori – Arduino limitează curentul prin terminalele sale, însă de multe ori ai nevoie fie să limitezi curentul mai mult, fie să le folosești pentru a forța anumite intrări într-o poziție (pull-up, pull-down) fie pentru a limita tensiunile analogice; valorile pe care le recomand sunt 470Ω (0,6 lei), 1KΩ (0,6 lei), 4.7KΩ (0,6 lei), 10KΩ (0,6 lei), 100KΩ (0,6 lei) și 1MΩ (0,6 lei). câte 10 din fiecare, pentru că oricum sunt ieftine;
punte H – una dintre aplicațiile cele mai spectaculoase ale Arduino este aceea de a face lucrurile să se miște; iar pentru a putea comanda motoare folosind Arduino, ai nevoie de o punte H; de preferat dublă pentru că e foarte ușor să controlezi mișcarea unui robot utilizând două motoare (10 lei);
tranzistori MOS-FET – de la LED-uri mici la LED-uri mai mari e un singur pas, așa că MOS-FET-urile sunt extrem de utile pentru controlul consumatorilor mari de curent; fie ca vrei să creezi o mini-seră încălzită sau să controlezi un element Peltier pentru a-ți răci băutura preferată, un MOS-FET e ideal; numărul minim recomandat este 2 (5 lei / 2 bucăți);
relee – când vezi că poți controla atâtea lucruri în jurul tău, te gândești cum poți trece la nivelul următor: poate să aprinzi o veioză? un releu te ajută să separi Arduino de tensiunile periculoase (priză, de cele mai multe ori). 2 sunt suficiente, de preferat cu tranzistorii și diodele necesare pentru control; dacă nu, se mai trec în listă câte un tranzistor și o diodă de curent mic pentru fiecare releu (7 lei / 2 bucăți, 19 lei / 2 bucăți);
conector baterie – la un moment dat proiectele vor deveni independente de interfața USB; în această situație, un conector de la o baterie de 9V la borna de alimentare a Arduino devine esențial (6 lei); o variantă mai bună, este obținearea unei cutii pentru baterii AA minimum 4 (3,5 lei), deși recomand 6 (5 lei) cu conector pentru alimentare – deoarece Arduino consumă destul de mult curent, iar o baterie de 9V are o capacitate relativ mică;

câteva tipuri de senzori

fotorezistori – așa cum îi spune numele, un fotorezistor își variază rezistența cu lumina incidentă: cu cât e mai multă lumină, cu atât rezistența e mai mică; poate fi extrem de util pe post de ”ochi” pentru un mic proiect Arduino; doi sunt utili (3,9 lei / 2 bucăți, 4 lei / 2 bucăți);
termistor – pe lângă lumină, temperatura e o altă mărime fizică fundamentală care poate fi convertită ușor în rezistență; un termistor este o rezistență care crește atunci când e frig și scade când e cald; recomand un termistor cu valoarea de 100KΩ; unul e suficient (3 lei);
microfon – poate nu la fel de facil de utilizat, însă cu siguranță spectaculos, un senzor util este cel pentru sunet; recomand un microfon cu electret și amplificator integrat, pentru a putea trimite semnalul acestuia direct, către un Arduino; util în proiectele în care vrei ca Arduino să ”simtă” muzica (36 de lei);
senzor de distanță – aici sunt mai multe opțiuni: optic sau cu ultrasunete; îl recomand pe cel din urmă, având o rază mai mare de acțiune, cele optice putând fi ușor replicate cu simple leduri (20 de lei, 25 de lei, 29 de lei);

câteva tipuri de elemente de control

difuzor / buzzer – după semnale optice, a doua metodă de a obťine feedback de la Arduino sunt sunetele; conectat direct la unul dintre piciorușele Arduino, un mic difuzor poate fi elementul care poate face proiectul tău mai interesant (2 lei, 6 lei, 10 lei);
servomotoare – sunt mici motoare care au inclus un circuit de feedback și cu ajutorul cărora poți interacționa prin mișcări precise cu lumea reală; recomand două, în special utile pentru a poziționa un senzor (ultrasonic sau optic) cu două grade de libertate (pe suprafața unei sfere) pentru, spre exemplu, un radar 3D (40 de lei / 2 bucăți, 46 de lei / 2 bucăți, 58 de lei / 2 bucăți);
motoare – sunt elementele care asigură autonomie unui robot controlat de Arduino; recomand două, cu reductor și roată inclusă (24 de lei / 2 bucăți);

câteva elemente esențiale, dar care pot fi achiziționate ulterior

fire de conexiune pentru breadboard (jumperi) – deși nu sunt necesare, sunt extrem de utile atunci când dezvolți circuite complexe folosind o placă pentru conexiuni; permit evitarea interferențelor parazite cauzate de firele prea lungi (15 lei, 25 de lei, 32 de lei);
un programator ICSP – am luat unul atunci când am stricat primul Arduino; e util pentru reprogramarea fără bătăi de cap a bootloader-ului pe cip și nu numai (60 de lei, 20 USD – include convertor USB-serial); poate fi simulat cu un alt Arduino;
un multimetru – nu neapărat necesar, este util în depanarea circuitelor și identificarea mai ușoară a problemelor: fie e un fir întrerupt, fie o tensiune nu e suficientă, fie un curent e prea mare; multimetrul identifică cu ușurință aceste probleme; ca să nu mai vorbim de rezistorii cu peliculă metalică pe care eu nu disting culorile (55 de lei, 61 de lei); poate fi emulat cu puțină îndemânare cu un Arduino;
convertor USB-serial – nu e esențial, dar incredibil de util pentru reprogramarea proiectelor care folosesc variante miniaturizate de Arduino (15 lei, 39 de lei, 75 de lei – include ICSP); poate fi emulată cu un Arduino;
o sursă coborâtoare/ridicătoare de tensiune – pentru proiectele mobile e o necesitate; Arduino conține un stabilizator de tensiune liniar, ieftin și robust, dar lipsit de eficiență; un astfel de circuit permite alimentarea de la acumulatori; recomand o variantă care să poată susține 5V la cel puțin 1.5A (30 de lei, 30 de lei);

raspberry pi

Raspberry PI 3 – e un mic calculator pe o plăcuță de mărimea unui card bancar; dacă Arduino e echivalentul unui ZX-Spectrum, Raspberry PI 3 e un fel de Pentium 3; adică destul de puternic pentru a vedea filme și a naviga pe internet; mai mult, are 4 porturi USB pentru periferice normale, o mulțime de spațiu de stocare și interfețe de rețea: bluetooth, wi-fi și ethernet; altfel, face cam ce face Arduino, dar cu un sistem de operare obișnuit, care suportă compilator C, limbaje de scripting (PHP, Ruby, Perl, JS) și servere http și ssh (209 lei, 245 de lei, 259 de lei);
RPI-UNO-HAT – produs de echipa din spatele watterott.com, RPI-UNO-HAT este o extensie a Raspberry PI care conține un Arduino împreună cu circuitele necesare interfațării; deși poate fi emulat cu un Arduino și câteva componente discrete, recomand varianta asta pentru simpliatatea în utilizare; poți astfel să construiești lucruri complexe, conectate la internet; RPI-UNO-HAT necesită un mic circuit pentru alimentarea Raspberry PI prin conectorul comun, care în această situație trece în lista de componente obligatorii (16 EUR);

software

Arduino – așa cum îi spune numele e complementul software al plăcuței; cu ajutorul acestuia poți programa o mulțime de plăcuțe compatibile cu Arduino (download: windows, linux, mac os x);
GNU Octave – dacă ești familiarizat cu MatLab, GNU Octave e o variantă open-source a acestuia; altfel, imaginează-ți-l ca pe un calculator foarte avansat care face în primul rând operații cu matrice (download: windows, linux, mac os x); sunt utile pachetele suplimentare io (download) și instrument-control (download);
native script – este o extensie de node.js care permite dezvoltarea de aplicații mobile; foarte util atunci când vrei să conectezi proiectul tăubla telefon (ghid instalare);
Microsoft Visual Studio Code – de departe cel mai bun editor text pentru programatori; chiar dacă e făcut de Microsoft, e open source, rulează cam pe orice platformă și e bun! (download);
Git/GitHub – atât clientul desktop cât și cel de consolă, împreună cu un cont gratuit, pentru a salva și a împărtăși cu toată lumea experimentele tale (download);

bogdan » arduino: conectarea la octave

10:29 pm on Apr 9, 2018 | #more | tags:

în urma rugăminții profesorului Stamatin, de câțiva ani țin un curs la Facultatea de Fizică din Măgurele. dacă inițial numele «modelare și simulare» ascundea ecuații matematice și metode numerice, recent am înlocuit diferențialele cu Arduino, în ovațiile celor câtorva studenți care frecventează cursul. dotările limitate m-au făcut să devin creativ cu materialele de curs, iar rezultatul mi s-a părut suficient de interesant pentru a-l reproduce aici. așa că:

GNU Octave:
GNU Octave este o alternativa gratuită a MathWorks MatLab. ambele fac în mare același lucru pentru utilizatorul de rând: efectuează extrem de eficient operații matematice cu matrice. mai mult, în cele mai multe cazuri, codul scris pentru unul funcționează fără probleme în celălalt. GNU Octave poate fi descărcat de aici.

recomand varianta zip, pentru arhitectura potrivită calculatorului tău cu mențiunea că în cazul în care nu știi ce înseamnă arhitectură, poți alege cu încredere varianta care are în numele fișierului w32. fișierul descărcat este o arhivă de tip zip și necesită dezarhivare. dacă utilizezi Microsoft Windows 10, poți folosi cu încredere utilitarul integrat în Windows Explorer. vei obține un director care conține octave.bat, fișierul pe care trebuie să dai dublu-clic pentru a porni aplicația.

instrument control:
GNU Octave poate comunica cu Arduino prin intermediul interfeței seriale, dar nu o poate face în starea inițială. la fel ca în cazul MatLab, e necesară o bibliotecă externă cu instrucțiuni care să-i permită citirea datelor seriale. cea pe care am utilizat-o în curs se numește instrument control și e disponibilă aici.

biblioteca se instalează ușor, descărcând fișierul și mutându-l în directorul src (de la source) al GNU Octave. în cazul în care directorul nu există, îl poți crea pur și simplu. urmează să pornești GNU Octave și cu ajutorul browserului de fișiere din stânga ferestrei principale, găsești și intrii în directorul src. ultimul pas constă în introducerea următoarei comenzi în consola GNU Octave:

>> pkg install instrument-control-0.3.0.tar.gz

instalarea instrument control durează destul de mult așa că poți să iei o pauză de câteva minute.

read_arduino.m:
pentru citirea interfeței seriale a Arduino am scris o mică bucățică de cod în formatul GNU Octave, read_arduino.m care îți pune la dispoziție o funcție cu ajutorul căreia poți citi datele într-o matrice. presupunem că îmi doresc să citesc tensiunea pe fiecare dintre cele 6 intrări analogice și să îi urmăresc evoluția în timp, la intervale de o secundă.

codul pentru Arduino este următorul:

void setup () {
  Serial.begin (9600); // <-- read_arduino.m suportă doar viteza de 9600 bauds
}

void loop () {
  byte port = 0; // <-- am nevoie de o variabila care specifica numarul portului analog
  while (port < 6) { // <-- cel mult voi citi date de la portul 5
    Serial.print (analogRead (port)); // <-- citesc si trimit valoarea citita catre portul serial
    Serial.print ("\t"); // <-- pentru a separa valorile, folosesc caracterul TAB (\t)
    port = port + 1; // <-- trec la portul urmator
  }
  Serial.print ("\n"); // <-- pentru a separa sirurile de date, folosesc caracterul NEW LINE (\n)
  delay (1000); // <-- aștept o secundă pentru a relua ciclul
}

care ar trebui să producă la fiecare secundă câte o linie cu valori cuprinse între 0 și 1023, corespunzătoare diferenței de potențial între pinul GND și pinii de la A0 la A5.

pentru a citi 10 rânduri conținând cele 6 valori, vei folosi:

>> A = read_arduino ('COM5', 10, 6)
A =

   339   339   326   319   312   324
   328   330   319   313   309   319
   327   329   319   314   310   319
   324   327   317   312   308   318
   323   326   316   311   307   317
   324   327   317   312   309   318
   322   324   314   310   306   315
   323   326   317   312   307   317
   324   327   317   312   308   318
   323   326   316   311   307   317

note de final:
COM5 este portul serial pe care se conectează plăcuța mea Arduino. în cazul tău, acesta va fi cel mai probabil diferit. verifică în Device Manager care este portul corect. read_arduino.m funcționează și pe Linux și pe MAC, însă în locul COM5 vei folosi denumirea portului corespunzătoare platformei. portul serial trebuie să fie liber, drept pentru care amintește-ți ca înainte să rulezi read_arduino să închizi monitorul serial al Arduino. ca în cazul MathWorks Matlab, fișierul read_arduino.m în directorul curent pentru ca funcția să devină accesibilă.

bogdan » arduino: senzor de lumină cu led

11:20 am on Mar 25, 2018 | #more | tags:

în urma rugăminții profesorului Stamatin, de câțiva ani țin un curs la Facultatea de Fizică din Măgurele. dacă inițial numele «modelare și simulare» ascundea ecuații matematice și metode numerice, recent am înlocuit diferențialele cu Arduino, în ovațiile celor câtorva studenți care frecventează cursul. dotările limitate m-au făcut să devin creativ cu materialele de curs, iar rezultatul mi s-a părut suficient de interesant pentru a-l reproduce aici. așa că:

senzorii de lumină domină lumea simțurilor electronice. cu mici modificări, aceștia pot răspunde unei multitudini de întrebări, de la banalul ”e lumină afară?”, la ”ce culoare are un obiect?” sau ”la ce distanță am un obstacol în față?”. la prima vedere funcționează complex: un fragment de siliciu reacționează la lumina incidentă, modificând o mărime electrică. Einstein a luat premiul Nobel pentru explicarea principiului în 1921, deci trebuie să fie complicat. cu toate acestea, tehnologia s-a dezvoltat pe parcursul secolului care a trecut suficient de mult ca să putem reface experimentul în bucătărie.

materiale necesare:

  • un Ardunio, de orice fel, în funcție de cât de familiarizat ești cu el; la curs l-am folosit pe ăsta (31 de lei);
  • un led obișnuit, orice culoare și orice mărime, dar să fie un led simplu; știi că e un led simplu (30 de bani), dacă e foarte ieftin;
  • două fire pentru a lega ledul la Arduino; mie îmi plac astea (3 lei), dar pot fi de orice fel;

puțină teorie:
un led este un dispozitiv semiconductor, de obicei din siliciu, al cărui element activ este vizibil. elementul activ poartă numele de joncțiune, adică locul de întâlnire pentru două materiale cu proprietăți diferite. ce e important de reținut pentru construcția de față este că cele două materiale formează un sandviș cu un mic spațiu între ele, asemeni unui condensator de la fizică. în funcționarea normală, trecerea curentului electric prin acel mic spațiu produce lumină. cu siguranță ai observat că polaritatea e importantă, deoarece lumina și circulația curentului se produc doar într-un singur sens.

ce se întâmplă în schimb când polaritatea e inversată? lipsa curentului electric duce la acumularea de sarcini electrice pe fețele sandvișului, încărcând condensatorul. cum naturii îi plac simetriile, orice rază de lumină incidentă generează perechi de sarcini, care se vor deplasa în direcții opuse, datorită atracției electrostatice. ajunse pe suprafețele sandvișului, acestea vor scădea sarcina acumulată pe condensator, scăzând proporțional și tensiunea electrică.

în mod normal, procesele se întâmplă extrem de repede și sunt extrem de mici ca intensitate. dar aici intervine genialitatea oamenilor care au proiectat Arduino: acesta e suficient de rapid și suficient de sensibil pentru a face față experimentului.

ce se va întâmpla:
Arduino va încărca ledul, alimentându-l invers, după care va număra cât îi ia condesatorului format în jurul joncțiunii ledului pentru a se descărca. pentru a repeta experimentul de la curs, vei conecta ledul cu plusul (piciorușul mai lung, anodul) la GND (ground, 0V) și minusul (piciorușul mai scurt, catodul) la unul dintre terminalele Arduino, cu excepția pinilor 0,1 – care sunt responsabili pentru comunicarea serială și pinul 13, care are deja un led conectat intern și care te va încurca. eu am ales pinul 2.

în pregătirea Arduino, am definit un loc în memorie pentru stocarea informațiilor primite de la led. tipul de date folosit va fi întreg (int), numărând câte perioade de timp condensatorul a fost încărcat. pentru a fi accesibilă de oriunde, definiția se va afla în afara și înaintea celor două funcții speciale Arduino, setup și loop.

int value; // <- asa definesc un loc in memorie, int este tipul, iar value este numele
// pentru ca am definit-o în afara setup și loop, voi putea să o accesez de oriunde, prin nume
void setup() {}
void loop() {}

pentru citirea informațiilor, am folosit interfața serială a Arduino, care va fi inițializată prin:

int value;
void setup() {
  Serial.begin(9600); // <- aici initializez conexiunea seriala cu viteza de 9600 caractere / s
}
void loop() {}

periodic, am încărcat ledul pentru un interval de timp. experimental am ales 1ms.

int value;
void setup() {
  Serial.begin(9600);
}
void loop() {
  pinMode(2, OUTPUT); // <- aici definesc pinul 2 ca fiind pin de iesire
  digitalWrite(2, HIGH); // <- setez tensiunea pe pinul 2 la tensiunea de alimentare a Arduino
  delay(1); // <- astept 1ms, sa incarc condensatorul ledului
}

am măsurat în cât timp tensiunea la bornele ledului scade sub un anumit prag. aici aș fi putut să folosesc convertorul analog-digital din Arduino, dar în unele situații este prea lent. așa că am folosit proprietatea unui pin digital configurat ca intrare de a-și schimba starea în jurul jumătății tensiunii de alimentare a Arduino. astfel, dacă tensiunea la intrare scade sub 2.5V față de GND (pentru un Arduino alimentat la 5V), valoarea citită intern va fi LOW, în timp ce dacă tensiunea crește peste 2.5V, valoarea citită va fi HIGH.

pentru a determina în cât timp tensiunea la bornele ledului scade, am verificat la intervale scurte de timp dacă a scăzut. dacă a scăzut, trimit prin conexiunea serială valoarea înregistrată, altfel, mai aștept puțin timp și verific din nou. experimentând, am folosit ca timp de așteptare 40uS.

int value;
void setup() {
  Serial.begin(9600);
}
void loop() {
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1);
  pinMode(2, INPUT);
  value = 0; // <- aici resetez ce stochez în memorie
  while(digitalRead(2) == HIGH) { // <- citesc pinul 2 si verific daca tensiunea depasește pragul
    delayMicroseconds(40); // <- daca e peste prag, lumina e prea slabă și aștept 40uS
    value = value + 1; // <- cresc cu o unitate valoarea stocată
  }
  // <- aici tensiunea la bornele ledului a scazut sub prag
  Serial.println(value); // <- așa că trimit valoarea prin conexiunea serială
}

în funcție de led și de condițiile de iluminare, valorile primite de calculator sunt uneori negative. acest lucru se întâmplă deoarece numărul de repetări depășește valoarea maximă care poate fi stocată într-un segment de memorie de tip întreg. pentru a preveni această situație, am introdus o limitare la 255 a numărului de cicluri pentru care verificarea are loc:

int value;
void setup() {
  Serial.begin(9600);
}
void loop() {
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1);
  pinMode(2, INPUT);
  value = 0;
  while((digitalRead(2) == HIGH) && (value < 255)) { // <- verific în plus dacă valoarea stocată e sub 255
    delayMicroseconds(40);
    value = value + 1;
  }
  Serial.println(value);
}

note de final:
ledul este sensibil la același tip de lumină pe care o emite. folosind acest principiu, poți foarte ușor să-l transformi într-un senzor de culoare. de asemenea, un led are de obicei o lentilă care dirijează razele de lumină, limitându-i astfel câmpul vizual, la fel ca în cazul emisiei. folosind această informație, poți adapta foarte ușor un led pentru a măsura distanța.

bogdan » raspberry pi minimal gentoo (updated)

03:46 pm on Dec 29, 2013 | #more | tags: ,

the love for gentoo and the spare time during this winter holidays made me update my minimal raspberry pi gentoo image. the image includes:

  • latest 3.10.y (3.10.25+) raspberry pi kernel (sha1: 035642b95ebe820cc265070af72a13f4fa1eb4c7). hdmi output is enabled, also the sound card module is compiled together with lan95xx driver, zd1211 usb wi-fi driver, 3g modem support, ftdi serial addapter and f2fs support. of course gpio. f2fs-tools are also included, but the root partition is still ext4 as some still use debian stable which has no f2fs support.
  • iproute2, iptables and dropbear ssh for networking. no ipv6 support as i think rpi is best suited for local networks. udhcpc is provided through busybox. same ping.
  • full blown vim and wget. i like editing in colors. and sometimes you have to download something.
  • lighttpd http server. as i’m starting to like how easy it is to setup. the root folder of the http server is on the VFAT partition, under www. so you can upload your website files directly from windows.
  • php5.5.4 with fpm and sqlite3. although minimal things are compiled in php, it should be enough to run wordpress. warning! no gd or imagemagick support.
  • wpa_supplicant if you decide to add an wifi dongle. pulled out onto the /boot VFAT partition the network configuration file under /boot/etc/network.
  • you need at least 2Gb of SD card. had incredible success with Hama 8Gb/Class 10/Blue cards. the Verbatim 8Gb/Class 10/Blue card on which i built the first version doesn’t work anymore.
  • root password is blackcat

here’s the download link. enjoy! =) gentoo-3.10.25-blackcat-1.0.img.gz (sha1: d5560f81e43361a7e99db6e7d42e67d4446b0b7b)

Raspberry Pi Minimal Gentoo Distro

bogdan » raspberry pi minimal gentoo (details)

12:11 am on May 3, 2013 | #more | tags: ,

a few details on running gentoo-3.8.8-cat-0.8.img.gz on your raspberry pi:

  • lacking a hwclock, the openrc will complain about the skew clock of some files. use touch to fix their clock and rc-update -u to update the openrc deptree. a reboot will show no more complains.
  • above is one of the reasons net.wlan0, sshd and lighttpd are not added by default to the “default” runlevel. more, the net.wlan0 symlink is missing. use ln -s /etc/init.d/net.lo /etc/init.d/net.wlan0 before running rc-update add net.wlan0 default. same for eth0.
  • to make it easier to configure the net, both /etc/wpa_supplicant/wpa_supplicant.conf and /etc/conf.d/net are linked in /boot/config/wireless.txt and /boot/config/network.txt respectively. you can edit those from windows (while creating the bootable SD card).
  • the kernel contains a fix that enables the nat table in iptables. who knows, a pi router might be a nice idea.
  • you can login via serial console =). it should be interesting connecting a serial LCD to see it.
  • also, lighttpd is pre-configured to use files in /www directory. there, each .rb file is parsed as a cgi script. i’ve minimized the config so it fits only .rb, .html, .js, .css., .jpg, .png files. more than enough in my opinion.
  • the linux includes pi_piper to access pi’s GPIO. including the SPI.

i’m thinking to build an arduino interface to protect the pi’s GPIO and to extend the functionality using the serial port. don’t know when i’ll have time to do that, but it’s in my plans.

 

if it moves, compile it

bogdan » raspberry pi minimal gentoo

09:58 pm on Apr 28, 2013 | #more | tags: ,

i love gentoo. mostly for its ability to be small and tight on the machine running it. so, here it is. a small gentoo distro (around 121Mb) that includes the following:

  • iproute2 & iptables (no ipv6 though, cause i don’t really like it)
  • vim & wget
  • lighttpd (wanted nginx, but has some problems with minimum arm cross-compile)
  • openssh (wanted dropbear, but same as above)
  • ruby (wanted python, but same as above)
  • reiserfs root, tools and kernel support (be it as it may, reiserfs is still a damn good file system in my opinion)
  • wpa_supplicant for wifi configuration
  • update (0.4): fixed ruby socket bug
  • update (0.6): fixed ruby ffi_c.so problem (gentoo doesn’t cross compile C extensions from ruby gems ebuilds. soon a post on a workaround). also added a full blown vim distribution: syntax and advanced commands support. added around 22Mb. you can still use the slim 0.4 version, but you have to replace ffi_c.so with this one (sha1: 07e000d78fd8af57c40a47a26dfd685092d03982)
  • root password is raspberrypi

the kernel:

  • 3.8.8 latest (3.8.y / last night fetched) raspberry pi patched kernel configured with usb LAN95xx network driver (default) and ZD1211 driver (for a USB WiFi SMC dongle i have) with firmware
  • for convenience, you get the imagetool-uncompressed.py on the /boot partition

downloads:

  • the updated raspberry pi 1Gb img file (including updated vim and a working pi_piper with an example.rb): gentoo-3.8.8-cat-0.8.img.gz (sha1: efe34f9c3c5dbd572f83884e9ef0e76136cecb4d)
  • the raspberry pi 1Gb img file (ready to be “burned” on an SD card): gentoo-3.8.8-cat-0.4.img.gz (sha1: 5fe996882533bfd3474bc199e6ee4f124e0f1f52)
  • the kernel image: kernel.img (sha1: cf2bcc30bc3da9c5d6d55c8c4d9a83cf7f43e928)
  • the kernel .config (as the bcmrpi_defconfig isn’t bootable): config (sha1: a524301b9818e11909206584f2710993c2dbc0d0)

references:

Raspberry-PI-Logo-01

bogdan » pic32-pinguino-otg enc28j60 example

11:10 pm on Nov 1, 2012 | #more | tags:

for a week or so i’m searching the internet for a simple example (that can be easily expanded) on how to use the pic32-pinguino-otg with a UEXT connected enc28j60 module (both from olimex). and of course i didn’t wanted to use the “universal” microchip tcp/ip stack that requires MPlab. after digging quite a lot trough the pinguino repositories, i managed to compile a set of working header files (which you can find here) and a small program from which you can ping your boards. for the library to work, copy it under %pinguino/p32/include/pinguino/libraries/ethernet, where %pinguino is the path to your pinguino installation folder. i used pinguino X.3 and it compiled fine.

/*----------------------------------------------------- 
Author:  --<>
Date: 28/Oct/2012
Description:

-----------------------------------------------------*/
#include <ethernet/ip_arp_udp.h>
#define BUFFER_MAX    224

static u8 buf[BUFFER_MAX+1]; // the received message
u16 len; // the length of the received messages

void setup() {
	// put your setup code here, to run once:
	// this is the enc28j60 ip address
	u8 myip[4] = { 192, 168, 2, 2 };
	// this is the enc28j60 mac address
	u8 mymac[6] = { 0x02, 0x04, 0x08, 0x10, 0x12, 0x14 };
	init_ip_arp_udp (mymac, myip);
	enc28j60Init (mymac);
	}

void loop() {
	len = enc28j60PacketReceive(BUFFER_MAX, buf);
	CDC.printf("received! len: %d\n", len);
    
	if (len == 0) {
		return;
		}
	if(eth_type_is_arp_and_my_ip(buf, len)) {
		make_arp_answer_from_request(buf, len);
		return;
		}
	if(eth_type_is_ip_and_my_ip(buf, len)==0) {
                return;
                }

	if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V) {
		// the ping reply
		make_echo_reply_from_request(buf, len);
		return;
		}
	}

bogdan » cheap low power PIR sensor

09:12 pm on Sep 23, 2012 | #more | tags:

recently i had a problem. i needed to build a wireless PIR sensor that could be powered by a LiPo 1400mAh battery. seems like a lot of juice, but thinking that the wixel draws usually almost 30mA and a mangled PIR sensor 8mA, the sensor would have to be recharged every 1.5 days. not a practical approach. through some neat hack i managed to send the wixel in sleep mode, making it draw less than 100uA, but still had the power hungry PIR sensor.

today i managed to solve this problem also. using a cheap (~$15) PIR sensor with a nice housing and a few components i managed to bring the PIR sensor as low as 1.6mA (measured), making the battery last for 34 days. here’s how:

first remove the PIR element. it’s quite big component, encased in metal and with a window for sensing IR radiation. be careful when removing it as it is quite a sensitive component! then gather the components and build this schematic:

components list:
IS1 is the PIR element. this component was on my Eagle library and matched the dimensions of the one i recovered.
R1, R3 = 47K
R2 = 18K
R4, R8 = 1M
R5 = 1K
R6, R7, R9 = 100K
R10 = 330K
C1, C7 = 10uF (there is no mistake! C7 is 10uF but can be polarized. i used tantalum capacitors)
C2, C3 = 4.7uF
C4, C5, C6 = 10nF
IC1A, IC1B = TL082
JP1 = a 3 pin connector in which 1 = +3V3, 2 = signal (connect to wixel P1_0), 3 = GND
JP2, JP3, JP4 = 2 pin connectors as there’s always a good idea to serve power to other devices

notes:
the R9, R10, C7 group sets the sensitivity of the PIR sensor. this setup worked for what i wanted but trust me, it took about 3 hours of testing to get to those values and configuration. the interrupt on P1_0 of the wixel should be configured for raising edge, not falling. R10 is needed to lower the IC1B output potential below the interrupt threshold. an IR event sends the IC1B output close to 3.3V followed by a drop to almost 0V then back to almost 1.65V (this is the value you should have when idle). with R9/R10 the idle voltage is close to 1.26V making the interrupts stable. setting R10 higher, moves this point close to 1.65V when the interrupts are unstable. making it lower decreases the sensitivity. i don’t recommend getting under 56K (standard value) as the interrupts cannot be triggered anymore.

bibliography:
i drew inspiration from Micropik’s D203B PIR element datasheet.

aceast sait folosește cookie-uri pentru a îmbunătăți experiența ta, ca vizitator. în același scop, acest sait utilizează modulul Facebook pentru integrarea cu rețeaua lor socială. poți accesa aici politica mea de confidențialitate.