W poprzednich częściach kursu zajmowaliśmy się odczytywaniem sygnałów cyfrowych. Dzięki temu mogliśmy np.: sprawdzić, czy przycisk został wciśnięty. Świat, który nas otacza nie jest jednak cyfrowy, czasami 2 stany (1/0) to za mało.
Dlatego teraz zajmiemy się przetwornikiem analogowo-cyfrowym, w skrócie ADC.
Elektronikę można podzielić na cyfrową oraz analogową. Cyfrowa ogranicza się do tego, że dane wejście lub wyjście może być w jednym z dwóch stanów. Wysokim (1) lub niskim (0). W praktyce oznacza to, że Arduino rozpozna na swoim wejściu 0V lub 5V (w uproszczeniu).
Niestety nie wszystkie rzeczy z otaczającego nas świata można opisać w tak prosty sposób. Podłączając czujnik odległości chcielibyśmy poznać dokładną odległość od przeszkody, a nie jedynie informacje na zasadzie: przeszkoda widoczna, brak przeszkody.
Czujnik taki na swoim wyjściu mógłby podawać napięcie proporcjonalne do odległości. Wtedy pomiar polegałby na odczytaniu napięcia np.: z zakresu 0-5V. To jest właśnie podejście analogowe. Dlatego w poniższych przykładach wykorzystamy odpowiednie peryferia Arduino, które pozwalają na pomiar napięcia dostarczanego do specjalnych wejść układu.
Uwaga!
Zanim przejdziemy do testów zapamiętaj, że do wejść Arduino UNO można podłączyć jedynie napięcie z zakresu 0-5V. Inne może uszkodzić płytkę, a nawet komputer, do którego podłączysz swój układ!
Do przetwarzania sygnału analogowego wykorzystuje się tzw. ADC, czyliAnalog-Digital Converter. Jest to jedno z najpopularniejszych peryferiów występujących w mikrokontrolerach. Jego zadaniem jest próbkowanie napięcia podanego na wejście układu i przetwarzanie go na postać cyfrową.
W tym wypadku przedstawiony został przetwornik 8-bitowy, ponieważ odczytana wartość mogła mieć 256 kombinacji (poczynając od 0). W rzeczywistości możemy się spotkać z różnymi przetwornikami, np. 12 lub 16-bitowymi. Przetwornik, który ma więcej bitów powinien być dokładniejszy, ponieważ jego maksymalna wartość jest większa (działa na tym samym zakresie, ale z większą rozdzielczością).
W ramach ciekawostki warto wiedzieć, że przetworniki analogowo-cyfrowe działają stosunkowo wolno. Oczywiście nie zauważysz tego w swoich programach.Jednak porównując ADC do innych peryferiów mikrokontrolera nie wypadają one na tym tle najlepiej.
Pomiar z ADC trwa 0.0001 s,
czyli maksymalnie można wykonać 10,000 pomiarów na sekundę!
Po drugie przetworniki te są drogie w produkcji. Jak pamiętasz z drugiej lekcji w Arduino UNO mamy do dyspozycji 6 wejść analogowych (A0-A5). Tak naprawdę w środku mikrokontrolera znajduje się tylko 1 przetwornik ADC, do którego podłączony jest multiplekser. Dzięki temu możliwy jest pomiar napięcia na 6 kanałach.
Na tym zakończę wstęp teoretyczny. Gdyby ktoś był ciekawy jak to wszystko działa dokładniej, to zapraszam do pytania w komentarzach. Teraz możemy przejść do pierwszego programu.
Gotowe zestawy do kursów Forbota
Komplet elementów Gwarancja pomocy Wysyłka w 24h
Teraz możesz kupić zestaw ponad 70 elementów niezbędnych do przeprowadzenia ćwiczeń z kursu u naszych dystrybutorów!
Masz już zestaw? Zarejestruj go wykorzystując dołączony do niego kod. Szczegóły »
ADC w praktyce
Czas na sprawdzenie jak ADC zadziała w praktyce. W tym celu należy złożyć układ zgodnie z poniższym rysunkiem. Pojawił się tutaj potencjometr w roli dzielnika napięcia. Jeśli nie pamiętasz czym jest dzielnik napięcia, to koniecznie zajrzyj teraz do trzeciej części kursu elektroniki.
Programowe wykorzystanie ADC jest banalne i ogranicza się do wykorzystania dosłownie jednej, funkcji analogRead(kanał ADC), gdzie za kanał ADC podstawiamy wybrany pin (A0-A5).
Nie pozostaje nam nic innego jak pierwszy prosty program. Na początku ograniczymy się tylko do przesyłania odczytanej wartości do komputera. Wykorzystamy do tego oczywiście USART, który poznaliśmy w poprzedniej części kursu.
int odczytanaWartosc = 0;
void setup() {
Serial.begin(9600);//Uruchomienie komunikacji przez USART
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytujemy wartość napięcia
Serial.println(odczytanaWartosc);//Wysyłamy ją do terminala
delay(200);//Czekamy, aby wygodniej odczytywać wyniki
}
Podczas kręcenia potencjometrem, na ekranie otrzymujemy wartości od 0 do 1023. To oznacza, że przetwornik ADC, który znajduje się w Arduino UNO jest 10-bitowy.
Czy takie suche wartości są dla nas przydatne? Ciężko powiedzieć. Lepiej byłoby odczytywać wynik w bardziej ludzkich jednostkach. Przykładowo w woltach, prawda?
Prosty woltomierz
Zadanie to jest łatwe i polega tylko na odpowiednim przeliczeniu odczytanej wartości. Wiemy, że napięcie wejściowe waha się w zakresie 0-5V, a z przetwornika ADC otrzymujemy 1024 wartości (liczymy od 0 do 1023). Czyli:
1024 => 5V
1 => x
1024x = 1*5
x = (1*5V)/1024 = ~0,0049V
Mówiąc prościej - każde zwiększenie napięcie wejściowego o ~0,0049V zwiększy wskazanie ADC o jeden. Czyli uzyskanie wyniku w woltach ogranicza się do dodania jednej linijki:
int odczytanaWartosc = 0;//Odczytana wartość z ADC
float napiecie = 0;//Wartość przeliczona na napięcie w V
void setup() {
Serial.begin(9600);//Uruchomienie komunikacji przez USART
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytujemy wartość napięcia
napiecie = odczytanaWartosc * (5.0/1024.0); //Przeliczenie wartości na napięcie
Serial.println(napiecie);//Wysyłamy zmierzone napięcie
delay(200);//Czekamy, aby wygodniej odczytywać wyniki
}
Zwróć uwagę, że zmienna napięcie została zadeklarowana jako typ float, czyli taką, która pozwala na przechowywanie liczb zmiennoprzecinkowych.
Liczby dzielone przez siebie w powyższym kodzie zostały zapisane z dopiskiem ".0", jest to informacja dla kompilatora, aby traktował je jako liczby zmiennoprzecinkowe. Inaczej wynik takiej operacji byłby całkowity!
Od teraz na ekranie komputera powinna wyświetlać się wartość z zakresu 0-5V. Tym samym zbudowaliśmy właśnie bardzo prosty, ale działający, woltomierz. Czy można zamiast potencjometru zmierzyć nim napięcie np.: baterii? Tak, ale tylko, gdy będziesz bardzo ostrożny.
Pamiętaj, że podłączenie napięcia wyższego od 5V uszkodzi nieodwracalnie Arduino! Dlatego nawet nie próbuj podłączać pod nasz woltomierz baterii 9V, która znajduje się w zestawie.
Jednak jeśli znajdziesz gdzieś najzwyklejszą baterię AA 1,5V (poszukaj w pilotach do TV), to możesz przeprowadzić eksperyment:
Minus (GND) baterii połącz przewodem z masą Arduino
Przewód idący od pinu A5 przyłóż do plusa baterii
Odczytaj napięcie z komputera
W moim wypadku, na nowej baterii, odczyt wynosił lekko ponad 1,6V, więc wszystko było w normie. Oczywiście woltomierz taki jest bardzo niedokładny i zbiera dużo zakłóceń (o czym przeczytasz dalej). Więc należy traktować go tylko jako ciekawostkę.
Prosty woltomierz na Arduino.
Czy widzisz już praktyczne zastosowanie dla pomiarów ADC (inne od woltomierza)? Jeśli nie, to sprawdź poniższe ćwiczenie (w przeciwnym wypadku również... - testów nigdy za mało).
Regulacja pracy programu dzięki ADC
Wcześniejszy program miał za zadanie jedynie demonstrować działanie przetwornika. Możemy teraz wykorzystamy potencjometr podłączony do układu, aby wpływać na działanie programu. W tym celu dodajmy do Arduino jedną diodę LED.
Wartości z przetwornika mieszą się w przedziale 0-1023, czyli stosunkowo niewiele. Co stanie się, gdy odczytaną liczbę wykorzystamy jako wartość opóźnienia w programie? Oto najszybszy sposób na zbudowanie urządzenia, które miga diodą z częstotliwością regulowaną potencjometrem:
int odczytanaWartosc = 0; //Zmienna do przechowywania odczytu ADC
void setup() {
pinMode(2, OUTPUT); //Konfiguracja wyjść pod diodę LED
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytanie wartości z ADC
digitalWrite(2, HIGH);//Włączenie diody
delay(odczytanaWartosc);//Uzależnienie czasu oczekiwania od ADC
digitalWrite(2, LOW);//Wyłączenie diody
delay(odczytanaWartosc);//Uzależnienie czasu oczekiwania od ADC
}
Zadanie domowe 4.1
Zaobserwuj co dzieje się, w jednej ze skrajnych pozycji potencjometru. Jak myślisz, co jest tego przyczyną?
Wskaźnik na diodach
Pora na bardziej rozbudowany projekt. Tym razem zależnie od pozycji, w której znajdzie się suwak potencjometru włączymy odpowiednią z diod. Na początku należy podłączyć wszystkie elementy. Moja propozycja podłączenia wygląda tak:
Zadanie jest proste, wystarczy podzielić maksymalną wartość, którą możemy odczytać z ADC, czyli 1023 przez 5 i na tej podstawie zbudować warunki włączania poszczególnych diod. Jednak możemy wykorzystać do tego bardzo wygodną funkcję map().
Funkcja ta pozwala na szybkie przeskalowanie pewnej wartości. Jako pierwszy argument podajemy wartość, która ma być skalowana. W naszym przypadku będzie to informacja z przetwornika ADC. Drugi i trzeci parametr, to zakres wartości wejściowej, natomiast ostatnie dwa parametry to zakres wartości wyjściowej (po przeskalowaniu).
W wyniku działania powyższej linijki kodu zawsze otrzymamy wartość z zakresu 1-5. W praktyce wykorzystać można to w następujący sposób:
int odczytanaWartosc = 0;
void setup() {
pinMode(8, OUTPUT); //Konfiguracja wyjść pod diody LED
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytanie wartości z ADC
odczytanaWartosc = map(odczytanaWartosc, 0, 1023, 1, 5);//Przeskalowanie wartości
if (odczytanaWartosc == 1) { //Pierwszy zakres
digitalWrite(8, HIGH);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (odczytanaWartosc == 2) { //Drugi zakres
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (odczytanaWartosc == 3) { //Trzeci zakres
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (odczytanaWartosc == 4) { //Czwarty zakres
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
digitalWrite(12, LOW);
} else { //Pozostałe, czyli piąty zakres
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, HIGH);
}
delay(50); //Opóźnienie, aby nie odczytywać ADC zbyt szybko
}
Zdaję sobie sprawę, że doświadczeni programiści mogą łapać się za głowę widząc powyższe warunki. Wszystko jednak pod kontrolą. Już niedługo zajmiemy się konstrukcją switch/case, która ułatwi takie długie warunki
Sprawdź co dzieje się z poszczególnymi diodami, gdy kręcisz potencjometrem. Jeśli wszystko zostało poprawnie podłączone, to wraz z przekręcaniem suwaka powinna świecić się inna dioda.
Przy jednej ze skrajnych pozycji potencjometru możesz zauważyć, że diody zachowują się dziwnie. Wtedy najlepiej metodą prób i błędów zmienić wartość maksymalną ADC, która ustawiona jest w funkcji map().
U mnie układ zachowywał się poprawnie już przy zmianie z 1023 na 1021.
Zadanie domowe 4.2
Jeśli będziesz miał szczęście (dużo zakłóceń w otoczeniu), to możliwe będzie wykonanie bardzo widowiskowego eksperymentu. Wykorzystaj połączony wcześniej układ z 5 diodami. Odłącz przewód idący do potencjometru i pozostaw go w powietrzu.
Co się dzieje, gdy zbliżasz rękę do przewodu (nie dotykając końcówki)? U mnie, przy przewodzie wiszącym w powietrzu świeciły się 3 diody, jednak wystarczyło zbliżyć rękę na odległość 2cm od kabla i zapalały się wtedy wszystkie diody. Masz pomysł dlaczego tak się dzieje?
Czekam na Wasze komentarze. Jeśli u Ciebie efekt ten nie jest tak wyraźny możesz do końcówki kabla przymocować "antenę" np.: ze sreberka.
Doświadczenie to powinno utkwić Ci w pamięci jako dowód na to, że nie wolno zostawiać żadnych wejść układu "wiszących" w powietrzu. Zobacz jakie mogą z tego wynikać problemy!
Lampka uruchamiana w ciemności
Pora na wykorzystanie nowego elementu oraz zbudowanie czegoś co będzie miało zastosowanie praktyczne. W tym ćwiczeniu wykorzystamy fotorezystor czyli element, którego opór zmienia się pod wpływem padającego światła (im bardziej go oświetlimy, tym mniejsza rezystancja).
Z wykorzystaniem fotorezystora możemy zbudować dzielnik napięcia, który będzie zależny od ilości światła w otoczeniu. Złóż układ zgodnie z poniższym rysunkiem. Fotorezystor powinien tworzyć dzielnik wraz z rezystorem 1k.
W momencie, kiedy na fotorezystor pada duża ilość światła, jego rezystancja jest minimalna i w punkcie, który podłączony jest do Arduino panuje stosunkowo "wysokie" napięcie. Gdy światło przestaje świecić, rezystancja fotorezystora wzrasta, i napięcie na dzielniku jest niskie.
Dysponując takim układem jesteśmy w stanie stworzyć lampkę, która uruchomi się po zmroku. Kod jest bardzo prosty (jak zawsze):
int odczytanaWartosc = 0; //Zmienna do przechowywania odczytu ADC
void setup() {
pinMode(8, OUTPUT); //Konfiguracja wyjść pod diodę LED
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytanie wartości z ADC
if (odczytanaWartosc < 100) {
digitalWrite(8, HIGH);//Włączenie diody
} else {
digitalWrite(8, LOW);//Wyłączenie diody
}
delay(50);
}
Jak widać znajduje się tam warunek, który odpowiada za włączenie lub wyłączenie diody. Pytanie jak dobrać tę wartość przełączenia? Najlepiej ręcznie...
U siebie ustawiłem ją na początku na 500 i stopniowo zmniejszałem, aż dioda uruchamiała się w odpowiednim momencie (gdy zakryłem czujnik ręką).
Wystarczy teraz zamiast niebieskiej diody podłączyć kilka mocniejszych białych (przez tranzystor) i już możemy chwalić się działającą lampką, która sama będzie wiedziała kiedy ma świecić. Co jednak, gdy przeniesiemy ją do innego pokoju, gdzie będą minimalne inne warunki? Czy znowu będziemy musieli programować kilka razy Arduino, aby dobrać odpowiedni próg? Tak, chyba, że...
Lampka uruchamiana w ciemności v2
Tym razem zadanie jest oczywiste. Tak jak wcześniej, chcemy stworzyć lampkę, która będzie uruchamiała się po zmroku. Powinna być ona jednak znacznie łatwiejsza w regulacji. Masz pomysł jak tego dokonać?
Ja wykorzystałem potencjometr podłączony pod kolejne wejście analogowe (A4):
Zamiast uzależniać włączenie diody od sztywnej granicy możemy teraz płynnie regulować próg włączenia za pomocą potencjometru. Zmiana w programie jest bardzo prosta i ogranicza się do edycji 3 linijek kodu:
int odczytanaWartosc = 0; //Zmienna do przechowywania odczytu ADC
int prog = 0; //Próg włączenia światła - ustawiany potencjometrem
void setup() {
pinMode(8, OUTPUT); //Konfiguracja wyjść pod diodę LED
}
void loop() {
odczytanaWartosc = analogRead(A5);//Odczytanie wartości z ADC
prog = analogRead(A4);//Odczytanie wartości z ADC
if (odczytanaWartosc < prog) { //Czy jest ciemniej od ustawionego progu?
digitalWrite(8, HIGH);//Włączenie diody
} else {
digitalWrite(8, LOW);//Wyłączenie diody
}
delay(50);
}
Jak najszybciej dostroić układ?
Połóż urządzenie w świetle, przy którym dioda ma być wyłączona
Przekręć potencjometr na pozycję tuż za miejscem, gdy gaśnie dioda
Gotowe!
Od teraz minimalne zasłonięcie fotorezystora powinno włączyć nasze symboliczne oświetlenie!
Używanie ADC jest bardzo proste, dlatego pora na samodzielną pracę z zadaniami domowymi. Pamiętaj, aby dobrze opanować wszystkie lekcje. Z czasem będziemy w programach używać wielu funkcji. Nie będzie wtedy dużo czasu na wracanie do podstaw!
Zadanie domowe 4.4
Rozbuduj program inteligentnej lampki, tak aby w momencie włączenia diody wysyłał (raz) do PC informację jakie napięcie pojawiło się na dzielniku.
Zadanie domowe 4.5
Spróbuj napisać prostą grę. Po uruchomieniu programu należy przekręcić potencjometr w losowe miejsce i wcisnąć przycisk. Wtedy Arduino powinno wyświetlić na PC komunikat:
Podaj liczbę:
Jeśli wysłana do Arduino liczba będzie zgadzała się z odczytem ADC o +/- 50, to gracz wygrywa. W przeciwnym wypadku włącza się żółta dioda i gracz ma jeszcze 2 próby. Gdy za każdym razem zostanie wpisana zła liczba, to na płytce stykowej włącza się czerwona dioda. Natomiast w przypadku wygranej zielona. Podpowiedź: do realizacji tego zadania przyda Ci się nowa funkcja, która nie była do tej pory używana w kursie – sprawdź samodzielnie w dokumentacji co robi funkcja toInt i zastanów się jak może pomóc Ci w tym zadaniu domowym. Pomocny może być również ten przykład.
Zadanie domowe 4.6
Wykorzystaj dwa fotorezystory w roli osobnych dzielników napięcia. Umieść je po skrajnych stronach płytki stykowej. Najlepiej będzie, gdy odchylisz je nawet minimalnie na zewnątrz. Wyświetl wartości obu czujników w terminalu. Co się dzieje, gdy machasz ręką przed płytką (robiąc cień) lub świecisz w nią latarką?
Czy analizując różnicę między pomiarami z dwóch czujników jesteś w stanie napisać program, który określi, po której stronie płytki znajduje się silniejsze źródło światła? Spróbuj wskazać kierunek na 5 diodach (bardziej w lewo, środek, bardziej w prawo itd.)!
Częste pytanie o książki
Dodatkowy akapit dedykuje osobom zainteresowanych książkami o Arduino. Całkiem często otrzymuję pytania, którą pozycje wybrać. Moim zdaniem, w tej chwili, warto wybierać pomiędzy:
W tej części kursu Arduino opisałem, moim zdaniem, jedno z najciekawszych peryferiów, czyli ADC. Z przetworników analogowych korzysta się bardzo często, gdy układ odczytuje jakieś informacje z zewnątrz. Co ważne ADC dostępne są nie tylko w Arduino, więc praktyczna wiedza z tej części zawsze będzie aktualna.
Pamiętaj, że komplet elementów niezbędnych do przeprowadzenia wszystkich ćwiczeń jest dostępny w Botlandzie. Zakup zestawów wspiera kolejne publikacje na Forbocie!
Jak zawsze czekam na Wasze komentarze i sugestie! Powodzenia w budowie własnych urządzeń, zachęcam do eksperymentowania, koniecznie w praktyce!
Autor: Damian (Treker) Szymański
Pierwsza wersja: Sławomir Kozok
P.S. Nie chcesz przeoczyć kolejnych części naszego darmowego kursu programowania Arduino? Skorzystaj z poniższego formularza i zapisz się na powiadomienia o nowych publikacjach!
Dołącz do 30 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY na bazie Arduino i Raspberry Pi.
Dołącz do 30 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY z Arduino i RPi.
Trwa ładowanie komentarzy...