Prezentowany w artykule termometr jest przeznaczony do mierzenia temperatur w warunkach domowych. Na wyświetlaczu może wyświetlić temperaturę o wartości od 0 do +51,1 stopni Celsjusza z dokładnością do 0,1 stopnia. Na pasku diod LED-RGB są wyświetlane kombinacje kolorów i liczby świecących elementów, odpowiadające temperaturom z zakresu +12…+36,6 stopni Celsjusza. Na diodach uzyskujemy rozdzielczość pomiaru 0,5 stopnia. Wartość można odczytać na podstawie koloru i ilości zapalonych diod zgodnie z tabelą 1.
W odróżnieniu od wcześniej prezentowanych projektów, projekt prezentowany w artykule wymaga dołączenia nie tylko shielda maXimator Expander (na którym umieszczono wyświetlacze LED oraz sensor temperatury STLM20 – fotografia 1), ale także linijki z 8 diodami LED-RGB WS2812B. W przykładzie użyto modułu KAmodWS2812-8, który dołączono do układu FPGA za pomocą pinów UART-a (fotografia 2):
- WS8212B " maXimator,
- GND " GND,
- +VDD " +5V,
- Din " TxD.
Wszystkie oznaczenia są umieszczone na płytkach, jak widać na fotografii. Układ zacznie działać od razu po włączeniu zasilania.
Opis projektu
Projekt składa się z czterech plików napisanych w języku VHDL. Plik główny rgb_termometr (najwyższy poziom w hierarchii) zawiera wszystkie niezbędne elementy do odczytania wartości napięcia z przetwornika analogowo-cyfrowego oraz przekazuje te wartości do bloków obsługujących wyświetlacz i diody RGB.
Blok opisany w pliku wysw (rysunek 3) odpowiada za obsługę wyświetlacza siedmiosegmentowego oraz algorytmy do uśredniania i obliczania temperatury w stopniach Celsjusza. Blok opisany w pliku led_gen pobiera wartość temperatury z bloku wysw i na tej podstawie ustala ile i jakich kolorów powinno być wyświetlonych na diodach RGB. Blok opisany w pliku led_sterownik zamienia kod koloru podawany przez led_gen na sygnał szeregowy, który jest wysyłany na linijkę diod.
Moduły funkcjonalne
led_sterownik (tabela 2). Blok led_sterownik zrealizowano jako maszynę stanów. Przechodzi ona przez 5 stanów: wysoka jedynka (h1), niska jedynka (l1), wysokie zero (h0), niskie zero (l0) oraz stan reset (resett).
Automat zaczyna cykl pracy od zapamiętania wejścia color_in do sygnału color_24. Licznik color_counter_high liczy, który bit koloru jest w danym momencie czytany – dane wysyła od najważniejszych bitów. W zależności od wartości tego bitu wchodzi w stan h1 albo h0. Każdy stan ma licznik, który wskazuje przez jaki czas maszyna ma pozostać w tym stanie. Po upływie tego czasu przechodzi do następnego stanu, którym jest l1 po stanie h1 lub l0 po stanie h0. Znowu czeka w tym stanie na odliczenie licznika do zadanej wartości. O tym, do którego stanu przejdzie dalej decyduje kolejny przeczytany bit. Jeżeli licznik color_counter_high jest większy od zera to przechodzi do odpowiedniego dla kolejnego bitu stanu h1 albo h0. Kiedy wynosi 0 to w zależności od wartości sygnału wejścia if_last zaczyna czytać bity od początku (23 bit) lub – jeżeli if_last = 1 - to przechodzi do stanu resett, który trwa określony czas. Po tym czasie przechodzi do stanu h1 lub h0, jeżeli sygnał if_last będzie mieć wartość 1. W przeciwnym przypadku ponownie wchodzi w stan resett.
W module występuje sygnał wyjściowy load_next. Informuje on, że można w tym czasie zmienić kolor na wejściu. Zmiana koloru raz w czasie całego stanu wysokiego. Jest on zapamiętywany, kiedy sygnał load_next jest równy 0. Sygnał reset nie ma żadnej funkcjonalności. Sygnał zegarowy musi mieć wartość 10 MHz (domyślna w maXimatorze), aby sygnał do diod miał odpowiedni „kształt” w funkcji czasu. Sygnał wyjściowy sterujący diodami LED przyjmuje wartość 1 dla stanów h1 i h0 oraz 0 dla pozostałych stanów.
led_gen (tabela 3). Blok led_gen odpowiada za wygenerowanie odpowiednich kolorów dla 8 diod RGB-LED WS2812B. Na wejściu przyjmuje 7-bitową wartość temperatury w stopniach Celsjusza, gdzie najmłodszy bit jest równy 0,5 stopnia. Zakres temperatur, które może przyjąć led_gen wynosi od 0 do 63,5 stopnia.
Moduł wybiera nowy kolor, kiedy sygnał load_next – pochodzący z modułu led_sterownik – jest równy 1. Na podstawie 4 najwyższych bitów wartości temperatury wejściowej temperature_b_2 określa, w jakim kolorze będzie wyświetlana temperatura. Progi kolorów wyglądają następująco: 12…15,5– ciemnoniebieski, 16…19,5– jasnoniebieski, 20…23,5 – zielony, 24…27,5 – żółty, 28…31,5 – czerwony, 32,0…35,5 – różowy. Kod koloru jest zapisywany do sygnału temp_color. Na podstawie wartości 3 najmłodszych bitów ustalane jest, ile z ośmiu diod modułu KAmodWS2812-8 powinno być włączonych. Dla wartości 0 jest to 1 dioda. Kiedy na 3 najmniej znaczących bitach w sygnale temperature_b_2 są same jedynki, to włączone są wszystkie diody.
Kody kolorów są wysyłane jeden po drugim. Licznik count_diodes odlicza, ile kolorów diod powinno być jeszcze wysłanych i ustala na wyjściu selected_color wartość temp_color, jeżeli dioda ma się świecić lub same zera, jeżeli dioda nie powinna się świecić. Po ośmiu kolorach licznik count_diodes przyjmuje wartość 8 i ustawia bit if_last, który sygnalizuje, że więcej kolorów nie będzie wysyłanych.
wysw (tabela 4). Moduł wysw jest odpowiedzialny za konwertowanie temperatury z przetwornika A/C do zadanych formatów oraz wyświetlaniu jej na wyświetlaczu siedmiosegmentowym. W module występuje sygnał slow_clk, który jest inkrementowany przy każdym zboczu narastającym zegara. Służy on jako wejście ‚clock enable’ do wyzwalania procesów, które należy włączać z dużo mniejszą częstotliwością niż częstotliwość głównego sygnału zegarowego.
Proces odczytywania temperatury jest uruchamiany co 4096 taktów zegara. Za każdym razem aktualna wartość z przetwornika ADC z pinu podłączonego do analogowego termometru STLM20 jest dodawana do sygnału temperature_temp1. Dodawane jest 128 pomiarów. Kiedy dodane zostanie taka liczba pomiarów, temperaturą jest 12 najwyższych bitów sumy (sygnału temperature_temp1). Odjęta jest od danej wartości (0xBE7) i pomnożona przez odpowiedni współczynnik, zgodnie ze wzorem:
temperature_temp2 = 3047 – temperature_temp1;
temperature_b_10 = t_przejściowa * 8 + temperature_temp2/4 + temperature_temp2/32 + temperature_temp2/64;
W ten sposób otrzymana jest temperatura w stopniach Celsjusza, gdzie bity temperature_b_10(12 downto 4) oznaczają temperaturę pomnożoną przez 10 (np. 0x018 to 2,4 stopnia).
W tym samym miejscu jest wyliczana temperatura przestawiona jako binarna wartość w stopniach Celsjusza, gdzie najmniej znaczący bit to 0,5 stopnia (temperature_b_2). Przekazywana jest ona do modułu, gdzie jest wykorzystywana do wyświetlania temperatury na diodach RGB. W procesie tym przeliczana jest także temperatura z postaci binarnej do kodu BCD za pomocą funkcji to_bcd - najwyższe bity sygnału temperature_b_10(12 downto 4) przekształcane do sygnału BDC temperature_decimal_10. Po cztery kolejne bity odpowiadają za kolejne cyfry.
Wyświetlanie na wyświetlaczach 7-segmentowych jest realizowane poprzez przypisanie selektywne. W zależności od wartości slow_clk(12 downto 11) wybierane jest jedna anoda i odpowiednie 4 bity z sygnału temperature_decimal_10, które następnie są konwertowane na format 7-segmentowy, który jest wpisywany do seg7_8_temp.
Moduł daje możliwość wybrania jasności wyświetlacza siedmiosegmentowego poprzez wybranie na wejściu brightness odpowiedniej wartości od 0 do 15. Zrealizowane jest poprzez sprawdzanie czy 4 bity rejestru slow_clk(7 downto 4) są mniejsze, czy większe od wartości brightness. Jeżeli warunek jest spełniony, to wyświetlacz jest gaszony. W projekcie termometru jasność na stałe jest ustawiona na wartość maksymalną.
termometr_rgb (tabela 5). Najwyżej położony w hierarchii moduł opisowy w VHDL, łączy wszystkie wyżej wymienione modułu oraz zawiera przetwornik ADC, który pobiera wartość z pinu wejścia analogowego numer 0. Jest on podłączony do kanału 15. Przetwornik zawiera moduły adc, fingertemp_adc_sequencer oraz pętlę pll generującą zegary na podstawie zegara wejściowego 10 MHz. Wartość z przetwornika jest zapisywana do sygnału counter, który jest wysyłany do bloku wysw. Blok ten zwraca sygnały, które są kierowane na piny do obsługi wyświetlacza siedmiosegmentowego oraz przekazuje sygnał z informacją o temperaturze do bloku led_gen. Blok ten przekazuje i dobiera sygnały z bloku led_sterownik, który na podstawie otrzymanej wartości koloru tworzy sygnał diodes_LED, który jest wyprowadzony na pin do sterowania diodami RGB.
Piotr Klasa, AGH