Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

środa, 9 marca 2011

CManiak: Biblioteka wyświetlacza LED


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:

Wyświetlacz siedmiosegmentowy LED z zaznaczonymi nazwami segmentów.


Więcej na Wikipedii: Wyświetlacz 7-segmentowy

A tak wygląda nasz symulator:

Widok symulatora wyświetlacza siedmiosegmentowego LED w kompilatorze CManiak.


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).

Jeżeli nie będziesz pewien, to popatrz na przykłady.


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.
Zbiorczy przykład powyższych punktów znajdziesz poniżej. Możesz go uruchomić w CManiaku, tak samo jak inne przykłady (definicje itp. jak w przykładzie nr 3):

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
Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

3 komentarze:

  1. Ciekawe, ale bez sensu. Po co skoro można próbować, na mikrokontrolerze z LED.

    OdpowiedzUsuń
  2. To się okaże :-)
    Już jutro opublikujemy nowy artykuł BlueDraco, gdzie symulator wykorzystamy.

    OdpowiedzUsuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.