Skocz do zawartości
slon

Matryca led: podstawy, proste wyświetlanie znaków - część 1

Pomocna odpowiedź

Temat z pewnością nie jest nowością na forum aczkolwiek postanowiłem spróbować opisać go w sposób trochę inny a czy bardziej przydatny to już ocenią inni.  W ostatnim czasie pojawiła się seria świetnych artykułów autorstwa elwisa na temat wyświetlaczy TFT. Ten artykuł piszę w celu jak najprostszego przedstawienia zagadnienia matryc led co oznacza ograniczenie stosowanych elementów do minimum. Analogiczna sytuacja tyczy się sterowania matrycą czyli szkicu. Całość została wykonana w  SimulIDE a więc w zasadzie każdy będzie mógł sobie to przećwiczyć. Zaczniemy od złożenia samej matrycy 5 rządów 3 kolumny.

Ten wpis brał udział konkursie na najlepszy artykuł o elektronice lub programowaniu. Sprawdź wyniki oraz listę wszystkich prac »
Partnerem tej edycji konkursu (marzec 2020) był popularny producent obwodów drukowanych, firma PCBWay.
PCBway_logotyp-350x233.png

Spis treści serii artykułów:

matryca.thumb.png.899be482fe6ad7f52e11bb1b8b13a748.png

 

Aby wykonać taką matryc przeciągamy elementy z lewej strony symulatora będą to kolejno:

  1. Sources -----> Fixed Volt.
  2. Sources -----> Ground
  3. Switches -----> Switch Dip x2
  4. Passive -------> Resistor Dip
  5. Outputs -------> Led 

Klikając prawym przyciskiem myszy na dany element możemy dostosować jego właściwości wybierając Properties. W naszym wypadku wystarczy , że zmodyfikujemy liczbę Dip Switchy do 5 rzędów i 3 dla kolumn. Możemy również dostosować wartość rezystora. W celu szybkiego złożenia matrycy polecam ustawić jedną kolumnę ledów a następnie skopiować dwa i połączyć całość tak ja na rysunku. Jeśli mamy już wszystko gotowe włączamy symulację (czerwony przycisk na górnej belce) i włączamy zasilanie naszego układu. Jeśli mamy wszystko dobrze podłączone to zaświecą się nam wszystkie ledy. Wyłączmy teraz dwie kolumny (obojętnie które) klikając w zielone kwadraty. Następnie wyłączmy kolejno rzędy. A teraz zadanie chcemy wyświetlić literę Z. Można by nad tym trochę pogłówkować ale jak by nie patrzeć albo raczej jak by nie naciskać w te zielone kwadraty to litery Z nie zobaczymy. Ale gdyby tak się dało klikać w te kwadraty tak szybko , że na rzędach ustalali byś my wzór który następnie był by przenoszony na każdą kolumnę z osobna to coś by z tego pewnie wyszło.

 

manual_matryce3-3.thumb.png.a54edfa8dfe905320bb215f7f37847c7.png

 

Żeby zrobić to samo u siebie najprościej skopiować cały schemat i wkleić dwa razy. Teraz to jeszcze nie wygląd jak litera Z ale już niedużo do tego brakuje. Oczywiście do wykonania tego zadania zaprzęgniemy arduino uno (jeśli ktoś preferuje czystą atmege328p to też jest taka możliwość).

 

uno_z.thumb.png.c59b0a72f73ee5aa0cc478e57c6215fb.png

 

 

No proszę mamy naszą literę Z. Teraz pora przejść do szkicu. 

#define ROW_PIN_MODE DDRD
#define ROW_PIN_STATE PORTD
#define COL_PIN_MODE DDRB

#define col_1 2
#define col_2 4
#define col_3 8

#define ALL_ROWS_OUTPUT 252
#define ALL_ROWS_LOW 0
/*tablica z kolumnami matrycy*/
const uint8_t col[3] = {col_1, col_2, col_3};
/*tablica z kolumnami litery dla litery Z*/
const uint8_t literaZ[3] = {152, 168, 200};

void setup() {
  ROW_PIN_MODE = ALL_ROWS_OUTPUT;
}
void loop() {
  /*pętla skanująca kolumny matrycy i kolumny litery*/
  for (int i = 0; i < 3; i++) {
    COL_PIN_MODE = col[i];
    ROW_PIN_STATE = literaZ[i] >> 1;
    delay(2);
    ROW_PIN_STATE = ALL_ROWS_LOW;
  }
}

Poprawność wyświetlania znaków w symulatorze możemy sprawdzić włączając symulację a następnie klikając w ikonkę Debug i przechodzimy linijka po linijce

 

uno_z1-2-3.thumb.png.a983b42e61284682961087e1108107d6.png

 

Jak widać wszystko wyświetla się tak jak powinno. Na wstępie do operacji na bitach wykorzystamy kalkulator wbudowany w windowsa.

win_calc.thumb.png.664e8b24911d27a754791c0fac4972c2.png

Otwieramy sobie widok a następnie zaznaczamy Programisty i podstawowy. Zaznaczamy również byte  czyli 8-bitów. Wpiszmy więc jedynkę a następnie klikajmy pomału w przycisk RoL i obserwujmy wartości dziesiętne będziemy mieli kolejno: 2, 4, 8, 16, 32, 64, -128 i ponownie 1. Pierwsze trzy wartości celowo pogrubiłem ponieważ możemy je zobaczyć już na początku szkicu przy col_1, col_2, col_3. Podobny efekt (nie taki sam) uzyskamy wpisując 1*2 i klikamy na znak równości. Wartości binarne celowo wziąłem w czerwoną ramkę ponieważ można klikać myszką bezpośrednio w poszczególne bity i w ten sposób ustawiać wartości. Wpiszmy teraz wartość 127 i już widać cały zakres liczb czyli od -128 do 127. Przejdźmy do kolejnej wartości ALL_ROWS_OUTPUT 252. Wpiszmy tą wartość do kalkulatora 2...5....ding...ding nieda się. No tak wszystko się zgada bo mamy wartość ze znakiem a chcemy mieć bez znaku. Jedyna opcja to chyba wybranie Word zamiast Byte teraz zobaczymy wartość binarną 11111100 czyli 6 jedynek , które odpowiadają rzędom (pierwsza jedynka z lewej to pin 7 który niebawem wykorzystamy). Przejdźmy więc do następnego przykładu.

 

uno_z2.thumb.png.8ec144ee04471fee826c69ee3a0fcbf2.png

 

Co tu się stało ? gdzie jest Z? Można by tu przytoczyć przysłowie , że nie wszystko złote co się świeci albo inaczej patrz na to co się nie świeci. Od strony szkicu dodaliśmy operator Not ~.  Kod dla pętli głównej będzie wyglądał następująco

for (int i = 0; i < 3; i++) {
  COL_PIN_MODE = col[i];
  /* ROW_PIN_STATE = literaZ[i] >> 1 */
  ROW_PIN_STATE = ~(literaZ[i] >> 1);
  delay(2);
  ROW_PIN_STATE = ALL_ROWS_LOW;
}

Litera Z jest zgaszona ale wizualnie nie widzimy wszystkich zmian jakie zaszły. 

 

matrix_z2.thumb.png.95124f6413eda09306380564ccce04f3.png

 

Teraz wyraźnie widać , że zmieniamy stan całego portu (PORTD od pinu D0 do D7) a nie tylko wybranych pinów.  Gdyby piny D0 , D1 lub D7 były wykorzystywane do sterowania lub komunikacji to była by to nieoczekiwania zmiana ich stanu. Więcej informacji na ten temat znajduje się w komentarzu drugiego szkicu. Popatrzmy teraz na wartości w tablicy literaZ

const uint8_t literaZ[3]= {152,168,200};

Taki zapis jest mało czytelny bo trzeba by było wartości dziesiętne ponownie konwertować do wartości binarnych czego nie będziemy robić. Rozpiszemy naszą tablicę ponownie. 

const uint8_t literaZ[3] =
{ 0b10011000,
  0b10101000,
  0b11001000
};

Taki zapis faktycznie jest o wiele łatwiejszy w edycji i nie trzeba go konwertować. Teraz pora nieco powiększyć naszą matrycę.

 

uno_6x5.thumb.png.f9c4b48b16b552bfb32f3f3c7c4ae919.png

 

Mamy teraz trochę więcej miejsca więc przesuniemy nasze Z w prawo.

 

uno_z6x5.thumb.png.ef080a3cca6d6e5ba5f6471538077a7a.png

 

Kod dla pętli głównej będzie wyglądał następująco

for (int i = 0; i < 3; i++) {
  /* COL_PIN_MODE = col[i]; */
  COL_PIN_MODE = col[i] << 2;
  ROW_PIN_STATE = literaZ[i] >> 1;
  delay(2);
  ROW_PIN_STATE = ALL_ROWS_LOW;
}

Dokonaliśmy przesunięcia bitowego o dwa miejsca w lewo:

  • col[0]  0b00000010 <<2 ---> 0b00001000
  • col[1]  0b00000100 <<2 ---> 0b00010000
  • col[2]  0b00001000 <<2 ---> 0b00100000

Teraz przesuniemy Z do góry.

uno_z_6x5.thumb.png.514c1f22d01974d486748a854cafe1bf.png

 

Kod dla pętli głównej będzie wyglądał następująco

for (int i = 0; i < 3; i++) {
  COL_PIN_MODE = col[i] << 2;
  ROW_PIN_STATE = literaZ[i];// >> 1;
  delay(2);
  ROW_PIN_STATE = ALL_ROWS_LOW;
}

Usunęliśmy jedynie przesunięcie bitowe w prawo. W zasadzie można powiedzieć , że ustawiliśmy literę Z w domyślnym rzędzie. jedna litera to niewiele dlatego poniżej wklejam nowy szkic z całym alfabetem (wraz z komentarzami).

#define BAUD_RATE 9600
#define BAUD_RATE_DIVISOR (F_CPU / 16 / BAUD_RATE - 1)

#define ROW_PIN_MODE DDRD
#define ROW_PIN_STATE PORTD
#define COL_PIN_MODE DDRB

#define ARDUINO_INTEGRATED_LED 0b00100000

#define col_1 0b00100010
#define col_2 0b00100100
#define col_3 0b00101000

#define ALL_ROWS_OUTPUT 0b01111100
#define ALL_ROWS_LOW 0b00000001
/*liczba liter w tablicy*/
#define LITERA_ALFABETU 26
/*liczba kolumn przypadających na jedną literę*/
#define KOLUMNA_LITERY 3
/*liczba kolumn w matrycy*/
#define MATRIX_COLS 3

#define ASCII_A 65
#define ASCII_Z 90

/*znak odebrany z klawiatury */
char SerialRX;
/*tablica z kolumnami matrycy*/
const uint8_t col[MATRIX_COLS] = {col_1, col_2, col_3};
/*tablica z literami i kolumnami liter*/
const uint8_t litera[LITERA_ALFABETU][KOLUMNA_LITERY] =
{
  /*litery bez polskich znaków*/
  /*----------litera A-----------*/
  { 0b11111000, // COL_1
    0b01010000, // COL_2
    0b00111000
  },// COL_3
  /*----------litera B-----------*/
  { 0b11111000,
    0b10101000,
    0b01010000
  }, //B
  /*----------litera C-----------*/
  { 0b11111000,
    0b10001000,
    0b00000000
  }, //C
  /*----------litera D-----------*/
  { 0b11111000,
    0b10001000,
    0b01110000
  }, //D
  /*----------litera E-----------*/
  { 0b11111000,
    0b10101000,
    0b00000000
  },  //E
  /*----------litera F-----------*/
  { 0b11111000,
    0b10100000,
    0b00000000
  },  //F
  /*----------litera G-----------*/
  { 0b01111000,
    0b10001000,
    0b10110000
  }, //G
  /*----------litera H-----------*/
  { 0b11111000,
    0b00100000,
    0b11111000
  },  //H
  /*----------litera I-----------*/
  { 0b11111000,
    0b00000000,
    0b00000000
  },  //I
  /*----------litera J-----------*/
  { 0b00010000,
    0b00001000,
    0b11110000
  },  //J
  /*----------litera K-----------*/
  { 0b11111000,
    0b00100000,
    0b01011000
  }, //K
  /*----------litera L-----------*/
  { 0b11111000,
    0b00001000,
    0b00000000
  }, //L
  /*----------litera M-----------*/
  { 0b11111000,
    0b01100000,
    0b11111000
  }, //M
  /*----------litera N-----------*/
  { 0b11111000,
    0b01000000,
    0b11111000
  }, //N
  /*----------litera O-----------*/
  { 0b01110000,
    0b10001000,
    0b01110000
  }, //O
  /*----------litera P-----------*/
  { 0b11111000,
    0b10100000,
    0b01000000
  }, //P
  /*----------litera Q-----------*/
  { 0b01100000,
    0b10010000,
    0b01101000
  }, //Q
  /*----------litera R-----------*/
  { 0b11111000,
    0b10100000,
    0b01011000
  }, //R
  /*----------litera S-----------*/
  { 0b01101000,
    0b10101000,
    0b10110000
  }, //S
  /*----------litera T-----------*/
  { 0b10000000,
    0b11111000,
    0b10000000
  }, //T
  /*----------litera U-----------*/
  { 0b11111000,
    0b00001000,
    0b11111000
  }, //U
  /*----------litera V-----------*/
  { 0b11110000,
    0b00001000,
    0b11110000
  }, //V
  /*----------litera W-----------*/
  { 0b11111000,
    0b00010000,
    0b11111000
  }, //W
  /*-----------litera X----------*/
  { 0b11011000,
    0b00100000,
    0b11011000
  }, //X
  /*-----------litera Y----------*/
  { 0b11000000,
    0b00111000,
    0b11000000
  },
  /*---------- Litera Z ---------*/
  { 0b10011000,
    0b10101000,
    0b11001000
  }, //Z
};

void setup() {
  Serial_Rx_Begin();
  ROW_PIN_MODE |= ALL_ROWS_OUTPUT;

}
void loop() {
  if (PINB == ARDUINO_INTEGRATED_LED)
    display_Letter_Highlighted(false); /*wyświetlamy literę zgaszoną*/
  else
    display_Letter_Highlighted(true); /*wyświetlamy literę podświetloną*/
}
/*Serial skonfigurowany tylko do odbierania łącznie z aktywowaniem przerwania  */
void Serial_Rx_Begin() {
  UCSR0A = 0 << TXC0 | 0 << U2X0 | 0 << MPCM0;
  UCSR0B = 1 << RXCIE0 | 0 << TXCIE0 | 0 << UDRIE0 | 1 << RXEN0 | 0 << TXEN0 | 0 << UCSZ02 | 0 << TXB80;
  UCSR0C = 0 << UMSEL01 | 0 << UMSEL00 | 0 << UPM01 | 0 << UPM00 | 0 << USBS0 | 1 << UCSZ01 | 1 << UCSZ00 | 0 << UCPOL0;
  UBRR0 = BAUD_RATE_DIVISOR;
}

void display_Letter_Highlighted(bool letterBacklight) {
  /*jeżeli odebrana literę A...Z*/
  if (SerialRX >= ASCII_A || SerialRX <= ASCII_Z) {
    /*pętla skanująca kolumny matrycy i kolumny litery*/
    for (int i = 0; i < 3; i++) {
      COL_PIN_MODE = col[i];
      if /* ustawiamy odebraną literę na właściwej pozycji w matrycy
            znak np: 'A' zgodnie z ASCII to 65 - 65= 0 czyli litera[0][] itd.*/
      (letterBacklight) ROW_PIN_STATE = (litera[SerialRX - ASCII_A][i]) >> 1;
      else /*
            rzędy liter w tablicy zaczynają się od litera[][0b10000000] dlatego >>1.
            W tym wypadku litera nie jest podświetlona a odbywa się to
            poprzez zastosowanie operatora NOT ~(tyltda), który powoduje odwrócenie
            stanu wszystkich bitów portu. Dlatego dokonujemy kolej operacji z udziałem
            operatora XOR ^(kareta), który zmienia stan wybranych bitów na przeciwny.
            (litera[][]>>1) musi być w nawiasie ponieważ operator >> ma niższy priorytet
            niż operator ~ np: litera[0][col_1) czyli A kolumna pierwsza
            0b11111000 >> 1 ---> ~0b01111100 ---> 0b10000011 ^ 0b10000011 ---> 0b00000000
*/
        ROW_PIN_STATE = ~(litera[SerialRX - ASCII_A][i] >> 1) ^ 0b10000011;
      delay(2); /*opóźnienie dla prawidłowego wyświetlania litery*/
      ROW_PIN_STATE &= ALL_ROWS_LOW;
    }
  }
}
/*procedura przerwania*/
ISR(USART_RX_vect) {
  SerialRX = UDR0; /*odbieramy znaki wysłane z klawiatury*/
  /*po wciśnięciu litery Q włączany/wyłączamy podświetlenie liter wyświetlanych na matrycy
    oraz zmieniamy stan diody Arduino na przeciwny nie naruszając stanu pozostałych bitów*/
  if (SerialRX == 'Q')  PORTB ^= ARDUINO_INTEGRATED_LED;
}

 Na koniec zachęcam do tworzenia własnych znaków (cyfr) w tym celu może być pomocna aplikacja na smartfona.

437221872_CustomCharacter.thumb.jpg.6af3fd0f154b2804b9d303cdf83c51ac.jpg

Dla leniwych w załączniku pliki do simulIDE: pliki.zip

Spis treści serii artykułów:

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

@slon artykuł opublikowałem, zachęcam wszystkich do komentowania! Od siebie dodam tylko, że jeśli planujesz zgłosić tekst do konkursu (do czego zachęcam) to proszę o poprawienie formatowania programu (w tej chwili jest trochę "rozjechany"), co więcej przydałyby się tam jakieś komentarze 😉

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Uwagi przyjąłem są słuszne. 

 

Edytowano przez slon

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...