czwartek, 21 lutego 2013

Programowanie AVR cz.8: Przetwornik analogowo-cyfrowy oraz modulacja szerokości impulsu.

Dziś kolejny wgląd w wyposażenie mikrokontrolera ATmega48P - tym razem przyglądamy się wbudowanemu w układ przetwornikowi analogowo-cyfrowemu oraz - dostępnej również w modelach ATtiny - modulacji szerokości impulsu realizowanej przez timery.

Artykuł ten jest w pewnym sensie wstępem do następnego, który pojawi się już wkrótce, a którego tematykę zdradziłem na końcu.

Przetwornik A-C (skrót spotykany w anglojęzycznej literaturze to ADC od Analog to Digital Converter) to układ pozwalający na zamianę wartości napięcia (elektrycznego sygnału analogowego ;-)) na liczbę. W przypadku mojej ATmegi przetwornik ma rozdzielczość 10-bitową, co oznacza, że wartość napięcia podawanego na wejście przetwornika może być po konwersji zapisana jako liczba z przedziału od 0 do 1023 (musimy użyć zmiennej word do zapamiętania tej liczby). Jeśli jesteśmy w posiadaniu mikrokontrolera w obudowie PDIP 28-wyprowadzeniowej, to mamy do dyspozycji sześć kanałów (niezależnych wejść) przetwornika A-C, przyporządkowanych wyprowadzeniom od 23 do 28. W sumie wszystkich kanałów jest osiem plus jeden dodatkowy, o którego przeznaczeniu napiszę w następnym artykule. Kwestie zasilania układu podczas korzystania z ADC przedstawiłem krótko na końcu posta.

Obsługa przetwornika analogowo-cyfrowego w BASCOMie wymaga wstępnej konfiguracji, podczas której ustawiamy m. in. tryb działania przetwornika (ciągły lub "na żądanie") oraz wartość napięcia odniesienia (najczęściej wartość doprowadzona do wyprowadzenia AVCC układu lub wewnętrzna wartość domyślna 1,1V). Szczegóły znajdziecie na stronie pomocy BASCOMa. Przykład konfiguracji (patrz: listing):

' Konfiguracja przetwornika analogowo-cyfrowego; napięcie odniesienia ustalone na 5V 
' (patrz: wyprowadzenie AVCC mikrokontrolera), czyli przedział od 0 do około 5V będzie 
' "rzutowany" na 10-bitową liczbę (od 0 do 1023). 
Config Adc = Single , Prescaler = Auto , Reference = Avcc 

Pojedyncze odczyty wykonywane są (w trybie "single") za pomocą funkcji getadc, która jako parametr przyjmuje numer kanału (w przypadku kanałów dostępnych fizycznie jest to liczba z przedziału od 0 do 5). Musimy pamiętać, że konwersja sygnału analogowego na cyfrowy wymaga czasu, dlatego też żeby otrzymać wiarygodne odczyty, należy unikać "lawinowego" wywoływania funkcji getadc. Wywołanie funkcji getadc w znakomitej większości przypadków sprowadza się do podania jako parametru numeru kanału przetwornika i zapamiętania wyniku w zmiennej typu word:

Dim Odczyt_0 As Word 
... 
Odczyt_0 = Getadc(0) 

Zawartość zmiennej Odczyt_0 możemy teraz swobodnie interpretować.

Kolejny opisywany dziś element wyposażenia ATmegi to generator PWM (ang. Pulse Width Modulation). Modulacja szerokości impulsu realizowana jest przez każdy z trzech timerów, jednak trzeba pamiętać, że tylko jeden z nich (timer1) jest 16-bitowy - pozostałe dwa to liczniki/timery 8-bitowe.
Jeśli chodzi o istotę zjawiska, modulacja szerokości impulsu to nic innego jak zmiana współczynnika wypełnienia dla fali prostokątnej o określonej częstotliwości.

Konfigurując timer jako generator PWM musimy ustalić, z jaką częstotliwością mają być generowane impulsy, jaki ma być zakres licznika (8, 9 czy 10 bitów; dotyczy tylko timera 16-bitowego - w przypadku liczników 8-bitowych nie ma możliwości zmiany zakresu) i czy rejestr porównania (przedstawiony w dalszym ciągu artykułu) ma decydować o szerokości (czasie trwania) logicznego zera bądź jedynki logicznej.

Przykład konfiguracji ośmiobitowego timera jako generatora PWM (szczegóły znajdziecie w dokumentacji BASCOMa - Timer0 i Timer1):

' Timer0 pracujący z największą szybkością w trybie PWM; porównywanie wartości timera 
' w systemie "clear up" spowoduje zwiększanie szerokości impulsu wraz ze wzrostem wartości zmiennych 
' PWM0A i PWM0B (patrz dalej). 
Config Timer0 = Pwm , Prescale = 1 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Up 

W dalszej części artykułu skupimy się właśnie na 8-bitowym timerze 0.

Każdy timer pracujący w trybie PWM posiada dwa wyjścia (stąd wniosek, że mamy do dyspozycji 6 kanałów PWM) - dla timera 0 są to OC0A i OC0B, przypisane odpowiednio wyprowadzeniom 11 i 12 układu. Każde z tych wyjść może być osobno konfigurowane ze względu na współczynnik wypełnienia przebiegu, czyli na dobrą sprawę mogą one pracować niezależnie (przynajmniej z punktu widzenia programu).

Za zmianę szerokości impulsu odpowiadają tzw. rejestry porównania, które w BASCOMie dostępne są poprzez zmienne (a raczej identyfikatory, symbole) Pwm0a i Pwm0b (dla timera 0; w przypadku pozostałych timerów używamy identyfikatorów z odpowiednio podmienioną cyfrą, zresztą podobnie rzecz ma się ze wspomnianymi wcześniej wyjściami). Wartości tych zmiennych, których rozmiar jest uzależniony od konfiguracji timera (w przypadku timera 0 są to zmienne 8-bitowe), mogą być ustalane programowo. Są one cyklicznie porównywane ze stanem licznika i w oparciu o wynik tego porównania (i konfigurację generatora) ustalany jest - że użyję szalenie skompresowanego skrótu - czas trwania jedynki logicznej lub zera logicznego na wyjściu generatora PWM.

Wyczerpujący opis działania timerów jako generatorów PWM w mikrokontrolerach AVR przedstawił Piotr Górecki w swojej książce Mikrokontrolery dla początkujących (Wydawnictwo BTC, Warszawa 2006) - polecam.

Ilustracją do tego artykułu jest prosty układ, przedstawiony na poniższym schemacie:


Za pomocą potencjometrów, które pełnią tutaj rolę regulowanych dzielników napięcia, podajemy na kanały 0 i 1 przetwornika analogowo-cyfrowego napięcie o wartościach między 0 a 5V (uwaga: program zakłada, że pracujemy z napięciem zasilania równym 5V; można obniżyć napięcie, ale wyniki wyświetlane na LCD będą przekłamane, chyba, że zmienimy w programie przelicznik). Wartość odczytanego z ADC napięcia, przetworzona na postać liczbową, a następnie na wolty według zaszytego w programie przelicznika, jest wizualizowana na opcjonalnie dołączonym do układu wyświetlaczu LCD (opisywany przeze mnie moduł wyświetlacza sterowany przez port szeregowy UART), natomiast za jasność świecenia diod LED odpowiada właśnie współczynnik wypełnienia przebiegu prostokątnego pozyskanego z generatora PWM. Współczynnik ten zależy w sposób pośredni od wartości napięcia odczytanej przez ADC, więc za pomocą potencjometrów regulujemy jasność świecenia diod.

Program z przedstawionego niżej listingu nie powinien zawierać żadnego zaskakującego elementu - kod sam dla siebie stanowi komentarz, choć parę rzeczy dorzuciłem.

Na koniec uwaga dotycząca zasilania mikrokontrolera podczas korzystania z przetwornika analogowo-cyfrowego. Zapewne zauważyliście, że lewa strona schematu zawiera mnóstwo kondensatorów o wartości 100nF oraz cewkę 10μH. Jest to po prostu standardowe podłączenie zasilania, zgodne z kartą katalogową ATmegi, szalenie ważne ze względu na prawidłową filtrację napięcia, pozwalającą uniknąć niestabilnego działania układu, a w niektórych przypadkach nawet umożliwić w ogóle działania.

W następnym poście przedstawię schemat układu szalenie prądożernego termometru mikroprocesorowego - oczywiście wykorzystującego m. in. opisane tutaj ficzery.

środa, 20 lutego 2013

Czego zazdroszczę amerykańskim kolegom?

Dlaczego akurat amerykańskim? Nie wiem, ale jakoś tak większość książek informatycznych, jakie przewinęły mi się przez ręce, była napisana przez właśnie autorów ze Stanów.

Bo znów bloguję o pisaniu książek. Informatycznych oczywiście.

Zatem obiektem mojej zazdrości jest czas, który niejednokrotnie autorzy zza oceanu dostają od swoich wydawnictw na napisanie bądź dokończenie książki. Ileż to razy czytałem w jakże charakterystycznych dla autorów z Nowego Świata podziękowaniach dla żon, ojców, matek, mężów, przyjaciół itp. że są szalenie wdzięczni za cierpliwość, jaką wspomniane osoby miały dla nich przez cały rok, kiedy to ich myśli były skierowane wyłącznie na książkę, nad którą pracowali... Rok! Marzenie. Ja najwięcej czasu to chyba ze trzy miesiące miałem - nie pamiętam dokładnie, musiałbym rzucić okiem na umowy. Krótki czas jest z jednej strony uzasadniony - we współczesnej informatyce zmiany zachodzą tak szybko, że jeżeli wyda się książkę o danej technologii, oprogramowaniu, języku czy środowisku z lekkim opóźnieniem, może się po prostu nie sprzedawać. Więcej czasu można poświęcić na stworzenie książki o bardziej ogólnym, choć ściśle ukierunkowanym znaczeniu, jednak ponadproduktowym, nie ograniczającym się do jakiejś konkretnej wersji programu czy technologii. Ale tego typu książki raczej nie mają aż takiego "brania" (chyba, że są wyjątkowo dobre) - wszak "Tworzenie aplikacji dla systemu /.../ w środowisku /.../ wersja 2014" sprzeda się lepiej, niż "Tworzenie aplikacji dla systemu /.../ w języku /.../". A będzie jeszcze gorzej w tym drugim przypadku, gdy autor nieopatrznie przemyci w środku informację, że tak naprawdę, to chodzi o jakieś dziwne narzecze jakiegoś cudacznego języka...
Inaczej jest oczywiście, gdy autor już ma jakiś opracowany tekst i szuka wydawcy (szczęścia życzę, choć dziś wydanie czegokolwiek nie jest aż takim problemem - o czym za moment), jednak ja większość tekstów pisałem na zamówienie, ponieważ moje propozycje okazywały się mieć niekorzystne trendy w kontekście oczekiwań potencjalnych czytelników.

Skąd te rozważania? Otóż ostatnio wpadłem na pomysł przygotowania kolejnej książeczki, tym razem jednak postanowiłem wziąć całość w swoje ręce, czyli wydać się sam. No, może nie do końca sam, ale z pomocą wydawnictwa, które pomogłoby w dystrybucji ebooka. Właśnie o to chodzi - dziś, gdy książki elektroniczne niewątpliwie dorównują - przynajmniej w pewnych kręgach - popularnością książkom klasycznym, wytworzyła się dla autorów świetna okazja do uniezależnienia się od trendów, wymagań, niekorzystnego wpływu wydawcy na kształt dzieła czy na tytuł itp. No i terminy nie ścigają - możesz pisać, jak długo chcesz; twój problem, gdy książka się nie sprzeda. Chyba, że napiszesz coś naprawdę dobrego, że się powtórzę.

Kiedyś popełniłem artykuł typu "rachunek sumienia" - teraz wracam do niego i postaram się solidnie przyłożyć do mojego nowego projektu książkowego.

Chwilowo nie zdradzę jednak, o czym rzecz będzie traktować.

poniedziałek, 4 lutego 2013

Niesamowicie prosty czujnik zmierzchowy.

Tym razem zero programowania, będzie natomiast nostalgiczno-wspomnieniowy układzik, lekko zmodyfikowany.
Otóż kilka dni temu rozmawialiśmy w gronie znajomych o różnego rodzaju czujnikach zmierzchowych i czujnikach ruchu. Ponieważ należę do tych wariatów, co to hołdują jeszcze owej przestarzałej i kompletnie odrealnionej dziś zasadzie: "po co kupować, gdy można zrobić", stwierdziłem, że poskładam takie coś (czujnik zmierzchowy; sensor ruchu faktycznie lepiej nabyć, choćby ze względu na rozmiary ;)) i być może podłączę do jakiegoś mikrokontrolera. Przypomniało mi się też przy okazji, że znalazłem ostatnio w elektronicznych śmieciach stary fotorezystor (dla niewtajemniczonych: element zmieniający rezystancję, czyli opór elektryczny, pod wpływem działania strumienia światła) RPP130, jeden z kilku pozostałych po montowanych wieki temu układach tranzystorowych do zdalnego sterowania pracą urządzeń za pomocą latarki... No OK, nie było to specjalnie rozbudowane zdalne sterowanie ;)
Skompletowałem części, przypomniawszy sobie wcześniej schemat takiego detektora-czujnika, i zmontowałem na płytce stykowej dwa jego warianty. Pierwszy - to układ, który powoduje zapalenie diody LED1 pod wpływem strumienia światła skierowanego na fotorezystor, drugi zachowuje się jak "rasowy" czujnik zmierzchowy, czyli zapala diodę LED1 gdy wokół zaczyna być ciemno. Jak widać na schematach, oba rozwiązania są trywialne i bazują w zasadzie na pracy tranzystora w skrajnych położeniach charakterystyki wyjściowej (nasycenie - odcięcie). Wartości rezystorów są dobrane tak, żeby po stronie wejściowej (obwód bazy tranzystora) zapewnić odpowiednie wysterowanie (lub jego brak) tranzystora, a po stronie wyjściowej - świecenie diody i zapobieganie uszkodzeniu tranzystora w momencie, gdy przez kolektor i emiter płynie prąd (aż do wartości odpowiadającej stanowi nasycenia).
Oto schematy kolejno czujnika oświetlenia i czujnika zmierzchowego:


Jasność świecenia diody zmienia się w zależności od natężenia strumienia światła, czyli w zależności od rezystancji fotorezystora - czyli od wartości napięcia pomiędzy bazą a emiterem. Innymi słowy fotorezystor działa tutaj jak potencjometr, tyle, że mechanizm regulacji zastąpiony został strumieniem światła. Jak już zapewne wszyscy zauważyli, różnica pomiędzy oboma układami polega na zamianie miejscami rezystorów R2 i R3.
Ważna rzecz: dobierając fotorezystor - bo przecież nie musimy stosować takiego eksponatu, jak ten u mnie - musimy sprawdzić jego podstawowe parametry, czyli tzw. rezystancję jasną (dla RPP130 to wartości od 1kΩ do 10kΩ), dotyczącą oświetlonego fotorezystora, i rezystancję ciemną (dla RPP130 ok. 10MΩ) dla elementu nieoświetlonego. Znajomość tych parametrów może pomóc w prawidłowym wyborze wartości rezystora R2 (R3).

A jak ten układ podłączyć do mikrokontrolera, np. ATmegi wyposażonej w przetwornik analogowo-cyfrowy? Sprawa jest prosta - można np. usunąć diodę LED1, zewrzeć emiter do masy, dobrać nową wartość R1 i podłączyć do wyjścia (między kolektor a emiter/masę) równolegle rezystor. Spadek napięcia na rezystorze wyjściowym będzie analizowany przez przetwornik.

I jeszcze kwestia kalibracji - tutaj też nie powinno być problemów, czułość urządzenia można ustawić odpowiednim doborem rezystorów albo po prostu poprzez bardziej finezyjnie rozbudowany układ.

Być może wkrótce zmajstruję jakiś mikroprocesorowy czujnik zmierzchowy, połączony z czujnikiem ruchu, jednak najpierw postaram się opublikować schemat i program dla niesamowicie prądożernego termometru z ATmegą i szesnastoma LED-ami w roli głównej :)