Arduino i pomiary napięcia z użyciem napięcia odniesienia AREF – LM336

Jedną z ciekawszych funkcji Arduino UNO R3 (a właściwie napędzającego go AtMega328) jest wbudowany przetwornik analog-cyfra. Przetwornik zamienia sygnał analogowy (napięcie) na postać cyfrową. Standardowo przetwornik może mierzyć napięcie w zakresie od 0 do Vcc voltów – gdzie Vcc jest napięciem zasilania AtMega. Podane zasilanie przetwornik dzieli na 1024 przedziały (stąd się bierze rozdzielczość 10 bitów – 2^10 = 1024) i ilość tych przedziałów zwraca w funkcji analogRead() (a dokładniej 0..1023).

Standardowo zakłada się, że Vcc=5v. Jeżeli więc funkcja analogRead() zwróci wartość około 511 – napięcie na takim pinie powinno wynosić około 2.5v. A tu niespodzianka: dla napięcia 2.5v moje Arduino zwróciło…  515 – czyli 2.5171. Skoro rozdzielczość przetwornika to 4.8mV (5v/1024), to skąd się bierze ta różnica, prawie 18mV?

Ok, być może 18mV to niewiele. Ale właśnie pracuję nad układem, w którym muszę odróżniać napięcia różniące się o dziesiątki mV. W takim przypadku błąd 18mV znacznie utrudni mi klasyfikację sygnałów. Dodatkowo, mój układ będzie pracował na bateriach – gdzie mogę się spodziewać spadków zasilania wraz z czasem i obciążeniem układu.

Pomiary

Rozważmy prosty program (funkcja fmap pochodzi z tego wątku):

Teraz do pinu A0 podłączyłem napięcie referencyjne 2.49916v.

Więcej o tym odniesieniu napięcia pisałem: Tanie odniesienie napięcia.

Po podłączeniu Arduino do zasilacza 12v (przez gniazdo DC), odczyt analogRead() wahał się między 514 i 515:

Napięcie zasilania Vcc wynosiło: 4.958v.

I właśnie na tym polega haczyk. Przetwornik A/C przyrównuje napięcie na pinach A0.. do napięcia zasilania Vcc – które nigdy nie jest równe dokładnie 5v.

Na szczęście przetwornik A/C kontrolerów AtMega wyposażono w specjalne wejście AREF. Można pod nie podłączyć źródło napięcia referencyjnego. Wtedy, zamiast napięcia zasilania Vcc, za odniesienie przy konwersji analogowego napięcia na postać cyfrową przetwornik A/C użyje napięcia podanego na AREF. Pozostaje więc stworzyć dostatecznie dokładne, niezależne od zasilania kontrolera, źródło napięcia referencyjnego.

Napięcie referencyjne (LM336)

Za źródło napięcia referencyjnego posłuży mi układ LM336z5. Układ ten potrafi dostarczyć stabilne napięcie o wartości 4…6v.

LM336 nie jest diodą Zenera – składa się z całkiem sporej ilości elementów. Zachowuje się jak dioda Zenera – może stąd symbol na schemacie do niej zbliżony wyglądem.

Co charakterystyczne napięcie referencyjne VREF dostarczane przez układ może być niezależne od zasilania LM336 (u mnie: Vdd), pod warunkiem, że:

  • napięcie zasilające LM336 (Vdd) ma co najmniej 5v (wartość reverse breakdown voltage – Vr) i
  • prąd przepływający przez układ jest większy niż 1mA (katalogowo 400uA, ale trzeba wziąć poprawkę na różne niedokładności i dodatkowe rezystancje) i
  • prąd przepływający przez układ jest mniejszy niż 10mA,

Jak widać z tej charakterystyki, powyżej 400uA (mikro-amper) układ powinien generować już stabilne napięcie 5v. W rzeczywistości trzeba tą granicę przesunąć trochę wyżej – około 1mA.

Aplikacja jest bardzo prosta, wymaga jednego rezystora (ograniczającego prąd przepływający przez LM336) i potencjometru do regulowania napięcia.

P to potencjometr, który pozwoli na dostrojenie napięcia VREF dokładnie do 5v. Instrukcja zaleca potencjometr 10kΩ.

Zadaniem rezystora Rs na wyjściu „+” jest ograniczenie prądu przepływającego przez układ. Maksymalny prąd wynosi ok. 15 mA (Vr – maximum reverse current). Jeżeli więc diodę zasilacie z Vdd=10v, zupełnie wystarczy rezystor Rs = 1kΩ :

I = {(Vdd-Vr) \over R} = {{10v - 5v} \over 1000 }=5 mA

5mA powinno wystarczyć do ustalenia napięcia VREF na poziomie 5v.

Procedura dostrajania układu wygląda tak:

  • Złóżcie układ – podłączcie go do zasilania (uwaga: nie podłączajcie do Arduino – zob. uwagi poniżej),
  • Do „-” i „+” LM336 podłączcie miernik,
  • Kręcąc potencjometrem P ustawcie napięcie VREF na poziomie 5v.

ALE…

W moim układzie, napięcie zasilające LM336 (Vdd) może się zmieniać. To typowy przypadek np. zasilania układu z baterii czy akumulatorów. Z czasem baterie się „zużywają” i spada ich napięcie. Nie chcę, aby mój układ „wariował”, gdy baterie zaczną dostarczać niższe napięcie.

Przeprowadziłem małe doświadczenie: dla zmieniającego się napięcia zasilania Vdd, mierzyłem napięcie VREF przy użyciu różnych rezystorów Rs.

Widać stąd, że przy rezystorze Rs=5kΩ, gdy tylko napięcie zasilające Vdd spadło poniżej 9.5v – napięcie referencyjne VREF (czyli „+” LM336) od razu spadło poniżej 5v. Natomiast przy rezystorze 1kΩ, nawet przy napięciu Vdd równym 6v – napięcie referencyjne VREF utrzymywało się na poziomie 5v.

Skąd biorą się te różnice?

Przykładowo, dla Rs=5kΩ, Vdd=8v:

I = {(Vdd-Vr) \over R} = {{8v - 5v} \over 5000 }=600 uA

…co w połączeniu z kabelkami, zworkami i płytką stykową – sprawia, że LM336 nie ma wystarczająco prądu i VREF spada – u mnie do 4.286v.

Przykładowo, dla Rs=1kΩ, Vdd=8v:

I = {(Vdd-Vr) \over R} = {{8v - 5v} \over 1000 }=3 mA

…co dalej pozwala LM336 na poprawne ustawienie VREF = 5v.

Granicę, gdzie LM336 jeszcze poprawnie generuje napięcie VREF = 5v można jeszcze przesunąć trochę w stronę 5v (zmniejszając wartość rezystora Rs).  Nigdy nie będzie to jednak 5v lub mniej (czyli poziom Vcc) – chociażby ze względu na wartość napięcia wstecznego.

Wniosek płynie z tego następujący: żeby LM336 ustawił stabilne napięcie referencyjne VREF=5v, Vdd (napięcie zasilające LM336) dla Rs=1kΩ musi być na poziomie co najmniej 6v.

LM336 i Arduino

Teraz dodam do pinu AREF napięcie referencyjne zbudowane na LM336. Układ z LM336 w konfiguracji jak powyżej podłączę VREF do portu AREF Arduino UNO.

UWAGA:

ŹLE – GROZI USZKODZENIEM ARDUINO:

  • podłączam VREF pod AREF,
  • zasilam Arduino z załadowanym przypadkowym szkicem, w którym:
  • wywołuję w kodzie analogRead()

DOBRZE:

  • odłączam VREF od AREF
  • ładuję kod na Arduino z instrukcją analogReference przed jakimkolwiek wywołaniem analogRead() – najlepiej w setup(),
  • odłączam Arduino od zasilania,
  • podłączam VREF pod AREF,
  • Arduino podłączam pod zasilacz lub baterie, Vcc>7v,

Trochę zmodyfikowałem kod dodając instrukcję analogreference() w setup():

I wynik:

Teraz jest już dużo bliżej oczekiwanej wartości:)

Niestety do działania wymagane jest zasilenia LM336 napięciem większym niż 6v. Gdy zasilacie Arduino zewnętrznie – nie powinno to być żadnym problemem. Opcją może też być dodatkowa bateria 9v.

Inne opcje

  • analogReference(INTERNAL): podłącza przetwornik do wewnętrznego źródła napięcia 1.1v; wartość 1023 zwrócona przez analogRead() oznacza 1.1v; dzięki temu możecie mierzyć napięcia tylko do 1.1v,
  • Zamiast LM336 można też użyć LM336z2.5 lub TL431 – ale wtedy napięcie referencyjne będzie miało do 2.5v,
  • Mierzone napięcie możecie podzielić dzielnikiem napięcia,
  • Wartość napięcia zasilania Vcc można też odczytać: zob. Secret Arduino Voltmeter – Measure Battery Voltage
  • Można zwiększyć (trochę) rozdzielczość przetwornika: zob. Enhancing ADC resolution by oversampling

…i pewnie jeszcze kilka innych… podpowiecie?

Źródła

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *