Co właściwie mierzy analogRead() ?

Kable, kable...
Kable, kable…

Widzicie to kłębowisko? To się oficjalnie nazywa stanowisko testowe LCD kitów. Po prostu – po zlutowaniu partii, każdy trzeba podłączyć aby sprawdzić czy świeci i wyświetla jak należy. Mógłby to być jakiś głupawy tekst, ale to byłoby zbyt proste.

Dlatego wśród kłębu kabli jest ukryty czujnik temperatury MPC9700 (a raczej dwa) i na LCD wyświetla się po prostu odczyt z niego. Wczoraj w nocy jakoś mnie zaintrygowało temperatura jaką wyświetlało Arduino. Była za wysoka, zdecydowanie. Różnicę między 21 a 24 każdy z nas dobrze zauważy (zdjęcie zrobiono w innych warunkach termicznych :) ). A zrzucić tego na niedokładność pomiaru trudno, bo czujnik ma przecież dokładność +/- 2 st.

Ponadto, raz czy dwa w rozmowie z klientami słyszałem takie opinie, że pokazuje za dużo (czujnik, czujnik :) ). Dlatego zacząłem grzebać i próbować różnych rzeczy.

Jak działa przetwornik napięcia?

Przetwornik analogowo cyfrowy ADC jest dokładnie opisany w nocie katalogowej ATmega328 strona 250. W dużym skrócie: napięcie AREF jest napięciem zasilającym przetwornik DAC (podzielnik napięcia sterowany cyfrowo) którego wyjście jest podłączone do komparatora porównywającego je z napięciem wejściowym na danym wejściu analogowym. Napięcie z przetwornika DAC 'startuje’ od zera i jest zwiększany aż osiągnie maksimum lub komparator wykaże przekroczenie poziomu sygnału badanego. Dzięki temu wiadomo jaką wartość ma badany sygnał.

Od razu rzuca się w oczy co wpływa na dokładność takiego pomiaru. Pierwsza rzecz to rozdzielczość (w bitach) przetwornika DAC – inaczej z jakim krokiem zwiększane jest napięcie do porównywania. ATmega328 ma 10-cio bitowy.

Druga wartość to napięcie AREF. Jeżeli liczba kroków jest określona (1023 bo 10 bitów) to wiadomo jakie napięcie przypada na krok. Jest to AREF/rozdzielczość. ATmega może korzystać z 3 różnych źródeł napięcia AREF. Może to być wewnętrzne źródło 1.1V (nie wiem jakiej dokładności), napięcie zasilania (około 5V) lub wartość podana na pin AREF.

Znajomość tej wartości jest konieczna tak aby móc przeliczyć odczyt cyfrowy z przetwornika na rzeczywistą wartość napięcia. Pomińmy na razie opcje korzystania z wewnętrznego źródła 1.1V oraz z podawania AREF własnoręcznie. Skupmy się na domyślnej wartość AREF – 5V.

Teraz kłania się nam podstawowa informacja o czujniki MCP9700 – czyli czułość. Wynosi ona 10mV/st C – dlatego jeżeli chcemy odczytywać dokładnie to co podaje czujnik to musimy znać dokładną wartość AREF.

Może na przykładzie

Odczyt z analogRead() dał nam 150. Myślimy że napięcie odczytane to 5/1023*150 = 0.7331 V. Jest to prawda, jeżeli AREF faktycznie wynosi 5V. A jeżeli ma naprawdę 4.9V? To wówczas prawdziwa wartość jaką oznacza odczyt 150 to: 0.7178V. Różnica – 14.6 mV. Dla czułości 10mV/C – prawie 1.5 stopnia!

A ile wynosi dokładnie ten AREF w domyślnym ustawieniu? Niby 5V, ale tak naprawdę Vcc (napięcie zasilania) podane na ATmega328.

Zaraz, powie ktoś, przecież Arduino ma na sobie regulator napięcia na 5V, więc taka duża różnica nie powinna występować. Prawda. Ale tylko jeżeli zasilamy Arduino przez gniazdo zasilania, a nie przez USB!

Jak wiadomo, standard USB mówi, że napięcie zasilania wynosi 5V, więc regulator napięcia nie działa, napięcie z kabla USB idzie prosto do ATmega. A regulator napięcia nie działa, bo żeby dostarczyć regulowane 5V to musi dostać więcej aby mieć z czego regulować, więc nie ma technicznej (prostej) możliwości regulacji zapewniającej 5V jeśli napięcie zasilania to też 5V.

Inaczej mówiąc jesteśmy zdani na to co komputer podaje na USB. I tutaj właśnie zostałem zaskoczony, bo mój notebook na porcie USB najwyraźniej podaje 4.9 V zamiast równych 5V.

Finalnie – przez to odczyt w moim przypadku był zawyżony o te 1.5 stopnia.

Ale, jeżeli skorzystać z analogReference(INTERNAL); to rezygnujemy z górnych zakresów odczytu (bo maksymalny odczyt to 1.1V czyli po przeliczeniu na temperature (1.1-0.5)/0.01 = 60 stopni) na rzecz zwiększenia dokładności odczytu (1.1/1023 = ok 1mV, tj 0.1 C) . Jeszcze raz uwaga – zwiększenie dokładności odczytu nie pomiaru :)

To tyle w dużym skrócie jeżeli chodzi o to co naprawdę mierzy analogRead. Ażeby wyjaśnić czemu na zdjęciu jeden odczyt to 18 stopni a drugi 20 – nie jest to jakaś magia związana z analogRead – jeden z czujników MCP to wersja A a drugi bez A w numerku. Ten z A (dołączony do Starter Kitu jak i sprzedawany samodzielnie) ma dokładność odczytu +/i 2 a bez A +/- 4 stopnie).