logo elektroda
logo elektroda
X
logo elektroda

Termometr/higrometr PIC18F2550 z AHT20 - część 2, ADC, kontrola jasności, obudowa

p.kaczmarek2  4 1032 Fajne? (+8)
📢 Słuchaj (AI):

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.
Animowany wyświetlacz 7-segmentowy z czerwonymi cyframi w obudowie
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:
Zbliżenie na płytkę drukowaną z przewodami podłączonymi do wyświetlacza 7-segmentowego

Uruchomienie ADC
Kolejnym krokiem było uruchomienie ADC. Zdecydowałem się użyć pinów portu A, bo na B mam już segmenty:
Fragment dokumentacji PIC18F2550 z zaznaczonymi pinami analogowymi RA0–RA5
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:
Fragment dokumentacji technicznej modułu ADC dla mikrokontrolera PIC18F2550
W ADCON0 włączamy ADC i wybieramy bieżący kanał, można tam też sprawdzić, czy odczyt został zakończony:
Tabela bitów dla rejestru ADCON0 sterującego przetwornikiem A/C w PIC18F2550
W ADCON1 wybieramy napięcia odniesienia oraz to, które piny AN są cyfrowe, a które analogowe:
Tabela ADCON1 pokazująca konfigurację pinów AN jako wejścia analogowe lub cyfrowe
W ADCON2 ustawiamy czas i zegar konwersji, jak również format wyniku:
Tabela rejestru ADCON2 mikrokontrolera PIC18F2550 z opisem bitów formatu, czasu i zegara
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++
Zaloguj się, aby zobaczyć kod

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++
Zaloguj się, aby zobaczyć kod

Wartość z zakresu 0-1023 może być trudna w przetwarzaniu, dla wygody zamienię ją jeszcze na napięcie:
Kod: C / C++
Zaloguj się, aby zobaczyć kod

Teraz trzeba to przetestować. Pod kątem programowym, wystarczy użyć naszego wyświetlacza:
Kod: C / C++
Zaloguj się, aby zobaczyć kod

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.
Kilka potencjometrów obrotowych na białym tle, część w woreczku foliowym
Gotowe:
Prototyp termometru z potencjometrem i wyświetlaczem 7-segmentowym na płytce stykowej
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ć?
Stary brązowy fotorezystor z dwoma metalowymi wyprowadzeniami i otworami montażowymi
Okrągły fotorezystor lutowany do ciemnej płytki z dwoma otworami montażowymi
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.
Zbliżenie na fotorezystor zamontowany na żółtej płytce stykowej z podłączonymi przewodami
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++
Zaloguj się, aby zobaczyć kod

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++
Zaloguj się, aby zobaczyć kod

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++
Zaloguj się, aby zobaczyć kod

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++
Zaloguj się, aby zobaczyć kod

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:
Model 3D ramki z widocznymi wymiarami w programie do projektowania
Poszło gładko i kształtka w sam raz nachodziła na wyświetlacz:
Czerwony wyświetlacz 7-segmentowy z ramką obudowy na białym tle
Można było zatem pójść o krok dalej.
Model 3D prostokątnej obudowy z otworem wentylacyjnym i wymiarami na ściankach
Zeszlifowałem boki płytki by nie wystawała poza ramę wyświetlacza i przygotowałem głębszy prototyp:
Wyświetlacz 7-segmentowy z mikrokontrolerem, fotorezystor i części obudowy 3D
Ładnie pasuje:
Płytka drukowana z wyświetlaczem 7-segmentowym w obudowie 3D trzymanej w dłoni
Wstępny efekt:
Wyświetlacz 7-segmentowy w czarnej obudowie 3D pokazuje wartość 8.8H Wyświetlacz 7-segmentowy z obudową 3D pokazujący wartość 23.0
Gorzej, że taka obudowa nie przewiduje w ogóle fotorezystora... pora go zwymiarować i coś na to zaradzić. Testowy wydruk:
Pierścień 3D w szarej kolorystyce w widoku perspektywicznym w programie do modelowania
Pasuje:
Czujnik światła z fotorezystorem podłączony do płytki prototypowej i obudowy 3D
Na próbę całość:
Czarny czujnik z wyświetlaczem LED i fotorezystorem na obudowie
Nie jestem pewny, czy to aż taki dobry pomysł...

Kod bieżącej wersji do wglądu:
Kod: C / C++
Zaloguj się, aby zobaczyć kod


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?

O autorze
p.kaczmarek2
Inżynier programista z wieloletnim doświadczeniem embedded i full stack developer. Specjalizuje się w: embedded, Full-Stack Developer p.kaczmarek2 napisał 14444 postów o ocenie 12414 , pomógł 650 razy. Jest z nami od 2014 roku.

Komentarze

efi222 23 Lip 2025 21:41

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]

p.kaczmarek2 24 Lip 2025 04:57

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]

efi222 24 Lip 2025 11:31

Może dać z przodu przyciemnianą szybkę. Zamaskowalaby fotorezystor i poprawiła kontrast wyświetlaczy. [Czytaj dalej]

jestan 06 Kwi 2026 17:09

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]

%}