- zakres pomiarowy temperatury: –40…125°C
- rozdzielczość pomiaru temperatury: 0,5°C
- dokładność pomiaru temperatury: ±2°C
- obsługiwane rozkazy: SEARCH_ROM, READ_ROM, MATCH_ROM, SKIP_ROM, CONVERT_T oraz READ_SCRATCHPAD,
- napięcie zasilania: 2,7…5 V, pobierany prąd: 6 mA.
To niewyobrażalne, aby element tego typu osiągał tak kuriozalne ceny, gdy jeszcze jakiś czas temu można było go kupić za równowartość 1$. Rozumiem bieżące problemy z dostępnością jakichkolwiek półprzewodników (a zwłaszcza mikrokontrolerów) lecz nic nie uzasadnia tak absurdalnej sytuacji. Na pocieszenie można dodać, że znacznie przystępniejsze, powiedziałbym normalne, ceny ma inny termometr tego producenta a mianowicie DS18B20. Niestety oba wspomniane peryferia nie są bezpośrednimi odpowiednikami, gdyż różnią się dokładnością, a co najważniejsze mają inną organizację wbudowanej pamięci (scratchpad) przechowującej wartość mierzonej temperatury a co za tym idzie nie można ich stosować zamiennie. I właśnie wtedy do głowy wpadł mi dość oryginalny, jak mi się wydaje, pomysł skonstruowania własnego termometru DS1820, którego projekt nazwałem dość sugestywnie, a mianowicie DS18SW20 (SW od słowa software).
Jednak zaznaczam, że nie będę realizował całej dostępnej funkcjonalności termometru DS1820 (choć zapewne z 90%) a skupię się wyłącznie na tych możliwościach, które zazwyczaj potrzebne są w systemach mikroprocesorowych. Zaprezentuję jednak szczegółowy opis implementacji w języku C, w związku z czym zainteresowani Czytelnicy bez problemu będą mogli dodać brakujące funkcje.
Magistrala 1-Wire
Zanim jednak przejdę do opisu samego urządzenia, jak i szczegółów implementacyjnych, nie sposób choćby skrótowo nie przypomnieć informacji na temat bardzo interesującej magistrali 1-Wire, tym razem jednak z punktu widzenia układu podrzędnego typu Slave. Tak jak wspomniano wcześniej, komunikacja na magistrali 1-Wire odbywa się przy udziale wyłącznie jednego przewodu (stąd nazwa interfejsu) oznaczonego jako DQ, który może jednocześnie pełnić rolę przewodu zasilającego w konfiguracji tzw. zasilania pasożytniczego (de facto nieobsługiwanego przez nasze urządzenie DS18SW20). W przypadku magistrali 1-Wire, tak jak w przypadku większości interfejsów szeregowych, transmisja przebiega w konfiguracji Master↔Slave.
Układ nadrzędny (Master) steruje wyszukiwaniem i adresowaniem układów podrzędnych (Slave), steruje przepływem danych oraz generuje sygnał zegarowy (inicjuje wysyłanie i odbieranie danych). Dane przesyłane są synchronicznie z prędkością do 16,3 kbps w trybie standard oraz do 115 kbps w trybie overdrive. Należy szczególnie podkreślić, że przesłanie każdego bitu informacji niezależnie od kierunku transmisji inicjowane jest wyłącznie przez układ Master za pomocą wygenerowania opadającego zbocza sygnału (ściągnięcie magistrali do logicznego „0” przez czas z zakresu 1…5 μs). Po wystąpieniu takiego zbocza sygnału układ Slave podejmuje różne działania, których scenariusz zależy od oczekiwanego kierunku transmisji. Tego typu organizacja protokołu transmisji zapewnia prawidłową synchronizację przesyłanych danych bez potrzeby stosowania dodatkowych linii sterujących.
Minimalny czas trwania pojedynczego bitu jest ściśle określony i wynosi 60 μs+1 μs na tak zwany czas odtworzenia zasilania (recovery time). Wyznacza on maksymalną prędkość transmisji w trybie standard (1/61 μs=16,3 kbps). Co ważne, każde z urządzeń podłączonych do magistrali musi mieć wyjście typu otwarty dren lub otwarty kolektor, a linia danych połączona jest do zasilania przez rezystor podciągający o typowej wartości 4,7 kΩ, co w stanie bezczynności powoduje utrzymywanie się stanu wysokiego na tej linii zapewniającego zasilanie urządzeń podrzędnych (jeśli pracują w trybie zasilania pasożytniczego).
Sama magistrala nie ma ustalonego formatu danych a sposób przesyłania informacji zależy od konfiguracji i właściwości układów podrzędnych. Przesyłane słowa są zawsze jednobajtowe a jako pierwszy transmitowany jest bit mniej znaczący. Dodatkową i jedną z najważniejszych cech urządzeń z interfejsem 1-Wire, o czym wspomniano na wstępie, odróżniającą je jednocześnie np. od urządzeń standardu I²C, jest unikatowy, ośmiobajtowy adres zapisany w pamięci ROM peryferium. Adres ten jest niepowtarzalny i właściwy tylko i wyłącznie pojedynczemu układowi scalonemu (dla elementów produkowanych przez firmę Maxim/Dallas zapisywany jest na etapie produkcji). Najmniej znaczący bajt tego adresu zawiera kod rodziny układów (Family code), kolejne 6 bajtów zawiera unikatowy kod konkretnego egzemplarza (właściwy adresu układu) a najbardziej znaczący bajt zawiera sumę kontrolną CRC8 (Cyclic Redundancy Check). Suma ta wyliczana jest na podstawie poprzednich siedmiu bajtów i jest ustalana na etapie produkcji (służy do kontroli poprawności transmisji).
Protokół transmisji danych interfejsu 1-Wire definiuje kilka, podstawowych sygnałów sterujących i stanów pracy magistrali:
- sygnał Reset, wysyłany przez układ Master, będący żądaniem zgłoszenia się układów Slave,
- sygnał Presence, wysyłany przez układy Slave, będący potwierdzeniem obecności tych układów na magistrali danych,
- zapis logicznej „1” i „0”,
- odczyt logicznej „1” i „0”.
Najlepszym sposobem na zrozumienie zależności czasowych dla poszczególnych stanów pracy magistrali jest zobrazowanie ich na rysunkach pokazujących sekwencje tych sygnałów widziane z perspektywy układu Slave.
Na rysunku 1 pokazano sekwencję inicjalizacji magistrali 1-Wire, która to, jak wspomniano wcześniej, umożliwia układowi Master wykrycie podłączonych do magistrali układów Slave. Sekwencja ta rozpoczyna się poprzez wysłanie przez układ Master sygnału Reset (ściągnięcie magistrali do masy przez czas 480 μs) i po odczekaniu czasu 15…60 μs, odpowiedzią układów Slave poprzez wysłanie sygnału Presence (ściągnięcie magistrali do masy przez czas 60…240 μs).
Na rysunkach 2 i 3 pokazano z kolei sekwencje sygnałów sterujących obrazujące operację zapisu danych (logicznego „0” i „1”) przez układ Slave na magistralę 1-Wire a będącą wynikiem żądania odczytu ze strony układu Master (ściągnięcie magistrali do masy przez czas 1…5 μs).
Dalej, na rysunku 4 pokazano sekwencję sygnałów sterujących obrazującą operacje odczytu danych wykonywaną przez układ Slave a będącą wynikiem zapisu tychże danych dokonanego przez układ Master (jak wcześniej, inicjowaną poprzez ściągnięcie magistrali do masy przez czas 1…5 μs).
Na koniec, na rysunku 5, zaprezentowany jest graf funkcjonalny bodajże najciekawszego mechanizmu charakterystycznego wyłącznie dla magistrali tego typu a przeznaczonego do wyszukania adresów wszystkich układów do niej przyłączonych nazywany SEARCH ROM. Należy bowiem pamiętać, że układ Master nie musi znać adresów przyłączonych do magistrali układów, w związku z czym musi istnieć pewny mechanizm na ich ustalenie. Operacja taka inicjowana jest poprzez wysłanie przez układ Master rozkazu 0xF0 (zwanego SEARCH ROM).
Następnie każdy układ Slave wystawia na magistralę wartość pierwszego, najmniej znaczącego bitu swojego numeru ID (oczywiście zapis inicjowany jest zawsze przez układ Master). Mając na uwadze specyfikę interfejsu 1-Wire, polegającą na tym, że wszystkie układy podłączone są do tej samej magistrali danych należy pamiętać, że na odebraną komendę przeszukiwania odpowiedzą dokładnie w tym samym czasie wszystkie układy Slave w związku, z czym rezultat wystawienia bitów docierający do układu Master jest iloczynem logicznym stanów wyjść wszystkich tych układów (tzw. wired and). Kolejnym krokiem jest wystawianie przez układy Slave zanegowanego, pierwszego bitu swojego numeru ID (oczywiście jak zwykle, na żądanie układu Master). W tym momencie układ Master decyduje o przyjętej wartości pierwszego bitu adresu i wystawia go na magistralę, a układy Slave odczytują go. Jeśli przesłana przez układ Master wartość (w tym trzecim kroku) pierwszego bitu numeru ID jest zgodna z rzeczywistą wartością pierwszego, najmniej znaczącego bitu numeru ID wybranego układu Slave, układ ten kontynuuje proces aż do przebrnięcia przez wszystkie 64 bity numeru. Jeśli taka zgodność nie występuje, układ Slave pozostaje nieaktywny aż do następnego sygnału Reset i żądania wyszukiwania numerów ID (rozkazu 0xF0). W ten prosty sposób układ Master, po przejściu przez każde 64 bity numeru ID, dysponuje każdorazowo kolejnym, znalezionym numerem ID układu pracującego na magistrali 1-Wire. Oczywiście opis ten pokazano z punktu widzenia układu Slave, gdyż algorytm dla układu Master jest nieco bardziej skomplikowany (bazuje na algorytmie tzw. drzewa binarnego).
Budowa i działanie
W tym miejscu dysponujemy już niezbędną wiedzą z zakresu protokołu 1-Wire przejdźmy zatem do schematu ideowego naszego urządzenia, który pokazano na rysunku 6. Jak widać, zaprojektowano bardzo prosty, wręcz trywialny, system mikroprocesorowy, którego sercem jest niewielki mikrokontroler ATtiny25 taktowany wewnętrznym oscylatorem 8 MHz odpowiedzialny za realizację całej, założonej funkcjonalności.
Jako element pomiarowy (termometr) zastosowano scalony przetwornik temperatura-napięcie pod postacią układu scalonego TC1047A produkcji Microchip cechujący się doskonałą liniowością (z nachyleniem 10 mV/°C) oraz akceptowalną dokładnością na poziomie ±2°C.
Nie jest to co prawda dokładność emulowanego termometru typu DS1820 (lub DS18S20), ale moim zdaniem jest jak najbardziej akceptowalna, zaś sam układ jest łatwo dostępny i niedrogi. Co oczywiste, do odczytu wskazań termometru użyto wbudowanego w strukturę mikrokontrolera 10-bitowego przetwornika ADC (kanał ADC2) oraz wewnętrznego napięcia odniesienia o wartości 1,1 V. Odczytywane 10-bitowe dane z przetwornika ADC przeskalowano w taki sposób, aby uzyskać rozdzielczość pomiaru równą 0,5°C oraz zakres mierzonych temperatur rzędu –40…+125°C (jak dla emulowanego termometru). Jako, że poziom napięć wyjściowych układu TC1047A (100…1750 mV) dla pełnego zakresu mierzonych temperatur nie mieści się w zakresie dopuszczalnych napięć wejściowych przetwornika ADC (w przypadku korzystania z wewnętrznej referencji 1,1 V) zastosowano prosty dzielnik napięcia pod postacią rezystorów R1/R2 (koniecznie dokładnych – 1%) niwelujący tą niedogodność.
Montaż i uruchomienie
W tym momencie przejdźmy do szczegółów dotyczących montażu układu. Schemat płytki PCB urządzenia DS18SW20 pokazano na rysunku 7. Jak widać zaprojektowano bardzo kompaktowy (12×20 mm) dwustronny obwód drukowany z wyłącznym montażem elementów SMD. Montaż urządzenia rozpoczynamy od przylutowania półprzewodników (o nieproblematycznych obudowach), następnie lutujemy elementy bierne a na samym końcu złącze GOLDPIN. Poprawnie zmontowane i zaprogramowane urządzenie nie wymaga żadnego uruchamiania i powinno działać tuż po podłączeniu napięcia zasilającego.
Jedynym procesem, jaki możemy wykonać jest zaprogramowanie opcjonalnego adresu urządzenia Slave w pamięci EEPROM mikrokontrolera. W przypadku problemów z dostępnością przetwornika TC1047A u dystrybutorów elektroniki bez wahania możemy go zamówić na stronie producenta układu (z resztą w niższej cenie, niż u dystrybutorów) lub otrzymać za darmo (i to kilka sztuk) w ramach programu bezpłatnych próbek (sample) z czego skorzystałem podczas montażu urządzenia.
Tyle w kwestiach sprzętowych, których nie ma nazbyt wiele, gdyż cała magia dzieje się w oprogramowaniu. W drugiej części artykułu, która ukaże się w kolejnym wydaniu EP, dokładnie omówimy najważniejsze fragmenty kodu programu sterującego urządzeniem.
Robert Wołgajew, EP
- R1: 22 kΩ 1%
- R2: 13 kΩ 1%
- R3: 4.7 kΩ
- C1, C2: 100 nF ceramiczny X7R
- U1: ATtiny25/45/85 (SOIC-8)
- U2: TC1047A (SOT-23)
- CON: złącze GOLDPIN kątowe 3×1 pin