[µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Projekty użytkowników forum zarówno sprzętowe, jak i związane z programowaniem w dowolnym języku.
Awatar użytkownika
ZbeeGin
User
User
Posty: 492
Rejestracja: sobota 08 lip 2017, 17:16
Lokalizacja: Śląsko-Zagłębiowska Metropolia
Kontaktowanie:

[µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: ZbeeGin » wtorek 25 cze 2019, 09:57

Po dłuższej przerwie kolejny µProjekt. Tym razem jest to panel z 6 wyświetlaczami LED i kompletem przycisków. I to w dwóch wersjach: pierwotną o małym rozmiarze i tzw. "Sen Antego" :) Wszystko obsługiwane przez azjatycki wynalazek TM1637. Uwaga! Ciężko dostępny u krajowych dystrybutorów. Jest to domyślna aplikacja tego układu:
led_key_panel_tm1637.png

Kompletny projekt (z programu KiCad 5.1) dla obu wersji:
led_key_panel_tm1637.zip


ps. W serwisach aukcyjnych można kupić różnej maści płytki również z tym kontrolerem.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: Antystatyczny » sobota 29 cze 2019, 13:19

Pozwoliłem sobie skrobnąć kawałek kodu w języku C, bo lubię mieć własne rozwiązania dla takich drobiazgów jak TM1637. Ot, kawałek initu, ustawianie wartości poszczególnych cyfr, jasności wyświetlacza oraz odczyt stanu przycisków, który wypełnię kodem, gdy przyjdzie "Sen Antego".

Obsługa wygląda tak:

Kod: Zaznacz cały

#include <avr/io.h>
#include <util/delay.h>
#include "TM1637/TM1637.h"

int main(void)
{
   uint16_t cnt = 0;

   TM_init();

   while(1)
   {
      TM_SetDigit(0, cnt / 1000 );
      TM_SetDigit(1, cnt / 100 % 10 );
      TM_SetDigit(2, cnt / 10 % 10 );
      TM_SetDigit(3, cnt % 10 );

      TM_SetDuty(1);

      if(++cnt > 9999)
      {
         cnt = 0;
      }
      _delay_ms(100);
   }
}


Powyższe dzielenia i modulo to standardowa metoda rozdziału liczby na pojedyncze cyfry. Każdy, kto choć raz robił zegarek, zna tę metodę ;)

W dokumentacji układu jest informacja, by nie przekraczać 250kHz na pinie CLK. W przypadku mojego softu wartość ta utrzymuje się w okolicy 170kHz:
TM1637 clock frequency.png


Oprogramowanie oczywiście można uprościć/skomplikować. Każdemu wedle potrzeb, jak zwykł mawiać nasz forumowy człowiek d/s filozofii :) W obecnej formie zajmuje około 360B pamięci flash, ale jeszcze nieco spuchnie po uzupełnieniu funkcji odczytującej stan przycisków.
Soft dopasowany jest do platformy AVR, ale warstwę sprzętową wydzieliłem do pliku TM1637_LL.h, by można było sterować układem przy pomocy dowolnej innej platformy sprzętowej. Poniżej umieszczam spakowane pliki projektu (tym razem bez plików specyficznych dla eclipse - tylko źródła i nagłówki):

TM1637.7z
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
ZbeeGin
User
User
Posty: 492
Rejestracja: sobota 08 lip 2017, 17:16
Lokalizacja: Śląsko-Zagłębiowska Metropolia
Kontaktowanie:

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: ZbeeGin » niedziela 04 sie 2019, 16:48

Jakby ktoś chciał płytkę z tego projektu to mam wolne po 3 sztuki z każdej.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: Antystatyczny » poniedziałek 05 sie 2019, 22:29

„Sen Antego” wylądował na moim stole. Dzięki uprzejmości Zbyszka (ZbeeGin) nie musiałem męczyć się z jej wykonaniem, ponieważ zlecił wykonanie płytek specjalistycznej firmie. Dzięki!

Jak już ostatnio wspomniałem, soft do obsługi TM1637 można uprościć lub skomplikować, więc nie dałem się długo prosić Zbyszkowi, bym go skomplikował. A słowo kodem się stało. Tym razem mam do dyspozycji w pełni obsadzony układ, więc będę mógł wyświetlać 6 cyfr oraz kontrolować 16 przycisków. Szybki test mojego poprzedniego softu przebiega pomyślnie i już po kilkudziesięciu sekundach od uruchomienia IDE cieszyłem się widokiem zaświeconych wszystkich cyfr wyświetlacza. Wygląda więc na to, że tej części softu nie będę musiał modyfikować (czy aby na pewno?).

IMG_20190805_221356.jpg


Odczyt stanu przycisków nie należy do trudnych i z grubsza ogranicza się do wysłania komendy o kodzie 0x42, a następnie pobraniu jednego bajtu. Tylko tyle i aż tyle. Oczywiście operację tę należy przeprowadzić na piechotę, bo układ nie komunikuje się z otoczeniem przy pomocy szyny IIC. Na szczęście producent zamieścił w dokumentacji kod, który działa niemal od tzw. kopa. Wystarczy dopasować do własnych potrzeb polecenia związane ze sprzętową obsługą pinów mikrokontrolera. Przy okazji pokusiłem się o radykalne ograniczenie czasów oczekiwania po zmianach stanu na linii CLK. A oto kod:

Kod: Zaznacz cały


uint8_t TM_GetKeys(void)
{
   uint8_t command = TM_READ_SCAN_DATA;
   uint8_t data = 0;

   TM_start();
   TM_write8bits(command);
   TM_ack();

   TM_DIO_IN;
   for (uint8_t i = 0; i < 8; ++i)
   {
      TM_CLK_LOW;
      data >>= 1;
      DELAY_US(2);
      TM_CLK_HIGH;
      DELAY_US(2);

      if(TM_DIO_IS_HIGH)
      {
         data |= 0x80;
      }
   }

   TM_ack();
   TM_stop();

   return (uint8_t)(~data);
}



Jak widać w funkcji powyżej, nie znalazło się w niej nic odkrywczego. Niemal wierna kopia kodu z dokumentacji układu. No dobra, jest funkcja sterująca wyświetlaniem cyfr na poszczególnych wyświetlaczach, jest funkcja sterująca jasnością świecenia, a teraz do drużyny dołączyła funkcja odczytująca stan przycisków. Zdaje się, że to już wszystko, ale… No właśnie, brakuje obsługi kropek dziesiętnych. Generalnie sprawa jest prosta: wystarczy zaświecić najstarszy bit w bajcie wysyłanym jako treść cyfry, by zaświecić kropkę, jednak ze względu na brak możliwości odczytu (z układu) treści aktualnie wyświetlanej, nie można wykonać operacji READ-MODIFY-WRITE na bajtach znajdujących się wewnątrz układu. Do wyboru są dwie opcje:

1. Modyfikuję soft w taki sposób, by przez cały czas przechowywał dane o aktualnie wyświetlanych cyfrach. W razie potrzeby zaświecenia kropki, odwołuję się do zbuforowanych danych osobną funkcją. Na nich wykonuję operację READ-MODIFY-WRITE, a następnie wysyłam zaktualizowane dane do układu. To będzie kosztowało 6 bajtów pamięci RAM oraz konieczność dopisania funkcji, która będzie przyjmowała jako parametry numer cyfry oraz nowy stan kropki. Następnie odczyta odpowiedni bajt bufora, zaświeci lub zgasi najstarszy bit w bajcie, a na koniec wyśle bajt do układu oraz odświeży wyświetlacz.

2. Jawnie przekazuję stan kropki jako trzeci parametr funkcji sterującej treścią wyświetlaną na poszczególnych wyświetlaczach. Odpada konieczność buforowania danych o aktualnie wyświetlanej treści, ale odrobinę uprzykrza sterowanie kropką.


Doszedłem do wniosku, że przerzucanie kropki na inne miejsca potrzebne jest raczej rzadko, dlatego zdecydowałem się na drugą wersję obsługi, czyli sterowanie poprzez trzeci parametr funkcji TM_SetDigit. Wygląda to tak:

Kod: Zaznacz cały


void TM_SetDigit(uint8_t digit, uint8_t value, TM_DP_StateType dp);




Teraz chyba już można mówić o pełnej obsłudze układu TM1637. Niestety brakuje jakiejkolwiek automatyki, a co dopiero mówić o wygodzie użytkowania. Oczywiście można korzystać z tego softu na zasadzie okazjonalnych odczytów przycisków typu:

Kod: Zaznacz cały


result = TM_GetKeys();



… lub też sterowania cyferkami:

Kod: Zaznacz cały


TM_SetDigit(3, TM_DIGIT_VALUE_5, TM_DP_off );



… ale pakowanie tego w pętlę główną skutecznie zamuli program, obniży czytelność oraz utrudni jego odpluskwianie i ewentualną późniejszą rozbudowę. Z pomocą przychodzą: timer, obsługa zdarzeń i funkcja wywoływana zwrotnie. Na temat tych funkcji już się kiedyś rozpisywałem, więc jeśli ktoś jest głodny tej wiedzy, serdecznie zapraszam tutaj.
Przede wszystkim należy uruchomić jakiś timer, by ten cyklicznie wywoływał przerwanie, w którym umieszczę jedną z trzech dodatkowych funkcji, które dopisałem do już istniejącego softu. Funkcję, której jedynym zadaniem jest wystawienie flagi, która poinformuje umieszczoną w pętli głównej funkcję TM_Task() o tym, że należy odczytać stan przycisków. Flaga taka będzie się pojawiała 100 razy na sekundę, bo ustawiłem timer sprzętowy na generowanie przerwań z taką częstotliwością. Póki co mamy takie kawałki kodu:

Kod: Zaznacz cały


ISR(TIMER0_COMP_vect)
{
   TM_ISR();
}



oraz pętla główna programu:

Kod: Zaznacz cały


while(true)
{
   TM_Task();
}



TM_ISR() ustawia flagę, a TM_Task() na nią czeka. Gdy flaga jest ustawiona, funkcja sprawdza stan przycisków. Potem następuje porównanie aktualnego stanu przycisków do poprzedniego stanu. Ma to na celu ustalenie, czy został zwolniony któryś z przycisków, bo i taką akcję czasem trzeba oprogramować. Na koniec, o ile okaże się, że stan przycisków uległ zmianie od ostatniego sprawdzenia, wywoływana jest funkcja zwrotna, którą użytkownik (w tym przypadku ja sam) zarejestrował jeszcze przed wejściem do pętli głównej programu. Do tego (rejestracji) służy trzecia z dodanych przeze mnie funkcji, czyli:

Kod: Zaznacz cały


typedef void (*OnPress)(uint8_t);
void TM_RegisterKeyboardCallback(OnPress cb);



Funkcja przyjmuje tylko jeden parametr i jest nim wskaźnik na funkcję o prototypie
void fun(uint8_t), a więc wskaźnik na moją funkcję, która zostanie wywołana za każdym razem, gdy TM_Task() wykryje jakąś zmianę w stanie przycisków. Cel jest już bardzo blisko. Teraz wystarczy napisać samą funkcję zwrotną. Oto moment jej rejestracji:

Kod: Zaznacz cały


TM_RegisterKeyboardCallback(KeyboardCallback);



… i jej ciało:

Kod: Zaznacz cały


void KeyboardCallback(uint8_t code)
{
   static uint8_t cnt, dim = 8;


   switch(code)
   {
   case TM_KEYCODE_0:
      dim = 0;
      break;
   case TM_KEYCODE_1:
      dim = 1;
      break;
   case TM_KEYCODE_2:
      dim = 2;
      break;
   case TM_KEYCODE_3:
      dim = 3;
      break;
   case TM_KEYCODE_4:
      dim = 4;
      break;
   case TM_KEYCODE_5:
      dim = 5;
      break;
   case TM_KEYCODE_6:
      dim = 6;
      break;
   case TM_KEYCODE_7:
      dim = 7;
      break;
   case TM_KEYCODE_8:
      dim = 8;
      break;
   case TM_KEYCODE_9:

      break;
   case TM_KEYCODE_A:

      break;
   case TM_KEYCODE_B:
      cnt = 0;//clear counter
      break;
   case TM_KEYCODE_UP:
      cnt++;//increment sample counter
      break;
   case TM_KEYCODE_DOWN:
      cnt--;//decrement sample counter
      break;
   case TM_KEYCODE_LEFT:

      break;
   case TM_KEYCODE_RIGHT:

      break;
   case TM_KEYCODE_NONE:
      //key released! You can add an extra code here if release of the key also should be managed
      break;
   default:

      break;
   }

   //display counter on the left three digits
   TM_SetDigit(0, cnt / 100 % 10, TM_DP_off );
   TM_SetDigit(1, cnt / 10 % 10, TM_DP_off );
   TM_SetDigit(2, cnt % 10, TM_DP_on );

   //display raw key code on the right three digits
   TM_SetDigit(3, code / 100 % 10, TM_DP_off );
   TM_SetDigit(4, code / 10 % 10, TM_DP_off );
   TM_SetDigit(5, code % 10, TM_DP_off );

   TM_SetDuty(dim);
}



Nie ma w niej żadnej magii, ale krótko opiszę jej działanie. W chwili jej wywołania przekazany został do niej kod naciśniętego przycisku lub kod świadczący o zwolnieniu przycisku. Wszystko, co trzeba zrobić, to odczytać wartość zmiennej code, a następnie zareagować w zależności od potrzeb. W tym konkretnym przypadku mam na przyciskach od 0 do 8 sterowanie jasnością wyświetlacza, na przyciskach UP i DOWN zwiększanie i zmniejszanie wartości przykładowego licznika programowego na zmiennej cnt, a na przycisku B jest zerowanie tego licznika. Następnie wyświetlany jest stan licznika na trzech lewych cyfrach wyświetlacza (przy okazji włączyłem kropkę w cyfrze o numerze 2), a na prawych trzech cyfrach wyświetlany jest aktualny kod klawisza, który został przekazany przez zmienną code. Ot, taki przykładowy programik. Mam nadzieję, że nie jest nazbyt trywialny lub, w drugą stronę, skomplikowany. Oczywiście dodaję cały soft w formie paczki. Pozdrawiam.

TM1637.7z
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
dambo
Expert
Expert
Posty: 645
Rejestracja: czwartek 17 mar 2016, 17:12

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: dambo » poniedziałek 05 sie 2019, 23:03

No i elegancko :) mam ten układ na chińskiej płytce to kiedyś odpalę w końcu

To jeszcze jeśli można prosić - kodzik na GITa :)
Nowy blog o tematyce embedded -> https://www.embedownik.pl/

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: Antystatyczny » wtorek 06 sie 2019, 16:51

dambo pisze:To jeszcze jeśli można prosić - kodzik na GITa :)


Jeszcze trochę trzeba na to poczekać
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
ZbeeGin
User
User
Posty: 492
Rejestracja: sobota 08 lip 2017, 17:16
Lokalizacja: Śląsko-Zagłębiowska Metropolia
Kontaktowanie:

Re: [µProjekt] Panel wyświetlacza LED i klawiatury na układzie TM1637

Postautor: ZbeeGin » środa 07 sie 2019, 11:52

Najpierw to my musimy mieć organizacyjnego git-a... :(

Więc założyłem: https://github.com/microgeek-eu


Wróć do „DIY”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 13 gości