Skocz do zawartości

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


slon

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
Link do komentarza
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 😉

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

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!

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

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.