Autor: Dondu
Kurs języka C: Spis treści
Przygotowałem dla Was bibliotekę do CManiaka symulatora 7-segmentowego wyświetlacza LED. Wyświetlacz może pokazać do 10 znaków.
Biblioteka przydatna jest do ćwiczenia pisania programów obsługi wyświetlaczy LED, pod kątem poprawności wyświetlania i konwersji cyfr, liczb i znaków na postać pozwalającą zapalić odpowiednie segmenty wyświetlacza.
Biblioteka nie służy do ćwiczenia multipleksowania wyświetlacza LED.
Wszystkie przykłady z artykułu znajdziesz w zakładce PRZYKŁADY kompilatora CManiak dostępnego w tym artykule - wystarczy wybrać i uruchomić.
Dla przypomnienia standardowy wyświetlacz 7-segmentowy z zaznaczonymi nazwami segmentów:
Więcej na Wikipedii: Wyświetlacz 7-segmentowy
Na wyświetlaczy pokazują się odpowiednie zapalone segmenty (diody LED).
Pod nimi znajdują się na stałe cyfry numeru znaku, odpowiadające indeksowi tablicy którą przekazałeś do wyświetlenia. Oznacza to że komórka tablicy o numerze zero, pokazywana jest jako pierwsza od lewej, a następne kolejno w prawo.
Aby zobaczyć wyświetlacz w praktyce uruchom pierwszy przykład w CManiak'u:
Przykład 1 (w kompilatorze)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <dondu/dd_LED_7seg.h> int main(void) { //bufor wyświetlacza unsigned char wysw[10]; //przykładowa zawartość do wyświetlenia wysw[0]=0x3f; wysw[1]=0x06; wysw[2]=0x5b; wysw[3]=0x4f; wysw[4]=0x66; wysw[5]=0x6d; wysw[6]=0x7d; wysw[7]=0x07; wysw[8]=0x7f; wysw[9]=0x6f; //pokaż wyświetalcz dd_LED_7seg_printf(wysw,10,0); return 0; //zakończ wykonywanie programu }
Jak korzystać z biblioteki w CManiak-u?
Aby móc wykorzystać bibliotekę w CManiaku, powinieneś poznać poniższą instrukcję jej używania.
Linkujemy bibliotekę
Wskazujesz kompilatorowi, iż w swoim programie chcesz korzystać z biblioteki wyświetlacza, poprzez następującą instrukcję:
#include <dondu/dd_LED_7seg.h>
Jest bardzo istotne (ze względu na specyfikę systemu CManiak'a), by:
- była dokładnie taka jak powyżej (bez dodatkowych spacji),
- była linkowana po linkowaniu standardowych nagłówków języka C, ale przed Twoim programem (z jednym wyjątkiem, o którym piszę poniżej).
Bufor wyświetlacza
Wyświetlacz pokazuje zawartość tablicy, którą mu wskażesz oraz wyświetli tyle znaków ile mu każesz.
W związku z tym musisz zadeklarować w swoim programie tablicę (bufor wyświetlacza), na której operujesz swoim programem. Tablica ta będzie symulowała port mikrokontrolera, do którego podłączony masz swój wyświetlacz. W przykładzie 1, jest to tablica o nazwie wysw[], ale Ty możesz nazwać ją dowolnie.
Tablica ta musi być tablicą typu char lub unsigned char. Poszczególne komórki tablicy numerowane są (zgodnie z specyfiką języka C) począwszy od zera, a w wyświetlaczu będą pojawiać się według kolejności od począwszy od lewej jego strony.
W jednej komórce tablicy mieszczą dane dot. jednego znaku wyświetlacza, a bity określają stan diod LED poszczególnych segmentów tego znaku wyświetlacza, zgodnie z rysunkiem powyżej.
Wywołanie wyświetlacza
Funkcją pokazującą wyświetlacz LED w zakładce Terminal CManiak'a, jest:
dd_LED_7seg_printf ( bufor, ilosc_znakow, negacja )
gdzie:
bufor - nazwa Twojej tablicy bufora np.: wysw
ilosc_znakow - liczba określająca ile znaków chcesz zobaczyć, czyli co najmniej 1, a maksymalnie 10.
negacja - flaga wskazująca czy chcesz by wyświetlacz zanegował bity segmentów wyświetlacza. Możliwe wartości, to: 0-segmenty niezanegowane, 1-segmenty zanegowane.
Deklaracja segmentów
Standardowo przyjmuje się, że bit najmniej znaczący (bit 0) odpowiada za segment A, i po kolei aż do bitu nr 6, który odpowiada za segment G. Kropkę reprezentuje bit najbardziej znaczący, czyli bit 7.
Dlatego też biblioteka zawiera następującą standardową definicję segmentów:
#ifndef DD_LED_DEFS #define DD_LED_SEG_A 0x01 #define DD_LED_SEG_B 0x02 #define DD_LED_SEG_C 0x04 #define DD_LED_SEG_D 0x08 #define DD_LED_SEG_E 0x10 #define DD_LED_SEG_F 0x20 #define DD_LED_SEG_G 0x40 #define DD_LED_SEG_DP 0x80 //kropka #endif
Jeżeli Twoje definicje segmentów są zgodne z powyższym standardem nie musisz nic kombinować. Jeżeli jednak nie to czytaj poniższy punkt.
Własne definicje pinów LED (segmentów)
Zauważ, że powyższe standardowe definicje są objęte warunkiem:
#ifndef DD_LED_DEFS //... definicje #endif
Warunek jest po to, że jeżeli będziesz miał taką potrzebę, to możesz poszczególnym definicjom segmentów przypisać swoje bity. Dałem taką możliwość dlatego, że w projektach wykorzystujących mikrokontrolery często stosuje się inne niż standardowe przypisanie segmentów do bitów, by na przykład ułatwić sobie prowadzenie ścieżek na płytce PCB.
Jeżeli chcesz utworzyć własny standard przypisania bitów do poszczególnych segmentów, to możesz to zrobić na przykład tak:
//własne definicje bitów segmentów #define DD_LED_DEFS 1 #define DD_LED_SEG_A 0x80 #define DD_LED_SEG_B 0x40 #define DD_LED_SEG_C 0x04 #define DD_LED_SEG_D 0x10 #define DD_LED_SEG_E 0x08 #define DD_LED_SEG_F 0x02 #define DD_LED_SEG_G 0x01 #define DD_LED_SEG_DP 0x20 //kropka
Jeżeli definiujesz własne bity musisz dodać definicję DD_LED_DEFS, by kompilator nie brał pod uwagę standardowych definicji, tylko Twoje. Najlepiej będzie, gdy przypiszesz DD_LED_DEFS jedynkę (patrz kod powyżej).
No to zobaczmy co się stanie jeżeli wykorzystamy ten sam program co w przykładzie 1, ale zastosujemy zmienione własne definicje podane jako przykład powyżej:
Przykład 2 (w kompilatorze)
//Przykład zawartości tablicy wysw[] niezgodnej ze zdefiniowanymi //własnymi bitami segmentów wyświetlacza. Dlatego na wyświetlaczu //pokaże się nic nie znacząca zawartość. #include <stdio.h> #include <string.h> #include <stdlib.h> //własne definicje bitów segmentów #define DD_LED_DEFS 1 #define DD_LED_SEG_A 0x80 #define DD_LED_SEG_B 0x40 #define DD_LED_SEG_C 0x04 #define DD_LED_SEG_D 0x10 #define DD_LED_SEG_E 0x08 #define DD_LED_SEG_F 0x02 #define DD_LED_SEG_G 0x01 #define DD_LED_SEG_DP 0x20 #include <dondu/dd_LED_7seg.h> int main(void) { //bufor wyświetlacza unsigned char wysw[10]; //przykładowa zawartość do wyświetlenia wysw[0]=0x3f; wysw[1]=0x06; wysw[2]=0x5b; wysw[3]=0x4f; wysw[4]=0x66; wysw[5]=0x6d; wysw[6]=0x7d; wysw[7]=0x07; wysw[8]=0x7f; wysw[9]=0x6f; //pokaż wyświetalcza dd_LED_7seg_printf(wysw,10,0); return 0; //zakończ wykonywanie programu }
W powyższym kodzie dodaliśmy tylko własne definicje bitów. Nie zmieniliśmy jednak zawartości tablicy wysw[], która odpowiadała poprzednim definicjom bitów. Dlatego też na wyświetlaczu zobaczymy tzw. sieczkę zamiast kolejnych cyfr:
Aby zobaczyć prawidłowo cyfry należy odpowiednio zmienić zawartość tablicy wysw[].
Możesz korzystać z tych definicji (oryginalnych lub własnych) w swoim programie, ponieważ są one załączone na początku programu.
Dlatego też używając definicji segmentów zmodyfikujemy powyższy program tak, aby Twoje definicje bitów, pokazały nam prawidłowo cyfry jak w pierwszym przykładzie (definicje itp. jak w przykładzie nr 2):
Przykład 3 (w kompilatorze)
#include <stdio.h> #include <string.h> #include <stdlib.h> //Przykładowe definicje segmentów w Twoim programie //Twoje nazwy i wartośći mogą być inne niż standardowe //Twoje definicje muszą być przed definicjami symulatora //wyświetlacza (patrz niżej) #define SEG_A 0x80 #define SEG_B 0x40 #define SEG_C 0x04 #define SEG_D 0x10 #define SEG_E 0x08 #define SEG_F 0x02 #define SEG_G 0x01 #define SEG_DP 0x20 //definicje bitów segmentów symulatora wyświetlacza //przypisujemy im odpowiednio Twoje definicje //zdefiniowane wcześniej (patrz powyżej) //W ten sposób osiągamy zgodniść definicji Twoich //oraz symulatora wyświetlacza #define DD_LED_DEFS 1 #define DD_LED_SEG_A SEG_A #define DD_LED_SEG_B SEG_B #define DD_LED_SEG_C SEG_C #define DD_LED_SEG_D SEG_D #define DD_LED_SEG_E SEG_E #define DD_LED_SEG_F SEG_F #define DD_LED_SEG_G SEG_G #define DD_LED_SEG_DP SEG_DP //dopiero teraz linkujemy bibliotekę (kolejność jest ważna!) #include <dondu/dd_LED_7seg.h> int main(void) { //bufor wyświetlacza unsigned char wysw[10]; // definicja tablicy zawierającej definicje bitowe cyfr LED unsigned char znaki[] = { SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F, // 0 SEG_B|SEG_C, // 1 SEG_A|SEG_B|SEG_D|SEG_E|SEG_G, // 2 SEG_A|SEG_B|SEG_C|SEG_D|SEG_G, // 3 SEG_B|SEG_C|SEG_F|SEG_G, // 4 SEG_A|SEG_C|SEG_D|SEG_F|SEG_G, // 5 SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G, // 6 SEG_A|SEG_B|SEG_C|SEG_F, // 7 SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G, // 8 SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G // 9 }; //przykładowa zawartość do wyświetlenia //tym razem podstawimy znaki w dowolnej kolejności wysw[0]= znaki[7]; wysw[1]= znaki[1]; wysw[2]= znaki[9]; wysw[3]= znaki[4]; wysw[4]= znaki[3]; wysw[5]= znaki[2]; wysw[6]= znaki[8]; wysw[7]= znaki[0]; wysw[8]= znaki[6]; wysw[9]= znaki[5]; //pokaż wyświetalcz dd_LED_7seg_printf(wysw,10,0); return 0; //zakończ wykonywanie programu }
Znaki inne niż cyfry
Wiele wyświetlaczy w jednym kodzie
Możesz także:
- utworzyć literki lub inne znaki,
- używać kilku tablic (buforów wyświetlacza) wykorzystując je w dowolnym momencie,
- używać wyświetlacza wielokrotnie w tym samym kodzie.
Przykład 4 (w kompilatorze)
int main(void) { //bufory wyświetlacza //może być ich więcej unsigned char wysw[10]; unsigned char a[4]; // definicja tablicy zawierającej definicje bitowe // wybranych liter unsigned char znaki[] = { SEG_C|SEG_D|SEG_E|SEG_F|SEG_G, // b SEG_B|SEG_C|SEG_D|SEG_E|SEG_G, // d SEG_C|SEG_E|SEG_G, // n SEG_C|SEG_D|SEG_E|SEG_G, // o SEG_C|SEG_D|SEG_E // u }; //przykładowa zawartość do wyświetlenia //tym razem do bufora zapiszemy napis: dondu wysw[0]= znaki[1]; //d wysw[1]= znaki[3]; //o wysw[2]= znaki[2]; //n wysw[3]= znaki[1]; //d wysw[4]= znaki[4]; //u //pokaż w wyświetalczu tablicę: wysw dd_LED_7seg_printf(wysw,5,0); //przykładowa zawartość do wyświetlenia //tym razem do bufora zapiszemy napis: bond a[0]= znaki[0]; //b a[1]= znaki[3]; //o a[2]= znaki[2]; //n a[3]= znaki[1]; //d //pokaż w wyświetalczu tablicę: a dd_LED_7seg_printf(a,4,0); return 0; //zakończ wykonywanie programu }
Zanegowane bity segmentów LED
Wyświetlacz ze wspólną anodą
W świecie mikrokontrolerów, bardzo często diody zapalane są zerem logicznym, a nie jedynką. W przypadku wyświetlaczy LED sytuacja ta ma miejsce, gdy używasz wyświetlaczy ze wspólną anodą.
W takiej sytuacji najczęściej w tablicy znaków przechowuje się zanegowane wartości bitów definiujących kształty poszczególnych znaków. Poniższy przykład pokazuje właśnie taki przypadek (definicje itp. jak w przykładzie nr 3):
Przykład 5 (w kompilatorze)
int main(void) { //bufor wyświetlacza unsigned char wysw[10]; // definicja tablicy zawierającej definicje bitowe cyfr LED // bity zanegowane ponieważ stosujesz wyświetlacz ze wspólną anodą unsigned char znaki[] = { ~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F), // 0 ~(SEG_B|SEG_C), // 1 ~(SEG_A|SEG_B|SEG_D|SEG_E|SEG_G), // 2 ~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_G), // 3 ~(SEG_B|SEG_C|SEG_F|SEG_G), // 4 ~(SEG_A|SEG_C|SEG_D|SEG_F|SEG_G), // 5 ~(SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 6 ~(SEG_A|SEG_B|SEG_C|SEG_F), // 7 ~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 8 ~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G), // 9 ~(0x00) // NIC (spacja) }; //przykładowa zawartość do wyświetlenia (kolejne cyfry) wysw[0]= znaki[0]; wysw[1]= znaki[1]; wysw[2]= znaki[2]; wysw[3]= znaki[3]; wysw[4]= znaki[4]; wysw[5]= znaki[5]; wysw[6]= znaki[6]; wysw[7]= znaki[7]; wysw[8]= znaki[8]; wysw[9]= znaki[9]; //pokaż wyświetalcz printf("Bez włączonej negacji:\n\n"); dd_LED_7seg_printf(wysw,10,0); //bez włączonej negacji //pokaż wyświetalcz printf("Z włączoną negacją:\n\n"); dd_LED_7seg_printf(wysw,10,1); //włączamy negację return 0; //zakończ wykonywanie programu }
Podsumowanie
Mam nadzieję, że powyższy symulator wyświetlacza ułatwi Wam naukę pisania programów do obsługi tego rodzaju wyświetlaczy. Jeżeli biblioteka będzie wykorzystywana, to pomyślę nad dodaniem możliwości nauki multipleksowania.
W przypadku gdyby powyższy opis był niewystarczający, proszę zadawać pytania w komentarzach.
Kurs języka C: Spis treści
39
Ciekawe, ale bez sensu. Po co skoro można próbować, na mikrokontrolerze z LED.
OdpowiedzUsuńTo się okaże :-)
OdpowiedzUsuńJuż jutro opublikujemy nowy artykuł BlueDraco, gdzie symulator wykorzystamy.
GJ
OdpowiedzUsuń