Termometr/higrometr PIC18F2550 z AHT20 - część 2, ADC, kontrola jasności, obudowa
TL;DR
- Kontynuacja budowy termometru/higrometru na PIC18F2550 z AHT20, 3-cyfrowym wyświetlaczem 7-segmentowym i programowaniem w SDCC bez zewnętrznych bibliotek.
- Uruchomiono 10-bitowy ADC PIC18F2550, odczytując napięcie z ADRESH/ADRESL i przełączając konfigurację portu A między analogiem a I2C.
- Do regulacji jasności użyto fotorezystora, a wyświetlacz działa w 8 poziomach jasności sterowanych przez przerwanie timera.
- W testach potencjometr zastąpił czujnik światła, pokazując zakres od 0V do 5V, a później przywrócono wyświetlanie temperatury i wilgotności.
- Projekt ma jeszcze otwarte kwestie obudowy i umieszczenia fotorezystora; planowana jest też kalibracja przez USB i kompletna wersja obudowy z micro lub mini USB.
Wygenerowane przez model językowy.
Zapraszam na drugą część przygody z termometrem/higrometrem zbudowanym od 0 w oparciu o PIC18F2550, części z szuflady oraz programowanym w kompilatorze SDCC - bez zewnętrznych bibliotek. W tej części uruchomię ADC, czyli przetwornik analogowo-cyfrowy, i zrealizuję w oparciu o niego kontrolę jasności wyświetlacza tak, by nocą segmenty nie świeciły zbyt mocno bez potrzeby. Dodatkowo zacznę tu już pracę nad obudową.
W poprzedniej części uruchomiłem wyświetlacz 7-segmentowy z 3 cyframi w oparciu o multipleksing z poziomu przerwania timera na PICu, a następnie zaimplementowałem programowo prostą obsługę I2C by móc pobrać pomiary z AHT20:
Termometr/higrometr na PIC18F i AHT20 krok po kroku - DIY od zera - część 1
Tutaj postaram się kontynuować i usprawnić ten projekt.
Zaczynamy!
Drobne poprawki
Zacząłem od drobnych poprawek. Pierwsze co zrobiłem, to zmniejszyłem wartości rezystorów, bo jednak wyświetlacz był zbyt ciemny. Potem przeniosłem złącze ICSP od programatora tak, by całość wystawała do tyłu, a nie na bok - to z myślą o obudowie:
Uruchomienie ADC
Kolejnym krokiem było uruchomienie ADC. Zdecydowałem się użyć pinów portu A, bo na B mam już segmenty:
PIC18F2550 posiada 10-bitowe ADC. Odczytujemy z niego wartość 10-bitową, czyli z zakresu 0-1023. Rezultaty odczytu są w ADRESH i ADRESL, a konfiguruje się go w rejestrach ADCON0, ADCON1, ADCON2:
W ADCON0 włączamy ADC i wybieramy bieżący kanał, można tam też sprawdzić, czy odczyt został zakończony:
W ADCON1 wybieramy napięcia odniesienia oraz to, które piny AN są cyfrowe, a które analogowe:
W ADCON2 ustawiamy czas i zegar konwersji, jak również format wyniku:
Na tym etapie widzę już jeden mały problem. W projekcie użyłem AN0 i AN1 jako pinów cyfrowych do I2C, a nie chcę przelutowywać kabelków. Z tabeli PCFG3:PCFG0 wynika jednak, że nie da się ustawić AN0 i AN1 w tryb cyfrowy, a np. AN2 w tryb analogowy. Będę musiał zmieniać wartość ADCON1 po konwersji tak bym mógł znów użyć I2C.
Ok, teraz pora wpisać wartości w kod:
Kod: C / C++
Teraz pora na sam odczyt. Konwersje wyzwala pin GO, mikrokontroler sam go gasi po dokończeniu odczytu. Niby można by to zrobić w przerwaniu, lub sprawdzać co jakiś czas ten pin, ale na ten moment niech będzie rozwiązanie blokujące. Na koniec łączę dwa 8-bitowe słowa tak by uzyskać 10-bitowy wynik:
Kod: C / C++
Wartość z zakresu 0-1023 może być trudna w przetwarzaniu, dla wygody zamienię ją jeszcze na napięcie:
Kod: C / C++
Teraz trzeba to przetestować. Pod kątem programowym, wystarczy użyć naszego wyświetlacza:
Kod: C / C++
Sprzętowo nie jest trudniej - wystarczy podać napięcie z zakresu 0 do 5V na wybrany przeze mnie pin, nada się do tego potencjometr. Taki potencjometr ma odczep w środku i stanowi dzielnik napięcia. Podłączyłem go między VDD a GND a odczep do nóżki PICa.
Gotowe:
Pora sprawdzić działanie:
Kontrola jasności wyświetlacza
Wyświetlacz w nocy nie musi być zbyt jasny, by go było dobrze widać, a nawet nie powinien zbyt mocno świecić. Sprawia to dyskomfort, męczy wzrok i przeszkadza. Z kolei w dzień, w dobrym oświetleniu ciężko jest zobaczyć ledwo co tlące się znaki. Z tego powodu warto spróbować dostosować ich poziom jasności dynamicznie.
Pomóc w tym może fotorezystor - jego rezystancja zmienia się wraz z poziomem oświetlenia. Sam mam jeden egzemplarz pochodzący jeszcze z bardzo starych czasów, ktoś wie z jakiego urządzenia to może być?
Miałem też nowsze, ale gdzieś zaginęły przy remoncie.
Usunąłem potencjometr i zastąpiłem go fotorezystorem i zwykłym rezystorem. Zwykły rezystor dobrałem tak, by różne poziomy oświetlenia ładnie pokrywały prawie cały zakres ADC.
Ostatecznie wyszło, że 0V na ADC to bardzo ciemne otoczenie, 3.8V to typowy jasny pokój, a 5V to snop światła latarki skierowany na czujnik.
Kolejnym krokiem jest wdrożenie tego jako poziomy jasności. Na ten moment mamy jeden timer, a każde jego wywołanie ustawia kolejną cyfrę:
Kod: C / C++
Można to jednak wykorzystać i zmienić założenie - powiedzmy, że będzie 8 poziomów jasności i timer będzie wywoływać się te 8 razy dla każdej z cyfr i sprawdzać bieżący indeks wywołania z nastawą jasności, by na bazie tego albo cyfrę zapalać albo gasić. Im dłużej cyfra będzie zgaszona, tym mniejszy poziom jasności.
Kod: C / C++
Tyle, że teraz wszystkie cyfry zmieniają się 8 razy wolniej - z tego powodu zmieniłem też preskaler timera tak by przerwanie wywoływało się odpowiednio częściej:
Kod: C / C++
Rezultat na filmie - poniższy program wyświetla też sam poziom oświetlenia jako wartość liczbową (od 0 do 7):
Chyba muszę jeszcze częściej odświeżać, bo na kamerze widać miganie, choć gołym okiem tego wcale nie odczuwam.
Pora przywrócić wyświetlanie temperatury i wilgotności:
Kod: C / C++
Teraz poziom jasności reaguje znacznie wolniej, ciężko to nawet ładnie pokazać na filmiku, ale to raczej nie problem - i tak noc nie przychodzi w ciągu kilkunastu sekund...
Koncept obudowy
Obudowę chciałem wykonać za pomocą druku 3D. Mój pierwszy pomysł zakładał obudowę dolegającą do wyświetlacza. Zacząłem od zwymiarowania wyświetlacza i przygotowania testowego wydruku:
Poszło gładko i kształtka w sam raz nachodziła na wyświetlacz:
Można było zatem pójść o krok dalej.
Zeszlifowałem boki płytki by nie wystawała poza ramę wyświetlacza i przygotowałem głębszy prototyp:
Ładnie pasuje:
Wstępny efekt:
Gorzej, że taka obudowa nie przewiduje w ogóle fotorezystora... pora go zwymiarować i coś na to zaradzić. Testowy wydruk:
Pasuje:
Na próbę całość:
Nie jestem pewny, czy to aż taki dobry pomysł...
Kod bieżącej wersji do wglądu:
Kod: C / C++
Podsumowanie części drugiej
W tym etapie najpierw dokonałem niezbędnych poprawek błędów z pierwszej części, czyli nieco zwiększyłem prąd segmentów tak aby wyświetlacz był jaśniejszy. Potem przeniosłem złącze od ICSP tak, by nie wystawało z boku, co blokowało mi możliwość dodania prostej obudowy.
Następnie zdecydowałem się na dodanie regulacji jasności wyświetlacza. Od strony sprzętowej był jeden problem, bo PIC18F2550 pozwala uruchamiać piny analogowe "licząc od 0", a ja RA0 i RA1 już przeznaczyłem na I2C, więc ostatecznie niechcąc przelutowywać magistrali zdecydowałem się na ponowną konfigurację portu co odczyt. Od strony programowej poszło gładko, jedynie zwiększyłem częstotliwość przerwania i dodałem w nim proste porównanie i zliczanie - od teraz na jedną cyfrę przypada 8 przerwań, gdzie w każdym sprawdzam czy bieżący licznik osiągnął dany poziom jasności i w oparciu o to zapalam lub gaszę cyfrę.
Na koniec zacząłem eksperymenty z obudową - zdecydowałem się na wersję przylegającą bezpośrednio do wyświetlacza, którego front nawet pasuje do całości kolorystycznie, choć te skazy może by się przydało zamalować.
Sprawę troszkę jednak komplikuje ten fotorezystor, bo na ten moment nie jestem pewny gdzie go umieścić - mój koncept obudowy go nie przewiduje, a jak go dam na górze, to położenie urządzenia na półce sprawi, że będzie on częściowo zasłonięty. Muszę to przemyśleć.
Planuję zrobić jeszcze trzecią część prezentacji, gdzie dodam:
- prostą kalibrację odczytów przez sprzętowe USB z PIC18F2550 (nie wymaga to wielu zewnętrznych komponentów, nie potrzeba żadnych konwerterów USB na UART, itd)
- ostateczną formę obudowy, tym razem pewnie już kompletną, z tyłu gniazdo micro lub mini USB by móc użyć starego zasilacza do telefonu
Dodatkowo mam do zrobienia jeszcze dwie potencjalne poprawki:
- może dałoby się sprytniej realizować kontrolę poziomu jasności, zamiast wywoływać przerwanie N razy dla N dostępnych poziomów, to wywoływać je dwa razy i dynamicznie liczyć wartości przepełnienia się timera
- wypadałoby posortować peryferia na porcie A, tak abym nie musiał zmieniać mu co chwila trybów (analogowy/cyfrowy), wynika to z limitacji PICa, to też umożliwi przeniesienie odczytu ADC do przerwania tak aby nie był blokujący (tylko badać odpowiedni bit)
Na razie to tyle, zapraszam do komentowania, czy macie może jakieś sugestie jak w finalnej wersji zrealizować obudowę i położenie fotorezystora? Czy też robiliście ostatnio coś metodą "100% DIY", tak jak ja starałem się w tym temacie?
Komentarze
Z fotorezystorem "na dachu" dość innowacyjne rozwiązanie. Finalnie pewnie skończy się na przeprojektowaniu obudowy i fotorezystor (nowszy, mniejszy) wyląduje z przodu. [Czytaj dalej]
Tak, gorzej, że mi się spodobał koncept wyświetlacza blisko krawędzi obudowy. Chyba nawet bym grubość jej ścianek zmniejszył... zależy, gdzie będzie to stało. [Czytaj dalej]
Może dać z przodu przyciemnianą szybkę. Zamaskowalaby fotorezystor i poprawiła kontrast wyświetlaczy. [Czytaj dalej]
Takie fotorezystory PIE (chyba Państwowego Instytutu Elektroniki) montowane były w telewizorach z lat 70 do automatycznej regulacji kontrastu, tzw. „oko elektryczne”. Mam taki sam z telewizora „Koral... [Czytaj dalej]