Przeszukaj forum
Pokazywanie wyników dla tagów 'Arduino'.
Znaleziono 521 wyników
-
Witam, taki luźny temat mi przyszedł do głowy z racji tego że mam kilka starych komputerów stacjonarnych zacząłem sie zastanawiać czy można by je wykorzystać do podobnych celów jak np raspberry pi. Oczywiście biorąc pod uwagę gabaryty "skrzynki" rozważam np jakąś instalacje stacjonarną typu grow box itp. Wiadomo pojawia się kwestia wejść i wyjść. Czy na plycie głównej jest coś co można wykorzystać w tym celu? Ewentualnie złącza usb dają chyba duże możliwości w tym zakresie, tylko jak to ugryźć programowo. Wiecie coś o takich projektach/wykorzystaniu komputera stacjonarnego? Doradźcie coś jak temat ugryźć bo nawet google za dużo nie podpowiada w tym temacie. Zapraszam wszystkich do dyskusji. Pozdrawiam
-
Taki mały projekcik - coś dla bezwzrokowców. Czyli nie tylko dla niewidomych i słabowidzących, ale również dla tych, którzy nie mają ochoty albo możliwości gapienia się na wyświetlacz... Czyli coś w rodzaju wypasionego termometru albo (jak kto woli) mini-stacji pogodowej. Ale zacznę może od genezy projektu. Szukając pewnego sprzętu do domu natrafiłem na osobę poszukującą mówiącego termometru pokojowego. Ktoś tam rzucił jakimiś linkami... z ciekawości zajrzałem. No i oczywiście pierwszy do Altix. Termometr co prawda niedrogi, ale za yi jak zwykle w tej firmie "kłopoty ze stanem magazynowym". Kolejne ceny wyglądały raczej mało zachęcająco... Jako że taki "gadający termometr z prognozą pogody" stanowi integralną część mojego "wygodnego domu" zacząłem zastanawiać się, czy coś podobnego (tylko bez tej "wygodnodomowej" otoczki) mogłoby się komuś przydać. No i po dłuższym zastanowieniu wyszło mi coś takiego: W moim przypadku sprawdza się to idealnie, tak że pewnie znaleźli by się zainteresowani... Przede wszystkim musi być to urządzenie DIY. Z uwagi na możliwości zastosowania różnych podzespołów raczej nie byłoby możliwe zaprojektowanie PCB czy obudowy - poza tym urządzenie powinno być możliwe do zbudowania przez początkującego adepta sztuki elektroniki (z możliwością wsadzenia tego na płytkę stykową włącznie). Dodatkowo wszystkie elementy muszą być dostępne w handlu, a przede wszystkim tanie! Wybrałem ESP32 jako "serce" urządzenia. Powodów było kilka, ale najważniejsze było to, że mam dobrze przetestowany syntezator mowy właśnie na ESP. Również ceny modułów są atrakcyjne. Jednocześnie nie mogę wymagać umiejątności użerania się z wersjami bibliotek (które lubią gryźć się albo z definicją płytki, albo ze sobą). Co prawda źródła programu dla Arduino powinny być dostępne, ale warto zadbać o to, aby ktoś kto nie ma zielonego pojęcia o programowaniu mógł wrzucić soft na płytkę i skonfigurować całość. Tak że wymagana by była równioeż wersja binarna, możliwa do prostego załadowania z pomocą esptool (Linux, Mac) czy FlashTool (Windows). Z wstępnych założeń wyszło mi coś takiego: Trzy typy komunikatów: Najkrótszy to tylko godzina i temperatura. Dłuższy to godzina, data, temperatura oraz dodatkowe parametry zależne od możliwości zastosowanych podzespołów (np. ciśnienie i wilgotność) Najdłuższy to ten sam co dłuższy, ale wzbogacony o dane ściągnięte z Internetu Postanowiłem wykorzystać serwis open-meteo.com. Tak więc zgodnie z możliwościami serwisu dane muszą zawierać bieżące warunki pogodowe oraz skróconą prognozę pogody. Uznałem, że rozwiązanie które mam w domu powinno się sprawdzić - czyli prognoza na dziś i jutro, lub po którejś godzinie na jutro i pojutrze. Konieczna jest też możliwość ustawienia wszystkiego co się da za pomocą terminala serial - po to, aby nie było trzeba robić jakichś zależności w czasie kompilacji. Jeśli chodzi o elektronikę, uznałem, że podstawową płytką będzie ESP32 DevKit. Ma wystarczającą ilość pamięci (zarówno RAM jak i Flash), wszystkie potrzebne interfejsy a co ważniejsze - jest tania i dostępna. Konieczny jest również jakiś wzmacniacz I2S - czyli znów najtańsza opcja: MAX98357. Dla niewtajemniczonych: monofoniczny dekoder I2S zawierający wzmacniacz mocy do 3W. Cena jest również zachęcająca, z dostępnością nie ma problemu. Do tego jeden przycisk (dwa to o jeden za dużo), jakiś zasilaczyk 5V o mocy wystarczającej na zasilenie wzmacniacza - i to wszystko. Jako czujniki postanowiłem dopuścić następujące: W pomieszczeniu - BMP180, BMP280, DS18B20. Na zewnątrz - DHT22, DHT11, DS18B20 z możliwością bezprzewodowego połączenia. Oczywiście można nie podłączać któregoś z urządzeń - w najprostszym (najtańszym) przypadku można zastosować tylko DS18B20 do pomiaru temperatury w pomieszczeniu, czas oraz warunki bieżące dla lokalizacji pobierać z Internetu. DHT11 oczywiście nie powinien być stosowany, ale po prostu taki mam 🙂 Jednocześnie w razie potrzeby byłbym w stanie dorobić BME280 jako czujnik wewnętrzny (jak to słusznie @mkwiatkowski zauważył, odczyt wilgotności może być potrzebny przy pracującej klimatyzacji). Dodatkowym wyposażeniem może być zegarek DS3231 (jeśli istnieje możliwość utraty połączenia z Internetem). Można również dodać detektor IR aby sparować urządzenie z dowolnym pilotem. Prace zacząłem już jakiś czas temu, ale nie chciałem nic pisać dopóki nie uzyskałem pewności, że zadanie jest wykonalne. W tej chwili działają wszystkie moduły, urządzenie sobie gada, coś tam mierzy, nawet serwer www wystawia do bieżących ustawień... Tylko pytanie: czy ktoś to wykorzysta? Czy przypadkiem nir planuję zrobienia kawału dobrej, nikomu niepotrzebnej roboty? Bo co prawda pisząc program musiałem rozwiązać kilka dość interesujących (z punktu widzenia Arduinowo-ESPowego programisty) problemów, ale więcej nie przewiduję, a czego trzeba to już się nauczyłem 🙂 I dla zachęty: plik mp3 z prognozą pogody (nagrany na pececie, ale to taki sam syntezator jak na ESP32): meteo.zip Prosiłbym o wypowiedzi czy dalsza praca ma sens. czy mam sobie darować i zająć się czymś bardziej pożytecznym. A może jakieś pomysły?
-
Witam wszystkich czytelników. Zainspirowałem się w wakacje postem użytkownika @Krzysiek97, który przedstawił swoją kierownice do gier na bazie arduino leonardo: Kierownica PC - wersja 2. Z racji tego że lubię grać w gry wyścigowe i symulatory postanowiłem zbudować własną kierownicę z dodatkowymi akcesoriami. Nie chciałem przerabiać starej gotowej kierownicy do komputera, więc wpadłem na pomysł aby zbudować całe stanowisko. Materiał o tym stanowisku/ projekcie znajduję się na moim kanale na YT do którego was zapraszam Kierownica do komputera na bazie arduino Chciałem aby w tym stanowisko znajdowała się kierownica o kącie obrotu 900 stopni, sprzęgło, gaz, hamulec, 8 biegów + wsteczny (8 biegów ponieważ tyle mają niektóre samochody np. w Forza Horizon 4), hamulec ręczny, 2 joystiki (do sterowania maszynami w Farming Simualtor), button matrix 4x5 = 20 przycisków (przypisanych do rożnych akcji w grach) i zegary do wyświetlania prędkości i obrotów. Tak więc gdzieś w połowie lipca zacząłem szukać potrzebne części. Pierwszym problemem z którym się spotkałem była niewystarczająca ilość wejść w arduino leonardo. Ktoś na tym forum podsunął mi płytki Nucleo 64 na STM32, obawiałem się jednak czy programy które wcześniej znalazłem w internecie będą z nimi współpracować. Bawiłem się naco wcześniej arduino lecz nucleo nie stąd moja niepewność ponieważ zaczynałem dopiero wtedy zabawę z tym wszystkim. Zdecydowałem się jednak zostać przy arduino i zakupiłem 3 płytki, po jednej dla każdego programu który obsługuję inną część stanowiska, ponieważ i tak nie ma prgoramu który ogarnie wszystkie moje rzeczy na raz. A więc tak: Arduino Leonardo - program EMC Utility Lite (z początku korzystałem z RFR Whell Configuration elcz sprawiał on problemy) - obsługuję kierownicę, pedały, hamulec ręczny - Link do programu EMC, Jak zainstalować program Pierwsze Arduino Pro Micro - program MMJoy2 - obsługuję button matrix i 2 joysticki - Link do programu MMJoy2, Jak zainstalować program Drugie Arduino Pro Micro - program SimHub - obsługuję zegary/wyświetlacze - Link do programu SimHub Zamówiłem też 20 guzików (push button) 10 styczników krańcowych 2 Joysticki 2 wyświetlacze Tm1638, 1 wyświetlacz Max7219 (zamówiłem też sterownik silnika BTS7960 lecz na razie nie zakładałem FFB). Rzeczy które miałem w domu to: 2 potencjometry 10k Ohm, stycznik krańcowy ls-11s, kable kawałki plastiku, materiału i gumy. Za postawę stanowiska posłużyła mi deska rozdzielcza i fotel od mazdy mx-5 i kierownica od mazdy 626. Całość jest przyspawana do rurki i przykręcona do euro palety. Z racji tego że deska pochodzi z anglika to nie mogłem zamontować zwykłych zegarów w miejscu poduszki pasażera. Zamieszczam tutaj schematy podłączeń danych elementów: Drugim problemem który chce tu opisać, było przeniesienie/ zczytanie obrotu z kierownicy do arduino. Na początku chciałem wykorzystać enkoder optyczny z swojej starej drukarki, lecz gubił się on często i nie działał dokładnie, więc kupiłem enkoder inkrementalny 600ppr. Nie będę się już tak rozpisywał co jak i gdzie jest skręcone dlatego wszystko pokazane i omówione jest w filmiku do którego link jest na początku posta. Więc to jest dodatkowy materiał dla ciekawych. Podsumowując: koszt budowy stanowiska zamknął się dla mnie w kwocie 300zl, czas realizacji od pierwszego pomysłu do zbudowania całości i upewnienia się że wszystko jest sprawne to 6 miesięcy. Tak oto prezentuję się kierownica i jej działanie w grze Forza Horizon 4 Na koniec pytanie głownie do administratora, czy i kiedy będzie znowu dostępny konkurs Opisz elektroniczne DIY i odbierz 50 zł rabatu do Botland?
- 10 odpowiedzi
-
- 6
-
Witam, Szukam czegos do nauki elektroniki/programowania dla dziewczyni zaraz osmio letniej. Natknalem sie na scratch ktory pewnie wdrozymy ale corka chciala tez pobudowac roboty 🙂 tak natknalem sie na forbota. Szczerze fajnie by bylo jakbyscie pisali od jakiego wieku, co polecacie.. 😉 z wstepnego przejrzenia kurs podstaw elektroniki jest za bardzo teoretyczny na ten wiek. Arduino i raspherry pi tez chyba za wczesnie. Zaatanawiam sie nad micro.bit ale tez nie wiem czy to nie za wczesnie dla 7-8 latki... Myslalem o nauce lutowania i budowania tym sposobem czegos i przy okazji uczenia sie troche. Co myslicie o takim pomysle? Czy sa jakies zestawy dla dzieci tego typu? na youtubie mignal mi kanal gdzie ktos z corka 7 letnia lutuje.. Osobiscie nie znam sie na tym wiec bede uczyl sie z corka (programowac umiem, kiedys cos tam polutowalem ale daleko do stwierdzenia ze cos umiem czy moge przekazac jakas wiedze) Z gory dziekuje za sugestie i pozdrawiam
- 7 odpowiedzi
-
- Elektronika
- Arduino
- (i 2 więcej)
-
Witam, podczas wykonywania zadań w części #6 2 kursu arduino na tej stronie dotyczącego wyświetlaczy 7 segmentowych natknąłem się na problem. Mianowicie, niektóre znaki (0, 2, 3, C) nie są wyświetlane tak jak należy, czy to podczas własnoręcznego ustawiania segmentów tak jak jest w kursie, czy podczas korzystania z biblioteki SevSeg. Wszystkie podłączenia oraz kody są zrobione tak jak w kursie oraz dokładnie sprawdzone. w załącznikach podane kolejno zdjęcia wyświetlania liczb 23,04,78. Tak jak widać, niektóre liczby są wyświetlane poprawnie, a niektóre nie. Będę wdzięczny za udzielenie pomocy lub rad związanych z tym problemem
- 1 odpowiedź
-
- Arduino
- wyświetlacz
-
(i 1 więcej)
Tagi:
-
Nie wiem z jakiego powodu, Monitor Portu Szeregowego zaczął wyświetlać w każdej linii godzinę. Wygląda to tak jak na obrazku poniżej. Jak można to wyłączyć i jak można to włączyć?
- 4 odpowiedzi
-
#define L_PWM A5 #define L_DIR 4 #define R_PWM 6 #define R_DIR 9 #define led 13 #define przycisk 2 #define PWM_MAX 165 #define buzzer 10 #define lSensor A1 #define rSensor A0 bool jedzie = false; #define granica 940 void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(L_DIR, OUTPUT); pinMode(L_PWM, OUTPUT); pinMode(R_DIR, OUTPUT); pinMode(R_PWM, OUTPUT); pinMode(przycisk, INPUT_PULLUP); pinMode(buzzer, OUTPUT); pinMode(lSensor, INPUT_PULLUP); pinMode(rSensor, INPUT_PULLUP); } void loop() { // put your main code here, to run repeatedly: if (digitalRead(przycisk) == LOW){ jedzie = true; } if (jedzie == true){ leftMotor(50); rightMotor(50); if (digitalRead(lSensor) == LOW || digitalRead(rSensor) == LOW){ rightMotor(-50); leftMotor(-50); digitalWrite(buzzer, 1); delay(1000); rightMotor(-50); leftMotor(50); digitalWrite(buzzer, 0); delay(250); } } } void leftMotor(int V){ if(V > 0){ V = map(V, 0, 100, 0, PWM_MAX); digitalWrite(L_DIR, 1); analogWrite(L_PWM, V); } else{ V = abs(V); V = map(V, 0, 100, 0, PWM_MAX); digitalWrite(L_DIR, 0); analogWrite(L_PWM, V); } } void rightMotor(int V){ if(V > 0){ V = map(V, 0, 100, 0, PWM_MAX); digitalWrite(R_DIR, 0); analogWrite(R_PWM, V); } else{ V = abs(V); V = map(V, 0, 100, 0, PWM_MAX); digitalWrite(R_DIR, 1); analogWrite(R_PWM, V); } } void stopMotors(){ analogWrite(L_PWM, 0); analogWrite(R_PWM, 0); } boolean leftSensor(){ if (analogRead(lSensor) > granica){ return 1; } else { return 0; } } boolean rightSensor(){ if(analogRead(rSensor) > granica){ return 1; } else { return 0; } } (Lewy silnik mam odwrócony, więc zamieniłem 1 z 0 i 0 z 1.)
-
Często pojawia się konieczność użycia pakietu płytko w konkretnej wersji. Szczególnie dla ESP32, gdzie różne wersje pakietów mogą działać inaczej, a wersje maior w ogóle nie są ze sobą kompatybilne - jest to wręcz niezbędne. Artuino IDE oczywiście pozwala zainstalować dowolną wersję pakietu, ale tylko jedną konkretną, a proces instalacji wcale nie jest taki szybki. Dodatkowo jeśli dokonaliśmy jakichś zmian w katalogu pakietu (w moim przypadku to dodanie nowych układów partycji i modyfikacja boards.txt) zaczyna być to niespecjalnie wygodne... Postanowiłem więc zrobić prosty przełącznik wersji. Działa dla ESP32, ale można go oczywiście zmodyfikować tak, aby działał dla dowolnych płytek. Rozwiązanie jest niestety linux-only, ale po drobnych zmianach (ścieżki, polecenia powinny działać tak samo) powinno ruszyć na Macu. A na pewno nowoczesny Windows pozwoli na zrobienie podobnego przełącznika... pozwoli, prawda? Kod jest stosunkowo prosty: #!/bin/bash #położenie docelowego pakietu ESP32 dstitem=${HOME}/.arduino15/packages/esp32 #tu są różne wersje srcdir=${HOME}/.arduinoESP32 if [ -n "$1" ]; then if [ "$1" = "off" ] ; then #przygotowanie do instalacji rm ${dstitem} echo "Gotowy do instalacji nowej wersji" exit 0 fi if [ "$1" = "show" ] ; then if a=$(readlink ${dstitem}) ; then basename $a else echo "Brak skonfigurowanej wersji" fi exit 0 fi # parametr to numer wersji src=${srcdir}/$1 if [ ! -d ${src} ] ; then echo "Brak wersji $1" else ln -sfn ${src} ${dstitem} echo "Ustawiona wersja $1" fi else #bez parametrów listuje zawartość katalogu ls ${srcdir} fi Jak tego użyć? Trzeba utworzyć plik o zawartości jak wyżej (ja nadałem mu nazwę espversion) i nadać mu prawa do wykonywania. Skrypt najlepiej utworzyć w katalogu gdzie przechowujemy własne polecenia (np. ~/bin/). Następnie trzeba sobie stworzyć katalog, który będzie zawierał wszystkie wersje pakietów. Ja utworzyłem do tego celu katalog ~/.arduinoESP32. Następnie należy kolejno zainstalować potrzebne wersje, a po instalacji przenieść zawartość pakietu do odpowiedniego miejsca. Przykładowo: po instalacji wersji 3.0.4 należy wykonać coś w stylu: mv ~/.arduino15/packages/esp32 ~/.arduinoESP32/3.0.4 Pamiętać należy, że przed jakąkolwiek próbą instalacji nowej wersji należy usunąć link ~/.arduino15/packages/esp32 - jeśli tego nie zrobimy, wersja zostanie nadpisana! Mamy więc teraz następujące możliwości: Listowanie dostępnych wersji: espversion Pokazanie która wersja jest aktualnie wybrana: espversion show Przygotowanie do instalacji nowej wersji (usunięcie linku): espversion off Zmiana wersji: espversion <numer_wersji> Tak więc teraz można sobie zmieniać wersje w locie, np: espversion 2.0.17 włączy wersję 2.0.17, o ile taką mamy przygotowaną. Pamiętać równie należy, że przy przełączaniu wersji Arduino IDE powinien być wyłączony! Jeśli ktoś korzysta z mojego pyrduino, należy przed kompilacją wydać polecenie: ardu -clean I to tyle. Przyjemnego przełączania życzy ethanak
-
Witam, chciałbym pochwalić się moim pierwszym wrzuconym tu projektem: Stacją pogodową! Użyłem tutaj tych elementów elektronicznych: Arduino UNO (klon) czujnik wilgotności i temperatury DHT11 LCD 2x16 konwerter I2C W nazwie projektu, DHT11 wzięło się właśnie z nazwy czujnika temperatury i wilgotności. Nie wiem czy mogę nazwać to stacją pogodową bo wyświetla temperaturę i wilgotność tylko z jednego miejsca. 🙂 Do wyświetlania użyłem wyświetlacz LCD 2x16 z konwerterem I2C, głównie z tego powodu że jest on łatwy w obsłudze i jest mało podłączania. Użył bym wyświetlacza TFT bo ładniej by to wszystko wyglądało, ale uczę się dopiero programowania i dalej mam problem z wyświetlaniem wartości na TFT. Ta stacja ma dwie funkcje, pomiar temperatury i pomiar wilgotności. Tutaj jest ilustracja podłączania modułów i czujników do Arduino. Nazywam to prototypem sami wiecie czemu. Niestety ale nie mam gdzie wkładać moich projektów, przez co wyglądają jak prototypy. Kod który użyłem nie jest skomplikowany. Na samym początku tworzy się znak stopnia, w void setup() wyświetlamy napisy temperatura i wilgotność, a potem wyświetlamy wartości temperatury i wilgotności gdzie przydaje nam się stworzony na początku kodu znak stopnia. Tutaj jest kod który użyłem do projektu: #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); byte znak_stopnia[8] = { 0b00111, 0b00101, 0b00111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 }; int gate=11; volatile unsigned long duration=0; unsigned char i[5]; unsigned int j[40]; unsigned char value=0; unsigned answer=0; int z=0; int b=1; void setup() { lcd.init(); lcd.backlight(); lcd.print("Temperatura"); lcd.setCursor(0,1); lcd.print("Wilgotnosc"); lcd.createChar(1, znak_stopnia); lcd.setCursor(14,0); lcd.write(1); lcd.print("C"); lcd.setCursor(13,1); lcd.print("%"); } void loop() { delay(1000); while(1) { delay(1000); pinMode(gate,OUTPUT); digitalWrite(gate,LOW); delay(20); digitalWrite(gate,HIGH); pinMode(gate,INPUT_PULLUP); duration=pulseIn(gate, LOW); if(duration <= 84 && duration >= 72) { while(1) { duration=pulseIn(gate, HIGH); if(duration <= 26 && duration >= 20){ value=0;} else if(duration <= 74 && duration >= 65){ value=1;} else if(z==40){ break;} i[z/8]|=value<<(7- (z%8)); j[z]=value; z++; } } answer=i[0]+i[1]+i[2]+i[3]; if(answer==i[4] && answer!=0) { lcd.setCursor(12,0); lcd.print(i[2]); lcd.setCursor(11,1); lcd.print(i[0]); } z=0; i[0]=i[1]=i[2]=i[3]=i[4]=0; } } Nie jest on cały robiony przeze mnie bo ja go tylko zmodyfikowałem oryginalny kod i projekt pochodzi z tego filmu na YouTube. Użyta jest tu użyta biblioteka LiquidCrystal_I2C którą pewnie wszyscy i tak mają. 🙂 I teraz najciekawsza część tego wpisu, czyli film na którym testuje moją stacje! (Polecam obejrzeć w prędkości 2x) Jak można zobaczyć na filmie, temperatura wynosiła 30 stopni. Po przyłożeniu rozgrzanego grotu od lutownicy temperatura wzrosła do 38 stopni, natomiast wilgotność zaczęła spadać. Przez to że cały czujnik się nagrzał to nawet i po oddaleniu grotu od czujnika temperatura jeszcze wzrosła o 2 stopnie. Niestety ale przez to że za bardzo skupiłem się na nagrywaniu to delikatnie stopiłem plastik z czujnika, ale na szczęście nie zakłóca to pomiarów. 🙂 To tyle z mojej strony, bardzo Ci dziękuję jeśli przeczytałeś to całe. Będzie mi bardzo miło gdy napiszesz opinie i uwagi, nie tylko odnośnie projektu i kodu ale też odnośnie tego jak napisałem ten artykuł. Bardzo dziękuję i pozdrawiam! 😄
-
Witam. Dzisiaj chciałem po raz pierwszy wgrać jakiś kod do Attiny85 używając klona Arduino UNO jako programatora. Zainstalowałem AttinyCore w tym wszystkie potrzebne sterowniki. (z tego poradnika i po zainstalowaniu robiłem wszystko co jest w tym filmie) Po kliknięciu przycisku Burn bootloader (w sekcji tools) wystąpił błąd: Failed chip erase: uploading error: exit status 1 Wszystko było robione na Arduino IDE wersji 2.3.2 Zdjęcia tego jak to podłączałem Podłączałem to wszystko według tego schematu (schemat pochodzi z filmu o którym pisałem powyżej): Wybrałem takie same opcje jakie zostały wybrane w tym filmie oraz płytkę: ,,ATTiny 45/85 (Obtiboot)" (chodzi o te opcje otoczone czerwoną linią): Kod który zrobiłem na pewno jest dobry bo po kliknięciu w przycisk ,,Verify" kompilator nie wykrywa żadnych błędów, ale na wszelki wypadek pokażę go tutaj: void setup() { pinMode(1, OUTPUT); } void loop() { digitalWrite(1, HIGH); delay(100); digitalWrite(1, LOW); delay(100); } Na samym końcu pokażę jeszcze kilka zdjęć które mogą się przydać (screeny robione przy podpiętym Arduino): Mam nadzieję że podałem wystarczająco dużo informacji Z góry dziękuję za poświęcony czas! 🙂
-
Sprzedam płytkę - klon Arduino UNO R3 CH340 Mikrokontroler: ATmega328P SMD Nowa, cena 20 zł Gwarancja rozruchowa: 7 dni Wysyłka: paczkomat - 12 zł kurier - 15 zł pobranie - 25 zł Mam 8 szt. Zainteresowanych proszę o kontakt w wiadomości prywatnej.
-
POMOC Arduino i błędne odczyty z odbiornika podczerwieni
Mariusz_Nadolny opublikował temat w Arduino i ESP
Cześć, chciałem zrobić jakiś prosty program używający odbiornika podczerwieni. Mam jednak problem z tym, że źle odbierane są dane. Używam tego klasycznego kodu: #include <IRremote.h> IRrecv irrecv(2); decode_results results; void setup() { Serial.begin(9600); irrecv.enableIRIn(); } void loop() { if (irrecv.decode(&results)) { Serial.print(results.value); Serial.println(" "); irrecv.resume(); } } To są dane jakie widzę po wciskaniu jednego przycisku: więc jak widać wartości dla jednego przycisku są różne, a transfer tej liczby na hex w ogóle nie działa. Sprawdzałem czy piny gnd, 5v i 3,3v nadają odpowiedni stan na wyjście pinów i zdaje się, że tak (nie potrafię dobrze posługiwać się arduinowym językiem, więc wysyłam link do poradnika, z którego korzystałem https://learn.andoyaspace.no/ebook/the-cansat-book/common/getting-started/software-start-up-and-test-of-arduino-uno/). Nie mam pojęcia dlaczego to co robię nie działa. Jeżeli ktoś ma jakiś pomysł to z wielką przyjemnością poczytam, bo flustruje mnie to, że nie potrafię nic z tym zrobić :). Dodam jeszcze, że Arduino jest oryginalne, a odbiornik, z którego korzystam to TSOP31236. Robiłem to parę miesięcy temu i wtedy wszystko działało.- 1 odpowiedź
-
- 2
-
- pomoc
- Początkujący
- (i 3 więcej)
-
Trochę cheat gadżet przede wszystkim dla licealistów którzy są leniwi tak jak ja. Dużo czasu w trakcie liczenia zadań zajmują same operacje matematyczne przy których także łatwo się pomylić. Najprostszym rozwiązaniem jest kalkulator naukowy lecz są one zabronione w szkole oraz na maturze. Stworzyłem więc własny kalkulator który tylko z pozoru wygląda jak prosty lecz ma ukryte funkcje. Oczywiście nie wygląda on idealnie ale to kwestia wydrukowania obudowy oraz zmiany klawiatury. Nawet użytkownik nie zapoznany z kalkulatorem nie odkryje specjalnych funkcji ponieważ wymagają one wciśnięcia specjalnej konfiguracji klawiszy. Kalkulator posiada takie funkcje jak Dodawanie Mnożenie Dzielenie Odejmowanie Obliczanie dowolnych potęg Obliczanie pierwiastka dowolnegos stopnia Obliczanie pierwiastków funkcji kwadratowej Obliczanie wszystkich funkcji trygomoterycznych Obliczanie logarytmu o dowolnej podstawie Całość zaprogramowana jest na arduino nano.
-
Cześć, Stworzyłem prosty układ z unipolarnym silnikiem krokowym JK42HS40, który steruję za pomocą sterownika DRV8834. Układ zasilam trzema bateriami AA przez regulowaną przetwornicę 3,6V S9V11MA. Niestety, napotkałem problem – układ nie działa poprawnie. Z wyjść sterownika do silnika nie płynie żaden prąd, a silnik nie reaguje na komendy. Załączam schemat połączeń oraz kod, z którego korzystam. Na schemacie zamiast przetwornicy znajduje się model stabilizatora liniowego, gdyż nie mogłem znaleźć takiej części w aplikacji Będę wdzięczny za wszelkie sugestie i pomoc w rozwiązaniu tego problemu. To mój drugi prototyp, który samodzielnie wykonałem, więc prosiłbym o wyrozumiałość i porady dla początkującego. #include <AccelStepper.h> // Define the pins for STEP and DIR #define DIR_PIN 7 #define STEP_PIN 8 // Create an instance of the AccelStepper class AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN); void setup() { stepper.setMaxSpeed(1000); // Set maximum speed in steps per second stepper.setAcceleration(500); // Set acceleration in steps per second^2 } void loop() { // Move one full revolution forward stepper.moveTo(200); // 200 steps forward stepper.runToPosition(); // Move to position delay(1000); // Move one full revolution backward stepper.moveTo(-200); // 200 steps backward stepper.runToPosition(); // Move to position delay(1000); } Dzięki!
- 6 odpowiedzi
-
- Arduino
- silnik krokowy
-
(i 1 więcej)
Tagi:
-
Dzień dobry, od niedawna próbuję stworzyć grę, chodzi o to że diody migają na lewo i prawo, a gracz ma wcisnąć przycisk aby miganie się zatrzymało. W zależności od tego na jakiej diodzie LED gracz zatrzyma, dostanie punkty (wyświetlane na LCD). I teraz chodzi o to że muszę w jednym kodzie sprawdzać czy przycisk nie został naciśnięty, i kontrolować miganie diod LED. Gdyby była opcja dwóch funkcji void loop to problem by był rozwiązany. Więc, czy można w jednym kodzie mieć dwie funkcje loop? Jeśli tak to proszę powiedzieć jak tego użyć, a jeśli nie to jak wykorzystać jedną funkcję loop do tego co chcę zrobić. Z góry dziękuję! 🙂
- 67 odpowiedzi
-
- Arduino
- Początkujący
-
(i 2 więcej)
Tagi:
-
Witam, próbowałem dzisiaj podłączyć wyświetlacz TFT dotykowy SPI ILI9341 do Arduino. Spróbowałem podłączyć z takiego zdjęcia z internetu i ekran się tylko zaświecił, kod się dało przegrać ale na wyświetlaczu nic się nie pojawiało. Potem zobaczyłem że jest więcej metod podłączania. I czy ktoś może mógłby mi wysłać zdjęcie/tabelkę prawidłowego podłączania wyświetlacza do Arduino? Wcześniej jak chciałem podłączyć zrobiłem to w! taki sposób jaki możecie zobaczyć na obrazku: i kod wgrałem ten: #include <Adafruit_GFX.h> #include <Adafruit_TFTLCD.h> #include <TouchScreen.h> #define LCD_CS A3 #define LCD_CD A2 #define LCD_WR A1 #define LCD_RD A0 #define LCD_RESET A4 #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define YP A1 #define XM A2 #define YM 7 #define XP 6 #define TS_MINX 940 #define TS_MINY 160 #define TS_MAXX 160 #define TS_MAXY 970 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); #define BOXSIZE 40 #define PENRADIUS 3 #define MINPRESSURE 10 #define MAXPRESSURE 1000 bool change = 0; bool touch = 0; void setup() { pinMode(A5, OUTPUT); digitalWrite(A5, LOW); Serial.begin(9600); tft.reset(); tft.begin(0x9325); tft.setTextColor(WHITE); tft.setTextSize(3); tft.fillScreen(BLACK); } void loop() { if (change == 0 && touch == 0) { digitalWrite(A5, LOW); tft.fillCircle(120, 160, 50, RED); tft.setCursor(95, 150); tft.println("LED"); change = 1; delay(200); } if (change == 0 && touch == 1) { digitalWrite(A5, HIGH); tft.fillCircle(120, 160, 50, GREEN); tft.setCursor(95, 150); tft.println("LED"); change = 1; delay(200); } TSPoint p = ts.getPoint(); pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); if (p.z > MINPRESSURE && p.z < MAXPRESSURE) { p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0); p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0); Serial.print("("); Serial.print(p.x); Serial.print(", "); Serial.print(p.y); Serial.println(")"); if (p.x > 70 && p.x < 170) { if (p.y > 110 && p.y < 210) { change = 0; touch = !touch; } } } } Tu są zdjęcia jak to podłączyłem: Mało na nich nich widać niestety, więc tu jest jeszcze zdjęcie ,,poglądowe": Gdyby było za mało informacji proszę napisać Z góry dziękuję za odpowiedzi! 😄
- 14 odpowiedzi
-
Dzień dobry, jak zasilić Arduino bateriami? Z góry dziękuję za odpowiedzi! 🙂
-
Dzień dobry, od wczoraj testuje wyświetlacz TFT. Wszystko idzie dobrze, ale nie wiem jak mam wyświetlić zmienną int na takim wyświetlaczu. Bardzo proszę o odpowiedź. Z góry dziękuję! 😄
- 17 odpowiedzi
-
- elektronika
- int
-
(i 3 więcej)
Tagi:
-
Witam, Zrobiłem sterownik do dwóch silników krokowych w oparciu o Arduino+Iduino ST1113 i 2x TB6660, wszystko działa jak należy do momentu przejścia na zasilanie arduino z przetwornicy napięcia StepDown 34>>5v. Co ciekawe całość działa poprawnie, tzn. silniki reagują na sterowanie przyciskami na LCD keypad shield ale nie wyświetlają się dane na wyświetlaczu (jest czysty i podświetlony). Gdy ten sam układ zasilę z komputera przez wejście USB w arduino znaki na wyświetlaczu są prawidłowe. Proszę o pomoc, czy do podłączenia zasilania z przetwornicy impulsowej potrzebuję jakiegoś dodatkowego modułu?
-
Witam serdecznie, Borykam się z dziwnym dla mnie problemem, otóż zbudowałem sobie pojazd rc składający się z czterech silników, arduino, nakładki od iduino i modułu esp32 wroom do komunikacji wifi z telefonem. Do sterowania użyłem aplikacji z google play, który wysyła 5 zapytań GET; "GET /?State=F", "GET /?State=B","GET /?State=L","GET /?State=R", "GET /?State=S". Kolejno są to : przód, tył, lewo, prawo i stop. Sygnały schodzą na esp jak i są przekazywane na arduino dopóki układ jest zasilany z kabla usb. Niestety gdy uruchomię z zasilania bateryjnego, to silniki na sygnały nie reaguję, podobnie jest gdy obwód jest zasilany z kabla usb, a przełączę przycisk zasilania bateryjnego, to wywala komunikację z komputerem. Kod sterujący silnikami w zależności od otrzymanej komendy, a pod nim kod z esp32, który odbiera sygnały z telefonu i przekazuje na arduino. Wydaje mi się, że jest kwestia zasilania, ale nie dam sobie ręki uciąć, może ktoś miał podobny problem? Z góry dziękuję za odpowiedzi. #include <AFMotor.h> // Inicjalizacja motor shield AF_DCMotor motor1(1); // Motor 1 podłączony do kanału M1 AF_DCMotor motor2(2); // Motor 2 podłączony do kanału M2 AF_DCMotor motor3(3); // Motor 3 podłączony do kanału M3 AF_DCMotor motor4(4); // Motor 4 podłączony do kanału M4 void setup() { Serial.begin(9600); // Komunikacja z ESP32 Serial.println("Arduino is ready to receive commands"); } void loop() { if (Serial.available()) { char command = Serial.read(); Serial.print("Received command: "); Serial.println(command); switch (command) { case 'F': // Ruch do przodu Serial.println("Moving forward"); motor1.setSpeed(255); // Maksymalna prędkość motor1.run(FORWARD); motor2.setSpeed(255); motor2.run(FORWARD); motor3.setSpeed(255); motor3.run(FORWARD); motor4.setSpeed(255); motor4.run(FORWARD); break; case 'B': // Ruch do tyłu Serial.println("Moving backward"); motor1.setSpeed(255); motor1.run(BACKWARD); motor2.setSpeed(255); motor2.run(BACKWARD); motor3.setSpeed(255); motor3.run(BACKWARD); motor4.setSpeed(255); motor4.run(BACKWARD); break; case 'R': // Skręt w prawo Serial.println("Turning right"); motor1.setSpeed(255); motor1.run(FORWARD); motor2.setSpeed(255); motor2.run(BACKWARD); motor3.setSpeed(255); motor3.run(FORWARD); motor4.setSpeed(255); motor4.run(BACKWARD); break; case 'L': // Skręt w lewo Serial.println("Turning left"); motor1.setSpeed(255); motor1.run(BACKWARD); motor2.setSpeed(255); motor2.run(FORWARD); motor3.setSpeed(255); motor3.run(BACKWARD); motor4.setSpeed(255); motor4.run(FORWARD); break; case 'S': // Stop Serial.println("Stopping"); motor1.setSpeed(0); motor1.run(RELEASE); motor2.setSpeed(0); motor2.run(RELEASE); motor3.setSpeed(0); motor3.run(RELEASE); motor4.setSpeed(0); motor4.run(RELEASE); break; default: Serial.println("Unknown command"); break; } } } #include <WiFi.h> // Nazwa i hasło sieci Wi-Fi const char* ssid = "RC_CONNECTION"; const char* password = "12345678"; // Inicjalizacja serwera WiFiServer server(80); // Piny dla Serial1 const int RX_PIN = 16; const int TX_PIN = 17; void setup() { Serial.begin(115200); Serial1.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); // Używamy Serial1 do komunikacji z Arduino // Ustawienie ESP32 jako Access Point WiFi.softAP(ssid, password); Serial.println("Access Point utworzony:"); Serial.print("SSID: "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.softAPIP()); // Uruchomienie serwera server.begin(); } void loop() { WiFiClient client = server.available(); // Sprawdzenie, czy są klienci if (client) { Serial.println("New connection"); String currentLine = ""; // do trzymania danych z klienta while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); // Wysyła komendę do komputera przez Serial if (c == '\n') { // Przetwarzanie żądania GET Serial.println("Processing request:"); Serial.println(currentLine); // Wysłanie komendy do Arduino przez Serial1 if (currentLine.indexOf("GET /?State=F") >= 0) { Serial1.println("F"); } else if (currentLine.indexOf("GET /?State=B") >= 0) { Serial1.println("B"); } else if (currentLine.indexOf("GET /?State=R") >= 0) { Serial1.println("R"); } else if (currentLine.indexOf("GET /?State=L") >= 0) { Serial1.println("L"); } else if (currentLine.indexOf("GET /?State=S") >= 0) { Serial1.println("S"); } // Wysłanie odpowiedzi do klienta client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); client.println("Komenda otrzymana"); client.println(); break; } else if (c != '\r') { currentLine += c; } } yield(); // Dodanie yield() w celu uniknięcia resetowania przez watchdog } client.stop(); Serial.println("Client Disconnected"); } delay(10); // Dodanie niewielkiego opóźnienia, aby odciążyć procesor }
- 3 odpowiedzi
-
- ESP32-wroom
- Motor Shield
- (i 3 więcej)
-
Space-Mouse Space Mouse dla FreeCAD-a, Arduino Micro Pro.
99teki opublikował temat w Projekty - DIY (mini)
- pora zamienić mysz zwykłą pracująca pod FreeCad-em na mysz 3D. - na Arduino Micro Pro wpisujemy do programu deskryptory HID-a dla myszy 3D, kompilujemy i sprawdzamy czy FreeCad widzi oprogramowanie na Micro Pro. - przechodzimy do FreeCad-a, przybornik, dostosuj, ruch Space Mouse są zakładki aktywne, czyli deskryptory są poprawne. - schemat dość prosty, 3 analogowe joystiki i drukowana obudowa. - pora się zabrać za sprawdzenie plików *.stl. -
Cześć Jak w tytule mam problem w moim projekcie, a mianowicie planuję zrobić system dostępu, który będzie działał następująco: Po przyłożeniu karty magnetycznej system będzie sprawdzał czy dana karta znajduje się w systemie, następnie jeśli tak to daje sygnał (nie zależnie od tego która to karta), jeśli nie to po prostu nie podaje sygnału. Zależy mi na tym aby była opcja nadpisania numeru karty, np. jak się zgubi karta "5" o numerze 19543 to mogę nadpisać żeby do "5" działała inna karta (pod "5" będą np. 3 karty o tym samym numerze więc ma działać nowy zestaw). (system nie ma dostępu do komputera ani Internetu) Zastanawiałem się jak to zrobić i obejrzałem kilka tutoriali, jednak wciąż nie mam pojęcia jak się do tego zabrać. Czy na karcie SD? na czymś innym? W jaki sposób wyszukiwać numer? to są pytania na które pragnę poznać odpowiedź (chcę również ograniczyć koszty)
-
Dzień dobry, Wstawiam temat do 'dla zielonych', ponieważ myślę, że to problem nowicjusza. Posiadam następujący układ MAX7219 (8x8 sektory, 64 width, 16 height) na obrazku, podłączony daisy-chain. Problem polega na tym, że tablica jak wyżej(64w.16h) działa tylko jako 32x16(zdublowane). Działająca wersja to również 32x32 jak w kodzie programu. Próbowałam zmienić układ w kodzie, by pasowało do obwodu(jak na obrazku), ale przy układzie 16x2 X-Y segments wyrzuca mi błąd(aaaaaaaaaa na feedbacku z Arduino) Każda kombinacja posiadająca 64 LEDy(32x2, 16x4) powoduje, że wyskakuje mi ten sam błąd. Czy jest to problem symulatora, że nie obsługuje większej konfiguracji, czy Arduino Mega(że za dużo danych na raz i "dławi" układ)? Dodałam animację, żeby zobaczyć, czy zwiększenie rowArrays spowoduje ten sam błąd, ale dodawałam 4-5 statycznych obrazków, zmieniających się w pętli po kolei i działa bez zarzutu. Nie mam już pomysłu, jak sprawdzić, czego to wina. Chciałam znaleźć inny symulator, ale nie posiadają płytek MAX7219, więc nie sprawdzę tego w inny sposób, poza fizycznym sprawdzeniem układu. Dopiero się uczę składania sprzętu, więc na razie odpuszczam konstruowanie układu Arduino, dopóki się nie nauczę podstaw z kursów, ale próbuję oprogramowania, żeby mieć już 'na gotowo', gdy będę miała większą wiedzę. Z góry dziękuję za odpowiedzi, mam nadzieję, że jest zrozumiale. #include <Arduino.h> #define CLK 13 #define DIN 11 #define CS 10 #define X_SEGMENTS 4 #define Y_SEGMENTS 4 #define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS) // a framebuffer to hold the state of the entire matrix of LEDs // laid out in raster order, with (0, 0) at the top-left byte fb[8 * NUM_SEGMENTS]; // Define four sets of arrays for each row (32 rows for 32x32 display) byte rowArrays1[32][32] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; byte rowArrays2[32][32] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; byte rowArrays3[32][32] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; byte rowArrays4[32][32] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Add the remaining rows manually }; byte (*currentRowArrays)[32] = rowArrays1; unsigned long lastSwitchTime = 0; const unsigned long switchInterval = 10; // switch every second int currentArrayIndex = 0; void shiftAll(byte send_to_address, byte send_this_data) { digitalWrite(CS, LOW); for (int i = 0; i < NUM_SEGMENTS; i++) { shiftOut(DIN, CLK, MSBFIRST, send_to_address); shiftOut(DIN, CLK, MSBFIRST, send_this_data); } digitalWrite(CS, HIGH); } void setup() { Serial.begin(115200); pinMode(CLK, OUTPUT); pinMode(DIN, OUTPUT); pinMode(CS, OUTPUT); // Setup each MAX7219 shiftAll(0x0f, 0x00); //display test register - test mode off shiftAll(0x0b, 0x07); //scan limit register - display digits 0 thru 7 shiftAll(0x0c, 0x01); //shutdown register - normal operation shiftAll(0x0a, 0x0f); //intensity register - max brightness shiftAll(0x09, 0x00); //decode mode register - No decode } void loop() { clear(); // Check if it's time to switch the picture if (millis() - lastSwitchTime >= switchInterval) { lastSwitchTime = millis(); currentArrayIndex = (currentArrayIndex + 1) % 4; switch (currentArrayIndex) { case 0: currentRowArrays = rowArrays1; break; case 1: currentRowArrays = rowArrays2; break; case 2: currentRowArrays = rowArrays3; break; case 3: currentRowArrays = rowArrays4; break; } } // Update the framebuffer based on the current rowArrays for (int y = 0; y < Y_SEGMENTS * 8; y++) { for (int x = 0; x < X_SEGMENTS * 8; x++) { if (currentRowArrays[y][x] == 1) { safe_pixel(x, y, 1); } else { safe_pixel(x, y, 0); // Ensure LED is off if not explicitly set } } } show(); delay(100); // Adjust as needed to smooth the display update } void set_pixel(uint8_t x, uint8_t y, uint8_t mode) { byte *addr = &fb[x / 8 + y * X_SEGMENTS]; byte mask = 128 >> (x % 8); switch (mode) { case 0: // clear pixel *addr &= ~mask; break; case 1: // plot pixel *addr |= mask; break; case 2: // XOR pixel *addr ^= mask; break; } } void safe_pixel(uint8_t x, uint8_t y, uint8_t mode) { if ((x >= X_SEGMENTS * 8) || (y >= Y_SEGMENTS * 8)) return; set_pixel(x, y, mode); } // turn off every LED in the framebuffer void clear() { byte *addr = fb; for (byte i = 0; i < 8 * NUM_SEGMENTS; i++) *addr++ = 0; } // send the raster order framebuffer in the correct order // for the boustrophedon layout of daisy-chained MAX7219s void show() { for (byte row = 0; row < 8; row++) { digitalWrite(CS, LOW); byte segment = NUM_SEGMENTS; while (segment--) { byte x = segment % X_SEGMENTS; byte y = segment / X_SEGMENTS * 8; byte addr = (row + y) * X_SEGMENTS; if (segment & X_SEGMENTS) { // odd rows of segments shiftOut(DIN, CLK, MSBFIRST, 8 - row); shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]); } else { // even rows of segments shiftOut(DIN, CLK, MSBFIRST, 1 + row); shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]); } } digitalWrite(CS, HIGH); } } [edit] po kilkunastu próbach na symulatorze, w końcu zadziałało jak miało być - nie wiem, co było z kodem nie tak. Na razie na większej matrycy nie pozwala zrobić animacji z powodu ograniczeń pamięci, aktualnie pracuję nad przeniesieniem danych ze SRAM przez progmem, nie wiem jak zamknąć temat.
-
Dzisiaj nieco odpoczynku od elektroniki. Ale oczywiście o ile ta cała kabelkologia jest niezmiernie ważna i ważne jest urządzenie sobie warsztatu - to samo można powiedzieć o "warsztacie programisty", czyli zorganizowaniu tak stanowiska, aby można było skupić się na tym co najważniejsze: tworzeniu kodu. Wrzucam to jako worklog, bo kilka spraw jest jeszcze nie do końca rozwiązanych (m.in. użycie esptool-ftdi, na czym bardzo mi zależy), ale w tej postaci jaka jest program jest absolutnie używalny i spełnia swoją funkcję. Na potrzebę powstania tego programu złożyło się kilka czynników. Przede wszystkim w większości do programowania swoich ESP używam frameworku Arduino, a Arduino IDE z różnych przyczyn uważam za mało używalne. Poza tym także nie przepadam za pisaniem Makefile (chociaż po napisaniu bardzo lubię używać make). Postanowiłem więc zrobić sobie wrapper do arduino-cli. Wrapper działa na Linuksie, ale nie widzę przeszkód w uruchomieniu go na Macu czy nawet na Windows, potrzebne by były jedynie niewielkie zmiany. Przede wszystkim musiałem zrobić to, czego mi a Arduino IDE brakuje - czyli oddzielna konfiguracja dla każdego szkicu. Postanowiłem pójść jeszcze dalej: ponieważ zdarza mi się ten sam program uruchamiać na kilku różnych architekturach, założyłem możliwość istnienia kilku wariantów konfiguracji dla każdego szkicu i zabrałem się do roboty. Ponieważ znałem już strukturę plików boards.txt i platform.txt poszło dość szybko - i w relatywnie krótkim czasie miałem już gotowy konfigurator. Oczywiście zanim cokolwiek się zrobi trzeba dodać nowy wariant. Po wciśnięciu klawisza "Nowa" ukazuje się okno tworzenia wariantu: Jak widać jest to podobne do menu wyboru płytki w Arduino IDE, dochodzi jedynie pole "Nazwa", pozwalające na nadanie wariantowi jakiejś łatwej do zapamiętania nazwy. Po utworzeniu wariantu można zabrać się do konfiguracji. I tu znów wzorowałem się na menu Arduino IDE - wszystkie parametry są widoczne na liście, a aktywacja wiersza (czyli dwuklik albo wciśnięcie Enter) powoduje pojawienie się możliwości wyboru predefiniowanej opcji: Jak widać, na razie różnice w stosunku do IDE są niewielkie, ale następną rzeczą, która w IDE jest dla mnie szalenie niewygodna, jest wybór portu do uploadu. Przede wszystkim - nasze systemy operacyjne przyporządkowują numer portu do urządzenia w sposób raczej losowy. Odłączenie i ponowne podłączenie płytki skutkować może np. zmianą portu z ttyUSB0 ma ttyUSB1, co potrafi trochę krwi napsuć. Dość dawno jednak stworzyłem prosty system detekcji portu, i zastosowanie go tutaj było oczywiste. Po prostu podaję jaki to ma być typ portu (do wyboru ttyS, ttyUSB i ttyACM) i/lub nazwę pod jaką zgłasza się podłączone urządzenie. Program szukając portu przeszukuje tylko te o zadeklarowanym typie, ewentualnie sprawdzając, czy nazwa odczytana z urządzenia zawiera w sobie wyszukany string. W ten sposób np. uploader dostaje informację że ma się połączyć na tym a nie innym porcie. Ten sposób działa u mnie już od ok. dwóch lat i jeszcze mnie nie zawiódł. W programie wprowadziłem jeszcze jedną zmianę: jeśli nazwa rozpoczyna się od VID:PID (np. "2341:0043 Uno R3") będzie wyszukiwane urządzenie odpowiadające odczytanym z USB wartościom VendorID i ProductID. Również nazwa w przypadku urządzeń USB będzie (o ile to mozliwe) pochodzić z oficjalnego wykazu. Następną sprawą jest ustawienie adresu i hasła OTA. O ile w IDE konieczne jest, aby urządzenie było włączone w czasie ustawiania portu, o tyle tu takiej konieczności nie ma: mogę albo skorzystać z listy urządzeń wykrytych przez zeroconf (przy czym mogę sobie zapisać albo nazwę, albo adres IP) albo podać te dane ręcznie (jeśli je znam). Poza tym mój program zapamiętuje hasło, co bywa wygodne (szczególnie w porównaniu do IDE w wersji 2.x). I ostatnia rzecz: użycie zewnętrznego programu do uploadu. Może to być np. program obsługi jakiegoś programatora, albo (jak w moim przypadku, co postaram się pokazać przy najbliższym DIY) skrypt wysyłający skompilowany plik do maszyny, do której podłączona jest płytka. W sumie okno konfiguratora uploadu wygląda tak: Istnieje również możliwość dodania dodatkowych parametrów do kompilacji. Dla architektury AVR można włączyć pełną wersję sprintf (tzn. taką, która pozwala na wypisywanie floatów). Można również dodać dowolną ilość definicji, które w programie będą traktowane jako dodatkowe linie #define. Poziom szczegółowości ostrzeżeń działa nieco inaczej niż w IDE: dla platform, dla których automatycznie dodawane jest -Werror przy wyświetlaniu wszystkich ostrzeżeń parametr ów nie jest dodawany automatycznie, można go dodać zaznaczając odpowiednie pole. W ten sposób można bez zbytniej ekwilibrystyki kompilować programy np. na ESP32 z wyświetlaniem wszystkich ostrzeżeń (w IDE przy takim przełączeniu kompilator odmawia kompilacji bibliotek które generują jakieś ostrzeżenia, choćby nawet nie miały wpływu na ich działanie): I to już cały konfigurator. Teraz wystarczy zapisać całą konfigurację (przycisk "Zapisz" lub "Zapisz i zakończ"). Jako domyślny zostanie wpisany wariant aktualnie wskazany na liście. No, ale konfigurator to nie wszystko - warto by było mieć coś, co z tego konfiguratora korzysta. Postanowiłem stworzyć jedno polecenie, które zależnie od podanych opcji będzie robiło różne czynności. Jako że najważniejszym poleceniem jest "help", tak wygląda wynik jego działania (i kilku następnych): Pisząc program natknąłem się na kilka nieprzyjemnych niespodzianek związanych z arduino-cli. Początkowo najbardziej naturalne wydało mi się umieszczenie katalogów build i cache wewnątrz katalogu szkicu. Stosowałem to już wcześniej używając arduino-builder i make, tak więc wydało mi się to najlepszym i w dodatku sprawdzonym rozwiązaniem. A guzik... arduino-cli bardzo grzecznie kompilował program, ale tylko raz. Ki diabeł? No tak, zajrzenie na githuba do issues wszystko wyjaśniło. Jest to stary, szacowny błąd z długą brodą, polegający na tym, że arduino-cli uważa pliku w katalogu build za pliki żródłowe, i próbuje je jeszcze raz skompilować (co się oczywiście nie udaje). W związku z tym preniosłem owe katalogi do /tmp, jakoś w miarę sensownie je ponazywałem i zadziałało... No prawie, a jak wiadomo - prawie robi wielką różnicę. Otóż plik konfiguracji (w formacie json) zapisywany jest w katalogu szkicu (no bo gdzie miałby być zapisany) z rozszerzeniem .json - a to też zmyliło arduino-cli które koniecznie chciało go skompilować. Zmiana rozszerzenia na .cfg skutecznie oduczyła arduino-cli nadmiernej gorliwości i wszystko ładnie ruszyło... Z jednym wyjątkiem: uploadu przez OTA. Podobno arduinio-cli to potrafi (w końcu jakoś IDE w wersji 2.x daje sobie z tym radę, aczkolwiek nie tak do końca). Postanowiłem więc darować sobie sprawdzanie i upload OTA rozwiązać "ręcznie". Jako że jak dla mnie dotyczy to tylko ESP, zaprzągłęm do pracy parser konfiguracji arduino (który i tak jest częścią programu), i dopisałem kilka linijek. Co prawda w tej postaci upload OTA możliwy jest wyłącznie dla ESP32 i ESP8266, ale po pierwsze nie mam innych mikrokontrolerów dla których mógłbym to wykorzystać, po drugie dopisanie kolejnych architektur to kwestia kliku minut, a po trzecie wszystko można załatwić możliwością uploadu przez zewnętrzne polecenie. Aha, no i najważniejsze: może autorzy arduino-cli jakoś w końcu uporają się z implementacją obsługi OTA 🙂 No cóż - chciałbym powiedzieć że to wszystko, ale już słyszę narzekania: linia poleceń? Ajaj, przecież to takie trudne, lepiej sobie kliknąć w jakieś menu w aplikacji! A da się. Porządne edytory (np. Geany) mają możliwość skonfigurowania zewnętrznych poleceń. Dla przykładu rozwiązanie wyklikane dla plików *.ino wygląda w Geany tak: No i na koniec kwestia instalacji. Najpierw musimy upewnić się, czy mamy potrzebne biblioteki i programy współpracujące:Python, gobject-introspection i gtk3 najprawdopodobniej już mamy; można to łatwo sprawdzić uruchamiając konsolę python3 i wpisując polecenia importu Gtk3: $ python3 Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gi >>> gi.require_version('Gtk', '3.0') >>> from gi.repository import Gtk >>> Jeśli nie było błędu wszystko jest w porządku; w przeciwnym razie należy sprawdzić w dokumentacji swojej dystrybucji. Dodatkowo potrzebny będzie pakiet zeroconf i usb.ids. Jeśli ich nie będzie, pakiet zeroconf można zainstalować z githuba, a plik usb.ids można ściągnąć z internetu i umieścić gdziekolwiek wskazując ścieżkę we właściwym miejscu w pliku arduports.py w linii zawierającej polecenie: f=open('/var/lib/usbutils/usb.ids','rb') No i ostatnie najważniejsze: arduino-cli. Możemy zainstalować z githuba, lub użyć wersji zawartej w Arduino-IDE 2.x. Ważne, aby znalazło się w ścieżce wskazanej przez $PATH! Właściwy program instalujemy oczywiście z poziomu użytkownika, a nie roota! W tym celu musimy znać katalog, w którym możemy umieścić polecenia. Dla Linuksów będą to najprawdopodobniej ~/bin lub ~/.local/bin - można to sprawdzić poleceniem: echo $PATH Załóżmy że jest to katalog ~/bin. Plik pyrduino.tgz umieszczamy tam, gdzie nie powinien się zgubić (np. w katalogu domowym) i wykonujemy kolejno polecenia: tar -xzf pyrduino.tgz cd pyrduino-src chmod 755 ardu.py ln -sf $(pwd)/ardu.py ~/bin/arducfg ln -sf $(pwd)/ardu.py ~/bin/ardu I to wszystko. Możemy teraz wejść do katalogu szkicu i pobawić się poleceniami arducfg i ardu. Na koniec jedna uwaga: o ile polecenie arducfg musi pozostać takie a nie inne (można to zmienić w pliku ardu.py), o tyle zamiast nazwy ardu możemy użyć dowolnej, która nam się podoba. I jeszcze jedno: jak wspominałem na początku, da się to pewnie zainstalować na Macu (z niewielkimi zmianami) i na Windows (z większymi zmianami). Gdyby komuś się to udało - proszę o danie znać w komentarzu; może komuś się przyda! Do ściągnięcia: pyrduino.tgz I tak już całkiem na zakończenie dla miłośników make - krótki przykład: BINARY=$(shell ardu -show | grep -P '^Build\s+=' | tr -d " " | cut -d= -f2) $(BINARY): *.ino ardu PHONY: flash flash: $(BINARY) ardu -V -flash PHONY:ota ota: $(BINARY) ardu -ota PHONY:clean clean: ardu -clean Prawda, że proste?
-
simracing Licznik samochodowy współpracujący z grami - projekt CAN bus
MattechPC opublikował temat w Projekty - DIY
Witam wszystkich! Po dłuższej nieobecności na formu chciałbym zaprezentować Wam kilka z moich najnowszych projektów przy okazji po krótce omawiając magistralę CAN bus. *** Wstęp *** Do tej pory opublikowałem dwa wpisy na forum opisujące budowę analogowych liczników samochodowych od Forda Galaxy oraz Audi A3 8L. Są to projekty niezwykle proste w budowie, wystarczy na określony pin podać 12V, masę lub sygnał z Arduino o określonej częstotliwości aby ożywić cały licznik i wszystkie wskazówki. Jednak ze względu na swoją prostotę projekty te posiadają liczne ograniczenia - przede wszystkim nie jesteśmy w stanie idealnie symulować zmiennej rezystancji czujnika poiomu paliwa oraz temperatury cieczy. Dodatkowo większosć kontrolek działa w logice 12V przez co nie można nimi sterować bezpośrednio z Arduino. Wszystkie te ograniczenia obchodzą liczniki, które do komunikacji wykorzystują magistralę CAN bus. *** Założenia projektu *** Projekt licznika miał być przede wszystkim uniwersalny i działać z szerokim wachlarzem gier - od ETS 2 gdzie prędkości obrotowe silnika wynoszą do 2500 RPM a prędkość rzadko kiedy przekracza 120km/h przez Framingi, BeamNG, Asseto Corsa na F1 kończąc gdzie silnik wkręca się powyżej 10.000 RPM a prędkości znacznie wykraczają za maksymalne wychylenie prędkościomierza licznika samochodowego. Licznik umożliwić ma nie tylko odczyt podstawowych parametrów prowadzonego pojazdu tj. obroty silnika, prędkość, temperatura cieczy, oleju czy poziomu paliwa ale także informować o stanie świateł, silnika czy nawet opon. *** Potrzebne materiały *** Arduino MCP2515 Zasilacz 12V (1A w zupełności starczy) Przewody połączeniowe *** Jak to działa? *** Do budowy projektu wykorzystałem dobrze znane większości z Was Arduino NANO wyposażone w USB-C. Dialog z licznikiem prowadzony jest poprzez moduł CAN MCP-2515 a całość zasila 12V zasilacz sieciowy. Całość umieściłem w małej obudowie wydrukowanej na drukarce 3D. Nie wgryzając się za bardzo w szczegóły techniczne - CAN bus to szeregowa magistrala danych wykorzystująca do komunikacji 2 przewody opisywane jako CAN-H oraz CAN-L. Jak łatwo się domyślić na przewodzie CAN-High panuje nieco wyższe napięcie niż na CAN-Low. CAN Bus jest magistralą działającą w sposób różnicowy czyli mierzy i porównuje napięcia na CAN-H oraz CAN-L. W ten sposób odczytywane są bity dominujące i recesywne tworąc ciąg zer i jedynek. Dla ułatwienia projektu nie oparłem o liczby binarne tylko znacznie przyjemniejsze dla oka - heksadecymalne. Ramka CAN wysyłana do licznika składa się z unikalnego identyfikatora (ID) oraz określonej ilości bajtów danych. Każdy bajt danych może przyjąć wartość od 0 do FF czyli decymalnych 255. Dla przykładu aby zapalić kontrolkę hamulca ręcznego w liczniku od Peugeota 407 muszę nadać ramkę o ID 128 a bicie zerowym nadać wartość 24HEX. Wygląda to mniej więcej tak: [ ID 128 0x24 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ]. Pod pozostałymi bitami kryją się kolejne kontrolki tj. kierunkowskazy, światła mijania, drogowe, przeciwmgielne oraz nielubiany przez kierowców check engine. Pod różnymi ID ramek można odnaleźć pozostałe funkcje licznika - sterowanie wskazówkami, podświetleniem, ustawianie przebiegu itd. Warto pamiętać, że niektóre liczniki po otrzymaniu zasilania będą pozornie wyglądać na martwe. Takie konstrukcje potrzebują tak zwanego sygnału przebudzenia, który "obudzi" licznik. Jeśli taki sygnał występuje to jest to pierwszy krok aby zacząć zabawę z licznikiem. *** Projekt licznika *** Do moich projektów wykorzystuję liczniki z samochodów Peugeot oraz Citroen. Magistrala CAN w obu markach jest bliźniaczo podobna i różnią się jedynie małymi szczegółami. Najważniejsze, że obie marki wykorzystują taką samą szybkość magistrali wynosząca 125Kbps. Do kontroli modułu MCP2515 wykorzystałem bibliotekę MCP2515.h. W pierwszej kolejności łączę moduł CAN z Arduino oraz podłączam magistralę wraz z zasilaniem do licznika. Należy pamiętać, że każdy licznik posiadać może swój własny indywidualny pinout. Powyżej można zobaczyć pinout licznika Citroen C3 I FL. Po podłączeniu wszystkich 4 przewodów wgrywam przygotowany wcześniej kod na Arduino. Warto zatrzymać się na chwilę przy kodzie i zastanowić się jak projektant tworzył licznik. Zespół projektujący licznik miał surowe dane - maksymalne obroty silnika 5200 RPM, maksymalna temp. cieczy 130℃, maksymalna temp. oleju 150℃, maksymalna prędkość 260km/h. Licznik przygotowany jest oczywiście na taki zakres danych z minimalnym zapasem jednak po przekroczeniu skali obrotomierza lub wskaźnika temperatury zaczną dziać się różne dziwne rzeczy. Wartości out of range są różnie traktowane przez liczniki - jedne ustawiają wskaźnik na "0", drugie wyłączają się a trzecie mogą się zawiesić. Dane z gier praktycznie zawsze będą wykraczać poza zakresy ustalone przez producenta więc trzeba przeanalizowaćkażdą grę z osobna i zastosować zabezpieczenia oraz skalowanie tak, aby wartości zawsze znajdowały się w akceptowalnym przez licznik zakresie. Kod musi brać także poprawkę na nieliniowość wskaźników temperatury - rzadko kiedy 1° obrotu silnika krokowgo będzie odpowiadał dokładnie takiemu samemu przyrostowi temperatury. Do przykładu - wskazówka temp. cieczy "zastyga" na 90℃ gdy faktyczna temperatura cieczy waha się od ~85-93℃. Dalszy wzrost temperatury będzie powodował niewielki wzrost wychylenia wskazówki. Jednak gdy temperatura niebezpiecznie wzrośnie to wskazówka momentalnie zwiększy swoją czułość i będzie wykonywać znaczny ruch co każdy 1-2℃. *** Dane z gier *** Po przetestowaniu kodu na "suchych" danych wpisanych "z palca" do kodu wypadałoby przestawić się na dane przesyłane z gier do licznika w czasie rzeczywistym. Za przygotowanie danych odpowiada aplikacja SimHUB współpracująca ze specjalnie napisaną przeze mnie formułą NCalc "obrabiającą" surowe dane z gier na zakresy liczbowe zaimplementowane w kodzie. Wygląd danych, którymi "karmię" kod Arduino przedstawiam poniżej. Jest to oczywiście wycinek danych ponieważ ogranicza mnie pole wyświetlające Raw result. *** Efekt końcowy *** Po wielu próbach i testach udało mi się ujarzmić prawie cały licznik. Wszytskie wskazania licznika: prędkość obrotowa silnika prędkość pojazdu poziom paliwa temp. cieczy temp. oleju wskaźnik biegów Kontrolki: hamulec ręczny kierunkowskazy światła mijania, drogowe, przeciwmgielne brak ładowania akumulatora niskie ciśnienie oleju rezerwa przegrzanie cieczy przebita opona przebieg nastawa tempomatu / aktualna prędkość pojazdu niskie ciśnienie w układzie hamulcowym (ETS2/ATS wykorzystując kontrolkę wody w filtrze paliwa) podniesienie osi (ETS2/ATS wykorzystując kontrolkę wyłączonej poduszki powietrznej pasażera) kończącego się czasu pracy (ETS2/ATS wykorzystując kontrolkę uszkodzenia wspomagania kierownicy oraz kontrolkę pasów bezpieczeństwa) przekroczonego limitu prędkości na drodze (ETS2/ATS wykorzystując kontrolkę usterki tempomatu (tylko Peugeot 407)) zbyt wysokich obrotów (ETS2/ATS wykorzystując kontrolkę trójkąta ostrzegawczego) retardera (ETS2/ATS wykorzystując kontrolkę świec żarowych) ekonomicznej jazdy (wykorzystując kontrolkę ECO) działanie ESP działanie ABS Działanie licznika w grach można zobaczyć na poniższych zdjęciach. *** Zbuduj sam własny projekt i odkrywaj tajniki CAN BUS! *** Z tego miejsca chciałbym gorąco zachęcić wszystkich zainteresowanych do spróbowania swoich sił i budowy własnego projektu z licznikiem opartym na magistrali CAN Bus. Elementy niezbędne do budowy projektu oraz same liczniki są bardzo tanie i projekt powinien spokojnie zamknąć sie w 100-150zł. Magistrala CAN grupy PSA jest bardzo dobrze opisana, obszerną dokumentację stanowiącą fundamentalny filar wiedzy można znaleźć pod TYM linkiem. Jeśli do wybranego przez Ciebie licznika nie ma żadnej dokumentacji to nic straconego, wystarczy napisać bardzo prosty generator losowych wartości bajtówki. Metoda ta nazywa się brute force i jest bardzo efektywna. Należy jednak korzystać z niej ostrożnie ponieważ istnieje niewielka szansa na zbrickowanie licznika. Eksperymentowanie z licznikiem oraz CAN Bus'em pozwoli Tobie także lepiej zrozumieć cały proces komunikacyjny, który finalnie zapala nielubiany check engine na liczniku. Za pomocą modułu MCP2515 możesz także podsłuchać co "szumi" w magistrali CAN Twojego samochodu. Jeśli rozszyfrujesz te dane to nic nie stoi na przeszkodzie abyś zaprojektował swój własny wyświetlacz doładowania, cyfrowy prędkościomierz czy wyświetlacz temperatury oleju w silniku. *** Wykorzystaj mój kod! *** Jeśli jednak nie czujesz się na siłach aby zbudować własny licznik to możesz bez problemu wykorzystać opracowane przeze mnie liczniki wraz z kodem na Arduino. Wszelkie informacje odnośnie budowy takiego projektu znajdziesz w poradniku na moim kanale: