Zapraszam na szczegółowe sprawozdanie z budowy prostego termometru/higrometru na bazie części znalezionych w szufladzie. Najpierw dobiorę i uruchomię tutaj wyświetlacz, potem złożę i wykonam niezbędny układ na płytce uniwersalnej, a na koniec do niego dodam czujnik AHT20, tak by móc odczytywać pomiary. Całość na popularnym 8-bitowym mikrokontrolerze PIC.
Ten miniprojekt jest nieco powiązany z moim tutorialem SDCC dla PIC18F2550 i będę tu częściowo bazować na opisanych tam krokach:
Część 1 - Konfiguracja środowiska pracy
https://www.elektroda.pl/rtvforum/topic3635522.html#18304424
Część 2 - Blink LED, piny IO, cyfrowe wejścia i wyjścia
https://www.elektroda.pl/rtvforum/topic3647884.html#18389188
Część 3 - Ustawienia oscylatora. Oscylator wewnętrzny, zewnętrzny, rezonator kwarcowy, PLL
https://www.elektroda.pl/rtvforum/topic3657704.html
Część 4 - Timery, przerwania
https://www.elektroda.pl/rtvforum/topic3676645.html#18580858
Część 5 - Obsługa wyświetlacza siedmiosegmentowego
https://www.elektroda.pl/rtvforum/topic3676650.html#18580877
Część 6 - Sterownik wyświetlacza LED MM5450
https://www.elektroda.pl/rtvforum/topic3845301.html
Spis treści będzie uzupełniany wraz z pisaniem przeze mnie kolejnych części.
Powiązane tematy o PIC12F683:
PIC12F683 i SDCC - tutorial - tworzymy prosty ściemniacz (czytamy noty katalogowe)
PIC12F683 i SDCC - cały zegar i termometr na dwóch pinach (bez zewnętrznych bibliotek)
Całość napiszę w SDCC pod PIC18F2550 bez zewnętrznych bibliotek.
Ze względów praktycznych nie będę tu powtarzać szczegółowo wiedzy z poprzednich części.
Cel projektu
Tym razem za cel postanowiłem sobie zbudowanie prostego termometru w oparciu o części, które już miałem na stanie. Planowałem dobrać jakiś większy wyświetlacz 7-segmentowy i uruchomić go z jakimś mikrokontrolerem PIC. Po drodze też wpadłem na pomysł, by dodatkowo dodać czujnik wilgotności. Wszystko oczywiście na płytce prototypowej z tego, co jest pod ręką.
Użyty mikrokontroler?
Zasadniczo użyłem tego, co miałem pod ręką. Początkowo planowałem użyć PIC16LF1902 (2048 słów Flash, 128 bajtów RAM). Układ ten został mi po projekcie obsługi LCD - gdyż on ma sprzętową obsługę LCD.
Niestety pracuje on tylko na napięciu 3.3V, a 5V jest dla niego zbyt wysokie, więc ostatecznie zdecydowałem się użyć klasyka - PIC18F2550. Ich wyprowadzenia są w dużym stopniu zgodne:
Tu mogę skorzystać z okazji i przestrzec przed nieintuicyjnym dla mnie nazewnictwem PICów. Zobaczmy:
- PIC18F2550 - pracuje na 4.2V – 5.5V, wiadomo
- PIC18LF2550 - pracuje na 2.0V – 5.5V
- PIC16LF1902 - pracuje na... 1.8 do 3.6V! Niespodzianka.
Trochę o tym zapomniałem, ale na szczęście wyprowadzenia są zgodne, więc przejście na PIC18F nie było problemem.
Dobór wyświetlacza
Tu też użyłem tego, co miałem pod ręką. Trochę tych wyświetlaczy się przez lata zebrało. W tym projekcie chciałem jakiś większy wyświetlacz, najlepiej na 2 lub 3 cyfry. W przypadku trzycyfrowego też potrzebna będzie kropka.
Zdecydowałem się na nieco większy niż zazwyczaj, potrójny, 7-segmentowy wyświetlacz z kropkami (kropka to ósmy segment):
Do kontrolowania tutaj jest 8 * 3 = 24 osobnych segmentów, ale pinów jest mniej, bo diody LED z danego znaku mają wspólne anody (bądź katody - zależy od typu wyświetlacza). Z tego powodu zacząłem od sprawdzenia czy wyświetlacz w ogóle działa oraz jakie ma wyprowadzenia. Do tego starczy 5V z odpowiednio dobranym rezystorem ograniczającym prąd diody. Wziąłem jakieś 470 omów.
W ten sposób określiłem, że mam do czynienia z wyświetlaczem o wspólnej anodzie. Wszystkie anody danej cyfry są połączone razem i podłącza się je do dodatniego napięcia (tu planuję 5V przez tranzystor - potrzebny będzie PNP). Aby świecił dany segment, jego katodę (one są osobno) należy podłączyć do masy.
Pierwsze testy
Zacząłem od sprawdzenia czy programator (PICKIT2) w ogóle widzi te PICe - zawsze krok po kroku wszystko odpalam.
Potem uruchomiłem blink, czyli miganie diodą LED. W tym celu dodałem brakujący rezystor 10k na pin MCLR, by móc odpalić wgrany program.
Nic nie cieszy tak jak samodzielnie skompilowany i wgrany blink, zwłaszcza gdy MCU też uruchamiamy luzem:
Budowa projektu na uniwersalnej płytce
W dzisiejszych czasach można dość tanio zakupić gotową dwustronną płytkę, tym bardziej jeśli jest ona mniejsza niż 10x10cm, ale to i tak nie ma sensu gdy ma się tylko jedną sztukę pasującego wyświetlacza. Z tego powodu zdecydowałem się użyć płytki wierconej, przeznaczonej na szybkie prototypy.
Postanowiłem, że wyświetlacz będzie wkładany w dwa gniazda szpilkowe, a pod nim będzie schowany MCU. Port B PICa będzie sterować segmentami (przez rezystory). Nie mam aż takiej wyobraźni, by spontanicznie to wszystko polutować, więc przygotowałem sobie szkic połączeń:
Analogicznie do wyświetlacza, PIC też dostał swoją podstawkę. Chcę móc w razie czego go wymienić lub wyjąć:
Niezbyt lubię lutować do takich płytek wierconych. Trzeba uważać z temperaturą oraz dobrze osadzać elementy, bo jak element osadzi się krzywo, a potem się go naciśnie, to pad lutowniczy odpada z PCB.
Tak dobrałem umiejscowienie elementów, by móc łatwo wlutować malutkie, montowane powierzchniowo rezystory między pinami MCU a segmentami wyświetlacza.
Potrzebne też były tranzystory do załączania cyfr. Odzyskałem je z elektrośmieci, z panelu frontowego jakiegoś odtwarzacza DVD czy tam tunera satelitarnego. Tam miały identyczną rolę co u mnie.
Nie bawiłem się nawet odsysaczem czy tam plecionką, po prostu łapię tranzystor kombinerkami i grzeję luty. To płytka ze złomu, może się uszkodzić, tranzystor zresztą też nie jest dużo wart.
Ten tranzystor to A1015 (KSA1015), PNP:
Tak się akurat fajnie składa, że idealnie pasuje do mojego PCB - bazy od strony MCU, kolektory razem (5V), emitery od strony wyświetlacza.
Nie są to najlepsze luty, ale niech już będzie.
W ten sposób zlutowałem minimalny układ dla PICa (rezystor 10k od MCLR, kondensatory na zasilaniu) oraz dla wyświetlacza (trzy tranzystory z rezystorami na bazach, rezystory od segmentów). Na koniec dolutowałem złącze od PICKITa (ICSP). Tak się fajnie składa, że PGD i PGC są po tej samej stronie co MCLR, więc wszystko ładnie przypasowało:
Programowanie wyświetlacza
Całość zweryfikowałem prostym programem blink:
Kod: C / C++
Zamiganie diodą nie jest raczej trudne, ale już tu jest jedna pułapka w postaci rejestru ADCON1 - trzeba go odpowiednio ustawić by włączyć tryb cyfrowy na pinach mających też funkcję ADC.
Zacząłem od uruchomienia osobnych cyfr. Załączyłem wszystkie segmenty (port B) a potem kolejno w pętli włączałem wybrany tranzystor:
Kod: C / C++
Rezultat:
W oparciu o ten kod szybko określiłem na którym pinie portu B jest który segment.
Kod: C / C++
Po prostu próbowałem 8 razy - za każdym razem zapalając inny segment i zapisując który bit mu odpowiada.
Potem mogłem już przygotować znaki - cyfry i litery do F, by móc w razie czego wyświetlać szesnastkowo.
Kod: C / C++
Ostatnim krokiem było wprowadzenie przerwania oraz funkcji rozbijającej podaną liczbę (typ float) na poszczególne cyfry:
Kod: C / C++
Testowy program:
Kod: C / C++
Czujnik AHT20
Zastanawiałem się troszkę skąd wziąć pomiary. Rozważałem DHT11 (lub podobny) oraz DS18B20, ale ostatecznie uznałem, że oba te czujniki wymagają mniej lub bardziej precyzyjnych czasowo operacji, a to może nieco skomplikować ich implementację. Postanowiłem wybrać coś opierające się o protokół I2C, gdzie to główny MCU (master) sam decyduje o zegarze i nie musi martwić się tym, że jednocześnie obsługuje przerwania od timera.
Padło więc na precyzyjny czujnik wilgotności temperatury AHT20. Taki czujnik umieszczony jest na wygodnym module i może być zasilany z 5V. Dokładność pomiaru temperatury wynosi ±0,3°C a wilgotności do ±2%.
Prezentowany moduł ma już rezystory podciągające do zasilania (4.7kΩ) bezpośrednio na PCB, więc nie trzeba ich osobno dodawać.
Uruchomienie I2C
I2C obsłużyłem w pełni programowo, po prostu poprzez operacje na cyfrowym IO. To samo wykonywałem już w temacie z PIC12F683. Wybrałem do tego dwa piny z portu A.
Kod: C / C++
Implementacja:
Kod: C / C++
Mamy tu funkcje:
- I2C_delay – generuje małe opóźnienie, w zasadzie zbędne przy użytym zegarze PICa
- I2C_start – generuje warunek START na magistrali I2C (przejście SDA z wysokiego na niski przy wysokim SCL)
- I2C_stop – generuje warunek STOP na magistrali I2C (przejście SDA z niskiego na wysoki przy wysokim SCL)
- I2C_restart – generuje warunek RESTART (powtórzony START)
- I2C_write – wysyła bajt danych na magistralę I2C, zwraca 1, jeśli otrzymano ACK
- I2C_read – odczytuje bajt z magistrali I2C, parametr ack określa, czy master wyśle ACK (1) czy NACK (0) po odbiorze bajtu
- WriteRegister – wysyła bajt do urządzenia o danym adresie
- ReadRegister – odczytuje bajt z urządzenia I2C o danym adresie
Potem uruchomiłem prosty skaner. Skan magistrali I2C to prosty sposób na podstawową weryfikację podłączeń oraz części implementacji protokołu.
Kod: C / C++
Uzyskany adres wyświetliłem na wyświetlaczu:
56 (dziesiętne) czyli 0x38 (szesnastkowo), zgadza się.
Odczyt z AHT20
Komunikację z AHT20 okroiłem do minimum. W tej wersji chciałem rezultatów. Najważniejsza jest komenda 0xAC (trigger measurement) wraz z argumentami:
Kod: C / C++
Potem zaimplementowałem oczekiwanie - sprawdzanie read status w pętli z oczekiwaniem na ukończenie pomiaru:
Kod: C / C++
Sprawdzam bit siódmy (licząc od zera - 0x80), poniżej rozpiska:
Na koniec zaimplementowałem odczyt pięciu wynikowych bajtów oraz zamianę ich na wilgotność/temperaturę z gotowego do użycia wzoru.
Kod: C / C++
Analogicznie dopisałem obsługę wilgotności:
Kod: C / C++
W głównej pętli teraz wykonuję jeden odczyt a potem najpierw pokazuję jeden wynik, a potem drugi. Wilgotność pokazuję z literką H.
Kod: C / C++
Wygląda na to, że wszystko działa. Test wartości z "H" oraz temperatura:
Dalsze plany
Projekt jeszcze nie jest gotowy, więc dopiero rozważam kolejne kroki. Potrzebna na pewno będzie obudowa. Tu mam dwie możliwości:
- druk 3D - wydrukować sobie dowolny kształt z wybranego koloru plastiku
- sposób "klasyczny", mam jakieś odpadki płyt, ścinki, choć może ktoś z czytających lepiej je określi. Można by rozważyć wykonanie z niej prostego "pudełka":
Przyda się też może jakiś polaryzer na wyświetlacz, mam coś ze starych tunerów satelitarnych...
Oczywiście też trzeba będzie całość upakować i dodać może jakieś złącze USB, tak by to zasilać ze starego zasilacza do telefonu, dużo takich nam zostało po komórkach z zeszłej epoki. Takie zasilacze z reguły mają małą wydajność prądową, ale dla pokazanego tu zegara i 500mA bez problemu wystarczy.
Innym pomysłem jaki mam do zrealizowania to uruchomienie ADC i dodanie prostej regulacji jasności wyświetlacza. W nocy nie musi aż tak mocno świecić, by go było widać.
Podsumowanie
To był kolejny krótki weekendowy projekt który zasadniczo wykonałem od 0. Z gotowych modułów użyłem jedynie AHT20, ale raczej inaczej się nie dało tego zrealizować sensownie, a sam moduł i tak dużo nie zmienił.
Z lutowaniem było troszkę zabawy i nie udało się osiągnąć wyżyn estetyki, ale to i tak będzie w obudowie. Nie było jednak większych problemów, a użycie rezystorów w obudowach 0603 bardzo ułatwiło zmieszczenie się w rozmiarówce samego wyświetlacza. Wyświetlacz teraz dobrze siedzi w gnieździe szpilkowym a w razie czego mogę go też z niego wyjąć, tak samo zresztą jak PIC - on też ma swoją podstawkę DIP28.
Projekt zamierzam dociągnąć do końca, więc jeśli macie jakieś pomysły co można jeszcze dodać (czujnik oświetlenia? Coś innego?), czy jak zrealizować obudowę, itd, to będę wdzięczny za wszystkie sugestie.
Na dzisiaj to tyle, w załączniku umieszczam projekt SDCC pod PIC18F2550.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.