Przeszukaj forum
Pokazywanie wyników dla tagów 'led matrix'.
Znaleziono 3 wyniki
-
Urządzenie które dzisiaj prezentuje powstało na prośbę mojego znajomego, jest liczydłem wskazującym za ile sekund zostanie zrobione zdjęcie. Sercem układu jest płytka black pill z mikrokontrolerem STM32F401 urządzeniem wyświetlającym matryca LED fotolicznik jest sterowany z zewnętrznego urządzenia a więc służy jedynie do wyświetlania czasu do zdjęcia. Schemat Schemat oraz płytka została zaprojektowana w edytorze pro.easyeda jest to wersja pierwsza, są tutaj drobne błędy które należałoby poprawić w kolejnych iteracjach: Ogólnie w tej wersji nie zostało wykorzystane zasilanie/podtrzymanie RTC, gniazdo usb oraz wyjścia OC z tranzystorów Q6...Q9 zostawiłem te elementy na poczet kolejnego projektu który będzie ich wymagał. W samym schemacie nie jest nic nadzwyczajnego ot kolejne stany na wejściach PC817 mają zmieniać zawartość wyświetlaną na matrycy. Program Oprogramowanie zostało napisane z bibliotekami HAL od ST. Program składa się z głównej pętli, która cyklicznie wywołuje funkcję dmd_proces(); do obsługi panelu użyłem biblioteki https://github.com/bjlli/DMD-for-STM32 ponieważ w plikach udostępnionych przez autora brakuje .ioc dla cubeMX dodaję tego konfiga na końcu artykułu. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { //HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_2); scanDisplayBySPI(&hspi1); // HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); } //int status; uint8_t first_transition = 2; uint32_t timer_first_trans; /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM3_Init(); MX_RTC_Init(); MX_SPI1_Init(); MX_WWDG_Init(); /* USER CODE BEGIN 2 */ //Write_Font_To_Flash(); HAL_TIM_Base_Start_IT(&htim3); //HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); setFont(Arial_Black_14); //setFont(Arial_Black_14); DMD(1,1,OE_P10_GPIO_Port, OE_P10_Pin, SCLK_P10_GPIO_Port, SCLK_P10_Pin, A_P10_GPIO_Port, A_P10_Pin, B_P10_GPIO_Port, B_P10_Pin); HAL_GPIO_WritePin(LED_BLUE_GPIO_Port,LED_BLUE_Pin,1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_WWDG_Refresh(&hwwdg); // Watch dog if(0 == first_transition) { dmd_proces(); } if(2 == first_transition){ timer_first_trans = HAL_GetTick(); first_transition = 1; setFont(SystemFont_5x7); drawString(0,0,"DMD",strlen("DMD"),0); drawString(0,9,"v1:25",strlen("v1:25"),0); } if((1 == first_transition) && (HAL_GetTick() - timer_first_trans) > 3000) { clearScreen(1); first_transition = 0; } } /* USER CODE END 3 */ } Program po restarcie wyświetla krótką informację na temat wersji i roku kompilacji, resetuje watchdog i wskakuje w wyżej wymienioną dmd_proces: #include "anim.h" #include "main.h" #include "dmd.h" #include "stdio.h" #include "stm32f4xx_hal.h" const uint8_t xPosChar[] = { 0,13,11,11,11,11,11,11,11,11,7,7,7,7,7,7,0 }; //0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 void dmd_proces(void) { // uint32_t x = HAL_GetTick(); static uint32_t licznik; licznik++; static uint32_t bounce_timer = 0; static uint16_t last_gpio_status = 0; static uint8_t bounce_test = 0; uint16_t pinStatus = GPIOA -> IDR; pinStatus &= 0x000F; if((last_gpio_status != pinStatus) && (0 == bounce_test)) { bounce_timer = HAL_GetTick(); bounce_test = 1; last_gpio_status = pinStatus; }else if((1 == bounce_test) && ((HAL_GetTick() - bounce_timer) > 10)){ if(pinStatus == last_gpio_status) { // stabilny clearScreen(1); uint8_t ctab = ~ pinStatus & 0x000F; char c = (char)ctab+'0'; if(ctab){ setFont(BIG_FONT); if(ctab < 10) { drawChar(xPosChar[ctab],0,c,0); }else{ char str[3]; drawString(xPosChar[ctab],0,itoa(ctab,str,10),strlen(str),0); } }else{ setFont(Arial_Black_16_ISO_8859_1); drawChar(0,-3,'F',0); drawChar(15,-3,'T',0); drawChar(7,3,'O',0); drawChar(23,3,'O',0); } HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port,LED_BLUE_Pin); }else{ last_gpio_status = pinStatus; } bounce_test = 0; } } Działanie polega na odczytaniu ćwiartki portu A sprawdzenia czy impuls nie był zakłóceniem i jeśli stan został potwierdzony - na wyświetlaczu pojawi się odpowiedni komunikat. Widać też że zależnie od tego co ma być wyświetlane zmieniam również wielkość fontów, dlatego napis "foto" jest innej wielkości niż cyfry które się wcześniej pojawiają. Te ogromne znaki liczbowe pobrałem z https://github.com/ekapujiw2002/ex4_jws_dmd/blob/master/lib/DMD/MyBigFont.h wypełniają maksymalnie przestrzeń roboczą panelu LED. Płytka i obudowa PCB została wykonana w warunkach domowych jako jednowarstwowa z montażem mieszanym przewlekanym i smd, połączenia brakujące - które normalnie zostałyby umieszczone na warstwie TOP wykonałem kynarem 0.4mm2 Ponieważ układ jest bardzo prosty obyło się bez wpadek i po montażu i sprawdzeniu pod kątem zwarć dał się uruchomić bez znaków dymnych. Obudowę dla pcb zaprojektowałem w fusion360 została wydrukowana z materiału PETG, zaś całość jest wbudowana w konstrukcję z blachy giętej malowanej proszkowo. Linki i źródła: https://sklep.msalamon.pl/produkt/stm32f401ccu6-dev-board/ https://tinyurl.com/4fm2bvx7 https://pro.easyeda.com/ https://github.com/bjlli/DMD-for-STM32 https://github.com/ekapujiw2002/ex4_jws_dmd/blob/master/lib/DMD/MyBigFont.h dmd01.zip
-
Cześć, dziś pokażę Wam, w jaki sposób złożyć do kupy moduł ESP8266 (w tym wypadku płytkę WeMos D1 mini) oraz matrycę LED na sterowniku MAX7219. Oprócz tego będziemy potrzebować paru przewodów połączeniowych, lutownicy z cyną, obudowy do zegarka oraz przewód microUSB do zasilenia naszego układu. Całość projektu jest dostępna w repozytorium na moim Githubie. Obudowa Jako obudowę użyłem sklejki o grubości 6 milimetrów, którą zamówiłem na aukcji Allegro razem z docięciem. Całość obudowy z dostawą kosztowała mnie mniej niż 40 złotych. Zaprojektowałem obudowę korzystając z programu Inkscape. Następnie została ona sklejona i pokryta lakierobejcą w kolorze jasnego dębu. Na front obudowy nakleiłem mleczną plexi o grubości 3 mm, którą dostałem w lokalnym sklepie za 5 złotych. Elektronika Tutaj będzie dużo łatwiej, gdyż wystarczy połączyć tylko odpowiednie piny. Połączyłem zgodnie z adnotacją w bibliotekach do obsługi MAX7219. Należy pamiętać, że WeMos D1 operuje na napięciu 3.3V na szczęście sterownik MAX7219 akceptuje je i nie będzie problemu aby układ ruszył. Na zdjęciu połączenie za pomocą przewodów z haczykami. Kod programu Przed kompilacją programu, należy dodać do Arduino IDE obsługę płytek opartych na ESP8266 (opisał to SOYER w tym temacie). Będziemy potrzebować trzech bibliotek, które nie są standardowo dołączone do Arduino IDE: MD_MAX72XX - dzięki której nasz procesor skomunikuje się ze sterownikiem MAX7219 MD_Parola - biblioteka rozszerzająca funkcje MD_MAX72XX NTPClient - dzięki niej zyskamy możliwość pobierania czasu z Internetu bez potrzeby używania modułu RTC. Po dodaniu bibliotek, kod wygląda następująco: #include <MD_Parola.h> #include <MD_MAX72xx.h> #include <SPI.h> #include <ESP8266WiFi.h> #include <NTPClient.h> #include <ESP8266WebServer.h> #include <WiFiUdp.h> #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4 #define CLK_PIN D5 // or SCK #define DATA_PIN D7 // or MOSI #define CS_PIN D8 // or SS MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); WiFiUDP ntpUDP; const char *ssid = ""; const char *password = ""; NTPClient timeClient(ntpUDP, "0.pl.pool.ntp.org", 3600, 60000); WiFiServer server(80); uint8_t frameDelay = 25; textEffect_t scrollEffect = PA_SCROLL_LEFT; #define BUF_SIZE 512 char curMessage[BUF_SIZE]; char newMessage[BUF_SIZE]; bool time_interval = false; String data; unsigned int run_seconds = 0; String timeCheck(){ timeClient.update(); data = timeClient.getFormattedTime(); data.toCharArray(newMessage, BUF_SIZE); P.displayText(newMessage, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT); return data; } String wifiCheck(){ WiFiClient client = server.available(); while(client.available()){ String req = client.readStringUntil('\r'); req = req.substring(5,req.length()-9); req.replace("%20", " "); client.flush(); String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nReq: " + req + "</html>\n"; client.print(s); delay(1); client.stop(); switch(req[0]){ case 's': data = req.substring(2); P.displayScroll(curMessage, PA_LEFT, PA_SCROLL_LEFT, frameDelay); return data; break; case 'i': data = req.substring(2); P.setIntensity(data); break; } } } void setup() { P.begin(); P.displayClear(); P.displaySuspend(false); P.displayScroll(curMessage, PA_LEFT, PA_SCROLL_LEFT, frameDelay); P.setIntensity(0); curMessage[0] = newMessage[0] = '\0'; WiFi.begin(ssid, password); while ( WiFi.status() != WL_CONNECTED ) { delay ( 500 ); } timeClient.begin(); server.begin(); sprintf(curMessage, "%03d:%03d:%03d:%03d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]); } void loop() { if ( (millis()/1000 - run_seconds) > 30 ){ run_seconds = millis()/1000; time_interval = true; } if (time_interval){ data = timeCheck(); time_interval = false; } data = wifiCheck(); data.toCharArray(newMessage, BUF_SIZE); if (P.displayAnimate()) { strcpy(curMessage, newMessage); P.displayReset(); } } W zależności od zakupionego modułu trzeba będzie wybrać wersję hardware sterownika MAX7219. Definiujemy ją w linijce 10: #define HARDWARE_TYPE MD_MAX72XX::FC16_HW Obecnie dostępne typy sprzętowe to: FC16_HW, PAROLA_HW, GENERIC_HW, ICSTATION_HW. Musimy tutaj dobrać wartość eksperymentalnie. Niewłaściwy typ sprzętowy powoduje błąd w kolejnosci wyświetlania oraz w kolejności animacji poszczególnych pikseli matrycy. Dodatkowa opcja (własny tekst) W kodzie dociekliwi zobaczą, że jest możliwość wyświetlenia własnego tekstu. Po uruchomieniu programu na wyświetlaczu przewinie się adres IP, który WeMos uzyskał z naszego routera. Po otworzeniu strony z poziomu przeglądarki (lub wywołaniu polecenia curl) na stronę: http://<IP>/s=<TEXT> na wyświetlaczu będzie on przewijany od prawej do lewej strony przez maksymalnie 30 sekund. Dodatkowa opcja (zmiana jasności wyświetlacza) Można również zmienić jasność wyświetlacza, albo na stałe (w kodzie linijka: 86) P.setIntensity(<liczba z zakresu 0-15>); lub poprzez stronę www pod adresem: http://<IP>/i=<LICZBA Z ZAKRESU 0-15> gdzie 0 - to wartość minimalna, a 15 odpowiada za maksymalny poziom świecenia. Zegarek prezentuje się następująco: obudowa.pdf
- 29 odpowiedzi
-
- 5
-
-
Cześć, używał może ktoś układu scalonego firmy "Texas Instruments" o symbolu TLC5920 (sprzętowy sterownik matrycy LED 16x8). Próbowałem napisać sterownik w C do tego układu (STM32F103 taktowany 72MHz) ale coś mi "nie trybi". Dla stałych wzorów wyświetlanie matrycy jest OK. Gdy jednak próbuję wyswietlać dane z tablicy [16][9] odświeżane z około 20 Hz to wystepują błędy polegające na tym, że w niektórych wierszach minimalnie świecą się kolumny, które nie powinny. Tutaj linki do strony produktu i data-sheet'a: https://www.ti.com/product/TLC5920 https://www.ti.com/lit/ds/symlink/tlc5920.pdf?ts=1634571932501&ref_url=https%3A%2F%2Fwww.ti.com%2Fproduct%2FTLC5920 Jedyna biblioteka w C, którą znalzłem to ta do Arduino z tego projektu: http://www.carbonfrog.com/Products/MC201V1.html ale tam sposób obsługi programowej matrycy jest nieodpowiedni (i dokładność generacji przebiegów słaba). Spróbuję wygenerować "timing diagram" dla tego układu na FPGA, jak zadziała to napiszę kod drivera w języku C. Jakby ktoś używał tego scalaka to byłbym wdzięczny za jakieś użyteczne uwagi. Pozdrawiam