Skocz do zawartości

encelados

Użytkownicy
  • Zawartość

    26
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    1

encelados zajął 1. miejsce w rankingu.
Data osiągnięcia: 19 lipca 2017.

Treści użytkownika encelados zdobyły tego dnia najwięcej polubień!

Informacje

  • Płeć
    Mężczyzna

Ostatnio na profilu byli

Blok z ostatnio odwiedzającymi jest wyłączony i nie jest wyświetlany innym użytkownikom.

Osiągnięcia użytkownika encelados

Starszy odkrywca

Starszy odkrywca (5/19)

  • Za 5 postów
  • Za 25 postów
  • Młodszy Juror
  • To już rok!
  • To już 5 lat!

Odznaki

2

Reputacja

  1. Witam. Do wszystkich miłośników paska menu z poleceniami tekstowymi (Command texts) po prawej stronie okna Eagle: Moja wersja Eagle'a to 6.5.0. Kolega "Nawyk" zaproponował rozwiązanie: Niestety, u mnie zaproponowane rozwiązanie powoduje błędy przy otwieraniu pliku ze schematem. Aby działało to bezbłędnie - odpowiedni fragment wpisu w pliku "eagle.scr" powinien wyglądać tak: SCH: Grid Default On; Change Width 0.006; MENU 'Add' 'Change' 'Copy' 'Delete' 'Display' 'Edit' 'Grid' 'Group' 'Move' 'Name' 'Net' 'Quit' 'Rect' 'Route' 'Script' 'Show' 'Signal' 'Split' 'Text' 'Value' 'Via' 'Window' 'Wire' 'Write' \ '---' \ '[designlink22.png] Search and order {\ General : Run designlink-order.ulp -general; |\ Schematic : Run designlink-order.ulp; \ }'\ '[LTspice.png] LT Spice simulation {\ Export: RUN ltspice.ulp /E; |\ Export Setup: RUN ltspice.ulp /E /S; |\ Export Group: RUN ltspice.ulp /E /G; |\ Import: RUN ltspice.ulp /I; \ }'\ ; Oczywiście dodawane pozycje do paska można wybrać samemu. Po zapisaniu pliku "eagle.scr" Eagle otwiera takie okno ze schematem: Następnie "łapiemy" początek paska LPM: I "przenosimy" na prawą stronę okna programu: 😉
  2. Sorry za kłopot. Oczywiście spróbuję sam. Komunikat pewnie się pojawi. O ile nastąpi sukces. Na film raczej nie ma co liczyć. Nie dlatego, że nie chcę. Tylko dlatego, że nie mam kamery. Ani nawet... smartfona. A mój cyfrowy aparat foto (kompletnie "przedpotopowy") oraz aparat foto w moim telefonie komórkowym (też kompletnie "przedpotopowym" :->) robią fotki w takiej jakości, że kilka dni później - sam muszę się domyślać co to takiego "sfotografowałem" 🙂 W każdym razie, niezależnie od mojego sukcesu lub porażki - wciąż pozostaje "druga alternatywa": dorobienie funkcji umożliwiającej kontrolę diodek przez port szeregowy (ustawianie kolorów, jasności, mrugania itp) poprzez wpisywanie ciekawszych komend klawiaturowych zamiast trywialnych "N" i "P".
  3. A czy mógłbyś zamieścić przykładowy kod "żarówkowy" dla zwykłej jednokolorowej diody LED (może być tylko jedna)? W takim przypadku jasnością diody będziemy sterować chyba zmieniając wypełnienie sygnału PWM...
  4. Dziękuję bardzo za wyczerpujące rozwinięcie tematu 😃 Co wybrać na jutro? Trudny wybór, bo ciekawi mnie i jedno i drugie. To może tak: najpierw popracujmy nad udawaniem na LEDach powolnych żarówek. A potem (pojutrze?) zajmiemy się dorobieniem funkcji umożliwiającej kontrolę diodek przez port szeregowy (ustawianie kolorów, jasności, mrugania itp) poprzez wpisywanie ciekawszych komend klawiaturowych zamiast trywialnych N i P 🙂 Ciekawi mnie też czy gdybym zechciał wyjść z "piaskownicy" Arduino (oraz Arduino IDE) i zaprogramować jakiegoś AVR-ka (np. ATmegę 328P) pisząc program w C w np. Atmel Studio 7.0 i wysyłając go do μC przez programator USBasp - to w takim programie mogę również korzystać z biblioteki Adafruit_NeoPixel? Czy to jest tylko dla Arduino?
  5. Witam ponownie - znowu upłynął ponad tydzień? Na wstępie chcę podziękować koledze z forum o nicku szrek2003 za podpowiedź będącą innym spojrzeniem (oszczędzającym) na to, co chcę osiągnąć w moim "projekcie". Przepraszam też, za mój głupawy i egoistyczny komentarz dotyczący nielogiczności zasięgu lokalnych zmiennych statycznych. Sądząc po długości Twojego ostatniego wpisu - to chyba teraz Ty się zirytowałeś. I słusznie, bo: programy pisane dla mikrokontrolerów AVR (a także dla innych mikrokontrolerów) potrafią na pewno realizować dużo więcej celów, niż ten mój problem. Ale dało mi to do myślenia i sporo wyjaśniło. Rozumiem też to, że nie wolno pisać programu dla mikrokontrolera bez przemyślenia planu, funkcjonalności i "na kolanie". Tworząc kod cały czas trzeba myśleć, i pisać ten kod tak, żeby potem zwiększanie jego funkcjonalności (np. dodanie nie jednego więcej - ale kliku więcej przycisków i ich obsługi) nie było... mordęgą. Mam dwie wiadomości: dobrą i złą. Zacznę może od tej... dobrej: Cały czas czytam, czytam, czytam i...czytam 🙂 I na obecną chwilę, wydaje mi się, że rozumiem dlaczego w pierszym poście nazwałeś platformę Arduino "piaskownicą". W każdym razie: rozumiem już czym są linie, porty, rejestry i operacje bitowe. Czym są przerwania wewnętrzne i zewnętrzne, czym są wewnętrzne timery mikroprocesora. I jak z nich korzystać. A przynajmniej tak mi się wydaje. 🙂 Wcześniej napisałeś: Domyślam się rozwiązania, które choć zapowiedziane... nie nastąpiło. I tu nie chodzi mi o mnie - tylko o innych początkujących (w "piaskownicy" ADRUINO IDE) czytających ten temat na forum. Dla nich byłoby dobrze, żeby to rozwiązanie jednak zostało pokazane. Oczywiście w sposób "arduinowy" 🙂 A ta zła wiadomość: Napisałeś: Tak "BTW": moje dzieci mają po 30 lat. I tak na co dzień raczej nie są "w pobliżu". Może chodziło Ci bardziej o moje wnuki? 😉 Wracając do tematu: koszty i Twojej i mojej opcji - są podobne. Około 30 zł. Do tego, pomimo, że napisałem iż wydaje mi się że rozumiem już programowanie mikrokontrolera w języku "C" - to, pomijając to, że mam tylko klona Arduino UNO oraz LED-y, rezystory, kondensatory - trzeba jeszcze kupić: programator (myślę o USBasp), mikrokontroler AVR ATmega 328P-PU (dodatkowy poza tym z Arduino - to jakieś 15 zł), "zewnętrzny" kwarc (jak w Arduino Uno czyli: 12 MHz). itp, itd. Dla Ciebie (i być może dla innych początkujących czytających ten temat) - te kwoty mogą wydawać się po prostu... śmieszne. Jednak dla mnie w tym momencie - w aspekcie ostatnich wydarzeń z życia mojego i mojej rodziny - o których nie chciałbym tu pisać na tym forum (które przecież jest jakoś... publiczne) - są to koszty na tę chwilę... nieosiągalne. Dlatego tym postem nie daję znać, że mam "zmontowany zestaw". Bo na tę chwilę nie mam. I chyba... nieprędko będę miał. Dlatego, mając wciąż "z tyłu głowy" początkujących (jak ja) czytających ten temat, proszę o "rozwinęcie tematu" pod tytułem: "jak z Arduino UNO (lub z mikrokontrolera) sterować "inteligentnymi" LED-ami RGB (jak sterować ich kolorem i jasnością). Oraz jak odwoływać się do adresów (i skąd wziąć te adresy) połączonych w linię "inteligentnych" LED RGB? O ile to możliwe - proszę o rozwinięcie tematu w sposób zrozumiały dla tych "bez "zmontowanego zestawu"" 😉
  6. A wydawało mi się, że to rozumiem 😉 W swoim przykładzie pod tytułem: "żeby jeszcze bardziej zakręcić" - pokazujesz zmienne lokalne różnych (2 ?) typów o takich samych nazwach. Ale w obrębie jednej funkcji. Czy żeby to rozumieć prawidłowo, mam myśleć że zmiennna typu static o nazwie licznik zadeklarowana w funkcji akuku() i pozostawiona w pamięci mikrokontrolera po zakończeniu działania tej funkcji - nie zostanie "nadpisana" (pomylona?) ze zmienną typu static o takiej samej nazwie licznik zadeklarowanej w innej funkcji o nazwie np. kukuryku()? Jeśli tak, to jest to faktycznie lekko... nielogiczne. W tym moim "rozwinięciu tematu" mówimy przecież wciąż o zestawie 8 punktów świetlnych. Z tym, że programowany (bo zmienny) ma być tylko ich kolor. Jasność świecenia każdego punktu ma być taka sama (stała). I tu poprawka: jeśli kolor będzie "programowany" to wystarczy 7 punktów świetlnych. Bo za tzw. pas dolny w semaforze będzie robiła jedna diodka świecąca raz na zielono a raz na pomarańczowo. Z "lutowaniem u mnie" - myślę, że dobrze. Myślałem raczej o zakupie czegoś takiego: http://botland.com.pl/led-rgb/2438-dioda-led-5-mm-rgb-ws2811-adresowana-10-szt.html A to dlatego, że tylko sześć takich LED RGB miałoby być umieszczonych w pionie. Siódma taka dioda miałaby być umieszczona obok tego sześcio-LED-owego "słupka", na "wysokości" trzeciej (licząc od góry) diody. W syglnalizacji kolejowej w Polsce występuje sygnalizator o nazwie "tarcza ostrzegawcza przejazdowa", który wyświetla dwa sygnały "Osp1" lub "Osp2"(http://www.kontrakt-bhp.com.pl/paul/kolej/sygn_top.php ). I właśnie ze względu na sygnał "Osp1" konieczne jest takie rozmieszczenie diod w modelu (przy założeniu, że model semafora ma wyświetlać wszystkie występujące na szlakach kolejowych w Polsce sygnały świetlne). Model semafora ma być tylko jeden. Stąd będzie tylko 7 takich LED RGB połączonych w jeden łańcuch. Tak, niektóre lampy będą mrugać. Tylko te (od góry licząc): pierwsza, druga, piąta. Ale zawsze (jeśli w ogóle coś będzie mrugać) - to tylko jedna lampa będzie mrugać. Dodatkowo (oprócz tej jednej mrugającej) - jedna lub dwie lampy mogą (ale nie muszą) świecić światłem ciągłym. "Potrzebne" kolory to: zielony, czerwony, pomarańczowy (żółty), biały, niebieski. "Zaczyna być ciekawie". No pewnie 😉
  7. Nie mam dość. A wręcz odwrotnie: czuję niedosyt 🙂 Wcześniej napisałeś: Chyba wiem dlaczego działa, chociaż niby nie powinno: początek funkcji glowny_fsm()? // Zmienna statyczna - to przypisanie wykona się tylko raz, // na początku programu. static uint8_t sygnal_state = S1; Wracając do Twojego ostatniego postu: niestety, wciąż jeszcze musimy podchodzić do sprawy w sposób tylko "Arduinowy". Próbowałem, zgodnie z Twoimi wcześniejszymi sugestiami, zmienić kod tak, żeby używając tylko jednej funkcji wykryj_klik() i tylko jednej funkcji sito() odkłócać oraz wykrywać wciśnięcie dwóch przycisków. Oczywiście próbowałem tylko w sposób "Arduinowy". Nie udało się. Bo nie mogło się udać. Pomimo tego, że funkcja sito() dostawała jako parametr - nr pinu odpowiedniego przycisku. Funkcja wykryj_klik() i funkcja sito() mają, co prawda, swoje "własne" zmienne lokalne. Ale przecież są to jednocześnie zmienne statyczne (typ static). Napisałeś: Otóż wydaje mi się, że... jednak nie. Zmienne statyczne, "lokalne" w różnych funkcjach - nie mogą się tak samo nazywać. Bo choć są dostępne tylko dla "swojej" funkcji, to po zakończeniu jej działania pozostają w pamięci. A w tym samym czasie mogą przechowywać różne wartości. Dlatego tak napisany program albo nie będzie działał w ogóle albo będzie działał nieprawidłowo.Czyż nie tak ❓ Ten problem można zapewne łatwo wyeliminować podchodząc do tematu w sposób bardziej zaawansowany niż ten "Arduinowy". Ale na to u mnie jeszcze nie czas... 😉 Chociaż w zasadzie mogłoby się to udać (jedna funkcja wykryj_klik() i jedna funkcja sito() dla wielu przycisków) i na sposób "Arduinowy" - o ile tu możliwe jest wewnątrz funkcji modyfikowanie nazwy zmiennej lokalnej poprzez "doklejenie" do tej nazwy przyrostka, przekazanego do funkcji jako jeden z jej parametrów (dostępne w innych językach programowania ❓ ). Ale żeby się o tym przekonać muszę "postudiować" podręcznik C/C++ (którego wciąż jeszcze nie mam) 😉 Póki co, musiałem napisać nie tylko dwie funkcje: sito1() i sito2() - ale także dwie funkcje wykryj_klik1() i wykryj_klik2(). Każda z osobna dla odpowiedniego przycisku (DALEJ i WSTECZ). Napisałeś dalej: Zaczynam to rozumieć 😉 Przycisków wcale nie musi być aż 8. Wystarczy, że zechcemy dodać jeden przycisk więcej niż było wcześniej - dla głównego FSM o... sporej ilości możliwych stanów układu. I ile to już "automatycznie" koniecznych zmian w kodzie... Żeby nie wklejać tu mojego "tasiemca" 🙂 z "wielkimi" switchami dla 18 stanów FSM - napisałem takiego "skrótowca" dla układu, w którym są tylko dwa przyciski. Główny FSM ( "główny" - bo przecież FSM-ami są też funkcje sito(), wykryj_klik() oraz raport()) - zmienia stan układu w "odpowiednią stronę", zależnie od tego, który przycisk został wciśnięty. Są tu tylko 3 możliwe stany układu. Tylko wtedy gdy nastąpi zmiana stanu układu - funkcja raport(sygnal) w oknie "Monitora szeregowego" podaje wartość aktualnego stanu układu. // Przyciski: #define DALEJ 3 #define WSTECZ 2 // Wartości stanu układu dla głównego FSM: #define S1 1 #define S2 2 #define S3 3 void setup() { pinMode(13, OUTPUT); // Żeby wbudowana LED na pinie 13 nie świeciła pinMode (DALEJ, INPUT_PULLUP); pinMode (WSTECZ, INPUT_PULLUP); Serial.begin(9600); // Ustawienie prędkości transmisji } void loop() { uint8_t klik1, klik2, sygnal; klik1 = wykryj_klik1(sito1()); klik2 = wykryj_klik2(sito2()); sygnal = glowny_fsm(klik1, klik2); raport(sygnal); delay(10); } // Wykrywanie wciśnięcia przycisku DALEJ: uint8_t wykryj_klik1(uint8_t odsiane) { static uint8_t nowy_stan1, poprzedni_stan1; nowy_stan1 = odsiane; if (nowy_stan1 < poprzedni_stan1) { poprzedni_stan1 = nowy_stan1; return 1; } else { poprzedni_stan1 = nowy_stan1; return 0; } } // Wykrywanie wciśnięcia przycisku WSTECZ: uint8_t wykryj_klik2(uint8_t odsiane) { static uint8_t nowy_stan2, poprzedni_stan2; nowy_stan2 = odsiane; if (nowy_stan2 < poprzedni_stan2) { poprzedni_stan2 = nowy_stan2; return 1; } else { poprzedni_stan2 = nowy_stan2; return 0; } } // Odkłócanie przycisku DALEJ uint8_t sito1() { const uint8_t czas_odbijania = 5; static uint8_t licznik_opoznienia1, poprzedni1, stabilny1; int odczyt = digitalRead(DALEJ); if (odczyt != poprzedni1) licznik_opoznienia1 = czas_odbijania; if (licznik_opoznienia1) licznik_opoznienia1--; else stabilny1 = odczyt; poprzedni1 = odczyt; return stabilny1; } // Odkłócanie przycisku WSTECZ uint8_t sito2() { const uint8_t czas_odbijania = 5; static uint8_t licznik_opoznienia2, poprzedni2, stabilny2; int odczyt = digitalRead(WSTECZ); if (odczyt != poprzedni2) licznik_opoznienia2 = czas_odbijania; if (licznik_opoznienia2) licznik_opoznienia2--; else stabilny2 = odczyt; poprzedni2 = odczyt; return stabilny2; } // Główna funkcja zmieniająca sekwencyjnie stan układu uint8_t glowny_fsm(uint8_t klik1, uint8_t klik2) { /* Zmienna statyczna - to przypisanie wykona się tylko raz, na początku programu. */ static uint8_t sygnal_state = S1; switch(sygnal_state) { case S1: if (klik1) sygnal_state = S2; else if (klik2) sygnal_state = S3; break; case S2: if (klik1) sygnal_state = S3; else if (klik2) sygnal_state = S1; break; case S3: if (klik1) sygnal_state = S1; else if (klik2) sygnal_state = S2; break; default: sygnal_state = S1; break; } return sygnal_state; } /* Funkcja wyświetlająca w oknie Monitora szeregowego wartość aktualnego stanu układu */ void raport(uint8_t sygnal) { static uint8_t poprzedni_sygnal = 255; if (poprzedni_sygnal != sygnal) { Serial.println(sygnal); Serial.println(); } poprzedni_sygnal = sygnal; }
  8. Dziękuję za cenne uwagi i porady. Zastosuję się. Fotek... nie będzie. Przynajmniej na tę chwilę. Bo moja "próba zbudowania w domu modelu (...)" - oznaczała na razie tylko złożenie prototypu układu na płytce stykowej i napisaniu kodu 😉 EDIT: Napisałeś No jasne. Przecież to było wyjaśnione już w filmie Barei pod tytułem "Miś":"Nie mieszajmy myślowo dwóch różnych systemów walutowych. Nie bądźmy peweksami." 🤣 EDIT 2: W nawiązaniu do tego, że "Fotek... nie będzie (...)". Bo to na razie tylko 7 LED-ów i 1 przycisk, wpięte w płytkę stykową: Ten mój model semafora - w zamyśle miał być taką "materialną wizualizacją" sygnałów możliwych do wyświetlenia na semaforze " pół-samoczynnym 5-komorowym", które można zobaczyć na wskazanej wcześniej przeze mnie stronie www. Miałoby to służyć do nauki (zapamiętania) wyglądu i znaczenia poszczególnych sygnałów. Stąd ten (docelowo) wyświetlacz LCD 16x2. Ale przecież sygnałów świetlnych na kolei jest więcej. Są także: semafory SBL, tarcze ostrzegawcze, sygnały powtarzające, tarcze manewrowe. Tylko, że różne kolory opraw (komór) świetlnych są w poszczególnych semaforach inaczej rozmieszczone (pomijając fakt, że semafory " pół-samoczynne" umieszczane są na masztach pomalowanych w biało-czerwone pasy, a cała reszta na masztach pomalowanych na kolor szary). Napisałeś wcześniej: I tu pojawiła się... nowa inspiracja: przecież budując taki fizyczny model semafora (pomijając sposób malowania jego masztu) i używając w tym modelu "inteligentnych LED RGB" oraz większego niż 16x2 wyświetlacza LCD - mógłbym zobrazować na tym modelu wszystkie występujące na szlakach kolejowych sygnały świetlne.Wtedy przydałaby się też rozbudowa "interfejsu" z jednego do dwóch przycisków. Jeden przycisk miałby zmieniać sygnały "w przód" (na następny sygnał), a drugi miałby zmieniać sygnały "w tył" (na poprzedni sygnał). Czyli w takim (tego rozbudowanego typu) modelu sygnalizacji kolejowej byłoby: 8 "inteligentnych LED RGB" połączonych w łańcuch oraz 2 przyciski ("poprzedni sygnał" i "następny sygnał"). No, tak. Tylko jak to zrobić w Arduino IDE? 😉 Jak zaimplementować obsługę dwóch przycisków tak, żeby jeden z nich robił "++sygnal", a drugi "--sygnal"? No i jak (w Arduino IDE) obsługiwać (adresować?) takie "inteligentne LED RGB" połączone w łańcuch? Jak to zrobić, żeby np. pierwsza w łańcuchu taka LED zaświeciła (lub migała) na zielono, a np. trzecia świeciła na biało (ale nie "w ogóle"=zawsze - a tylko w czasie wyświetlania jednego, konkretnego sygnału) ? Cały czas pamiętam też to, co napisałeś na samym początku: Więc i nie oczekuję gotowego "podręcznika". Tylko jakiejś... podpowiedzi (chociażby tylko sugerującej) gdzie mogę się czegoś (albo wręcz: czegokolwiek) na ten temat dowiedzieć (koniecznie z przykładami kodu!). No i najlepiej w jęz. polskim...Bo na pewno nie sposób się tego dowiedzieć z kursów na stronach www albo z książek (tam "królują" proste przykłady prostych czynności, zawsze z użyciem "bez ograniczeń" funkcji "delay()") 😉
  9. 1. To nie będzie makieta do kolejki H0. Więc skala jest... nieistotna. 2. No właśnie nie. Będą to same diodki (LED) plus sygnalizacja na LCD (początkowo Monitor Portu Szeregowego). Ale nie "kilka przycisków" - tylko... jeden przycisk. Po jego wciśnięciu wyświetlane przez LED-ki sygnały (oraz ich opisy na LCD lub w Monitorze Portu Szeregowego) będą się zmieniały "sekwencyjnie" - czyli po kolei, z jednego na drugi. 3. Nie mam pojęcia. Jakie powinny być opóźniena (w ms) zapalania i gaszenia LED aby to wyglądało na tradycyjną żarówkę? Próba zbudowania "w domu modelu pół-automatycznego semafora 5-komorowego" (jeden przycisk, 7 LED) na płytce stykowej i Arduino UNO - udała się za pierwszym razem. W głównej pętli "loop" co 10 ms wywoływany jest taki kod: void loop() { uint8_t klik, sygnal, pinLED, stanLED; klik = wykryj_klik(); sygnal = glowny_fsm(klik); podaj(sygnal, klik); delay(10); } Funkcja "wykryj_klik()" wykrywa (nioeomylnie) naciśnięcie przycisku. Funkcja "glowny_fsm()" - sekwencyjnie (z jednego na następny i z ostatniego na pierwszy) zmienia aktualny sygnał. Funkcja "podaj(sygnal, klik)" w zależności od wartości zmiennej "sygnal" wywołuje funkcję "obsluga_led" (odrębną dla każdej z 7 LED) z odpowiednim parametrem. Napisałeś: No tak. Ale jeśli mam dwie "znaczące" zmienne: "sygnal" i "klik" to moja funkcja "podaj(sygnal, klik)" - włącza odpowiednie LED w odpowiednim "trybie" i do tego w warunku "if (klik)" (jeśli wciśnięto przycisk) - wywołuje kolejną funkcję "raport(sygnal), która wyświetla w Monitorze Portu Szeregowego opis aktualnie wyświetlanego na LED-ach sygnału. Oczywiście tylko wtedy, gdy wyświetlany sygnał się zmienił. Nie jestem (ani nie czuję się) programistą - i wyszedł mi jakiś taki... "tasiemiec". Na pewno sporo zrobiłem "nie tak", sporo można by poprawić, inaczej pogrupować kod, inaczej skonstruować całość. Dodatkowo na wielkość kodu (ilość jego linii) - niewątpliwie ma wpływ ilość możliwych do wyświetlenia sygnałów. Razem z tym sygnałem zastępczym ("Sz") - jest ich razem... osiemnaście. Póki co - mój szkic (program) działa i wygląda tak: #define pinPrzycisku 2 #define LED_OFF 0 // stany LED #define LED_ON 1 #define LED_BLINK 2 #define GREEN 12 // nr pinów LED #define ORANGE_UP 11 #define RED 10 #define ORANGE_DN 9 #define WHITE 8 #define PAS_ORANGE 7 #define PAS_GREEN 6 #define S1 1 // nr sygnałów #define S2 2 #define S3 3 #define S4 4 #define S5 5 #define S6 6 #define S7 7 #define S8 8 #define S9 9 #define S10 10 #define S10a 11 #define S11 12 #define S11a 13 #define S12 14 #define S12a 15 #define S13 16 #define S13a 17 #define Sz 18 void setup() { pinMode(13, OUTPUT); // Żeby wbudowana LED na pinie 13 nie świeciła pinMode (pinPrzycisku, INPUT_PULLUP); pinMode(GREEN, OUTPUT); pinMode(ORANGE_UP, OUTPUT); pinMode(RED, OUTPUT); pinMode(ORANGE_DN, OUTPUT); pinMode(WHITE, OUTPUT); pinMode(PAS_ORANGE, OUTPUT); pinMode(PAS_GREEN, OUTPUT); Serial.begin(9600); //Ustawienie prędkości transmisji Serial.println("S1 - Stop."); Serial.println("Zakaz dalszej jazdy!"); Serial.println("\n"); } void loop() { uint8_t klik, sygnal, pinLED, stanLED; klik = wykryj_klik(); sygnal = glowny_fsm(klik); podaj(sygnal, klik); delay(10); } // Funkcja opisująca w Monitorze portu szeregowego // wyświetlany sygnał - tylko przy zmianie sygnału void raport (uint8_t sygnal) { switch(sygnal) { case S1: Serial.println("S1 - Stop."); Serial.println("Zakaz dalszej jazdy!"); Serial.println("\n"); break; case S2: Serial.println("S2 - Jazda."); Serial.println("V maksymalna dozwolona."); Serial.println("Kolejny semafor: V maksymalna dozwolona."); Serial.println("\n"); break; case S3: Serial.println("S3 - Jazda"); Serial.println("V max: 160km/h."); Serial.println("Kolejny semafor: ograniczenie do 100 km/h."); Serial.println("\n"); break; case S4: Serial.println("S4 - Jazda"); Serial.println("V max: Zwolnij."); Serial.println("Kolejny semafor: ograniczenie do 60 lub 40 km/h."); Serial.println("\n"); break; case S5: Serial.println("S5 - Jazda"); Serial.println("V max: Zwolnij."); Serial.println("Kolejny semafor: wskazuje stop."); Serial.println("\n"); break; case S6: Serial.println("S6 - Jazda"); Serial.println("V max: 100 km/h."); Serial.println("Kolejny semafor: V max."); Serial.println("\n"); break; case S7: Serial.println("S7 - Jazda"); Serial.println("V max: 100 km/h."); Serial.println("Kolejny semafor: ograniczenie 100 km/h."); Serial.println("\n"); break; case S8: Serial.println("S8 - Jazda"); Serial.println("V max: 100 km/h."); Serial.println("Kolejny semafor: ograniczenie 60 lub 40 km/h."); Serial.println("\n"); break; case S9: Serial.println("S9 - Jazda"); Serial.println("V max: 100 km/h."); Serial.println("Kolejny semafor: wskazuje stop."); Serial.println("\n"); break; case S10: Serial.println("S10 - Jazda"); Serial.println("V max: 40 km/h."); Serial.println("Kolejny semafor: V max."); Serial.println("\n"); break; case S10a: Serial.println("S10a - Jazda"); Serial.println("V max: 60 km/h."); Serial.println("Kolejny semafor: V max."); Serial.println("\n"); break; case S11: Serial.println("S11 - Jazda"); Serial.println("V max: 40 km/h."); Serial.println("Kolejny semafor: ograniczenie 100 km/h."); Serial.println("\n"); break; case S11a: Serial.println("S11a - Jazda"); Serial.println("V max: 60 km/h."); Serial.println("Kolejny semafor: ograniczenie 100 km/h."); Serial.println("\n"); break; case S12: Serial.println("S12 - Jazda"); Serial.println("V max: 40 km/h."); Serial.println("Kolejny semafor: ograniczenie 60 lub 40 km/h."); Serial.println("\n"); break; case S12a: Serial.println("S12a - Jazda"); Serial.println("V max: 60 km/h."); Serial.println("Kolejny semafor: ograniczenie 60 lub 40 km/h."); Serial.println("\n"); break; case S13: Serial.println("S13 - Jazda"); Serial.println("V max: 40 km/h."); Serial.println("Kolejny semafor: wskazuje Stop."); Serial.println("\n"); break; case S13a: Serial.println("S13a - Jazda"); Serial.println("V max: 60 km/h."); Serial.println("Kolejny semafor: wskazuje Stop."); Serial.println("\n"); break; case Sz: Serial.println("Sz - Jazda z ostroznoscia"); Serial.println("V max: do 40 km/h."); Serial.println("Gotowosc do naglego zatrzymania."); Serial.println("\n"); break; } } // Funkcja wyświetlająca odpowiedni obraz na semaforze // w zależności od zmienej sygnał - wywołuje "obsluga_led()" // oraz "raport()" z odpowiednimi parametrami. void podaj(uint8_t sygnal, uint8_t klik) { switch(sygnal) { case S1: obsluga_led1(LED_OFF); obsluga_led2(LED_OFF); obsluga_led3(LED_ON); obsluga_led4(LED_OFF); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S2: obsluga_led1(LED_ON); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_OFF); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S3: obsluga_led1(LED_BLINK); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_OFF); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S4: obsluga_led1(LED_OFF); obsluga_led2(LED_BLINK); obsluga_led3(LED_OFF); obsluga_led4(LED_OFF); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S5: obsluga_led1(LED_OFF); obsluga_led2(LED_ON); obsluga_led3(LED_OFF); obsluga_led4(LED_OFF); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S6: obsluga_led1(LED_ON); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_ON); if (klik) raport(sygnal); break; case S7: obsluga_led1(LED_BLINK); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_ON); if (klik) raport(sygnal); break; case S8: obsluga_led1(LED_OFF); obsluga_led2(LED_BLINK); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_ON); if (klik) raport(sygnal); break; case S9: obsluga_led1(LED_OFF); obsluga_led2(LED_ON); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_ON); if (klik) raport(sygnal); break; case S10: obsluga_led1(LED_ON); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S10a: obsluga_led1(LED_ON); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_ON); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S11: obsluga_led1(LED_BLINK); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S11a: obsluga_led1(LED_BLINK); obsluga_led2(LED_OFF); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_ON); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S12: obsluga_led1(LED_OFF); obsluga_led2(LED_BLINK); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S12a: obsluga_led1(LED_OFF); obsluga_led2(LED_BLINK); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_ON); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S13: obsluga_led1(LED_OFF); obsluga_led2(LED_ON); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case S13a: obsluga_led1(LED_OFF); obsluga_led2(LED_ON); obsluga_led3(LED_OFF); obsluga_led4(LED_ON); obsluga_led5(LED_OFF); obsluga_led6(LED_ON); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; case Sz: obsluga_led1(LED_OFF); obsluga_led2(LED_OFF); obsluga_led3(LED_ON); obsluga_led4(LED_OFF); obsluga_led5(LED_BLINK); obsluga_led6(LED_OFF); obsluga_led7(LED_OFF); if (klik) raport(sygnal); break; } } // Główna funkcja zmieniająca sekwencyjnie stan sygnału uint8_t glowny_fsm(uint8_t klik) { // Zmienna statyczna - to przypisanie wykona sie tylko raz, // na początku programu. static uint8_t sygnal_state = S1; switch(sygnal_state) { case S1: if (klik) sygnal_state = S2; break; case S2: if (klik) sygnal_state = S3; break; case S3: if (klik) sygnal_state = S4; break; case S4: if (klik) sygnal_state = S5; break; case S5: if (klik) sygnal_state = S6; break; case S6: if (klik) sygnal_state = S7; break; case S7: if (klik) sygnal_state = S8; break; case S8: if (klik) sygnal_state = S9; break; case S9: if (klik) sygnal_state = S10; break; case S10: if (klik) sygnal_state = S10a; break; case S10a: if (klik) sygnal_state = S11; break; case S11: if (klik) sygnal_state = S11a; break; case S11a: if (klik) sygnal_state = S12; break; case S12: if (klik) sygnal_state = S12a; break; case S12a: if (klik) sygnal_state = S13; break; case S13: if (klik) sygnal_state = S13a; break; case S13a: if (klik) sygnal_state = Sz; break; case Sz: if (klik) sygnal_state = S1; break; } return sygnal_state; } // Obsługa LED1 void obsluga_led1( uint8_t stanLED) { static uint8_t licznik1; switch(stanLED) { default: case LED_OFF: digitalWrite(GREEN, LOW); licznik1 = 0; break; case LED_ON: digitalWrite(GREEN, HIGH); licznik1 = 0; break; case LED_BLINK: if (++licznik1 >= 100) // Licznik działa w cyklu 100 licznik1 = 0; if (licznik1 < 50) // Wypełnienie 50 na 50 digitalWrite(GREEN, HIGH); else digitalWrite(GREEN, LOW); break; } } // Obsługa LED2 void obsluga_led2( uint8_t stanLED) { static uint8_t licznik2; switch(stanLED) { default: case LED_OFF: digitalWrite(ORANGE_UP, LOW); licznik2 = 0; break; case LED_ON: digitalWrite(ORANGE_UP, HIGH); licznik2 = 0; break; case LED_BLINK: if (++licznik2 >= 100) // Licznik działa w cyklu 100 licznik2 = 0; if (licznik2 < 50) // Wypełnienie 50 na 50 digitalWrite(ORANGE_UP, HIGH); else digitalWrite(ORANGE_UP, LOW); break; } } // Obsługa LED3 void obsluga_led3( uint8_t stanLED) { switch(stanLED) { default: case LED_OFF: digitalWrite(RED, LOW); break; case LED_ON: digitalWrite(RED, HIGH); break; } } // Obsługa LED4 void obsluga_led4( uint8_t stanLED) { switch(stanLED) { default: case LED_OFF: digitalWrite(ORANGE_DN, LOW); break; case LED_ON: digitalWrite(ORANGE_DN, HIGH); break; } } // Obsługa LED5 void obsluga_led5( uint8_t stanLED) { static uint8_t licznik5; switch(stanLED) { default: case LED_OFF: digitalWrite(WHITE, LOW); licznik5 = 0; break; case LED_ON: digitalWrite(WHITE, HIGH); licznik5 = 0; break; case LED_BLINK: if (++licznik5 >= 100) // Licznik działa w cyklu 100 licznik5 = 0; if (licznik5 < 50) // Wypełnienie 50 na 50 digitalWrite(WHITE, HIGH); else digitalWrite(WHITE, LOW); break; } } // Obsługa LED6 void obsluga_led6( uint8_t stanLED) { switch(stanLED) { default: case LED_OFF: digitalWrite(PAS_ORANGE, LOW); break; case LED_ON: digitalWrite(PAS_ORANGE, HIGH); break; } } // Obsługa LED7 void obsluga_led7( uint8_t stanLED) { switch(stanLED) { default: case LED_OFF: digitalWrite(PAS_GREEN, LOW); break; case LED_ON: digitalWrite(PAS_GREEN, HIGH); break; } } // Odkłocanie przycisku uint8_t sito() { const uint8_t czas_odbijania = 5; static uint8_t licznik_opoznienia, poprzedni, stabilny; int odczyt = digitalRead(pinPrzycisku); if (odczyt != poprzedni) licznik_opoznienia = czas_odbijania; if (licznik_opoznienia) licznik_opoznienia--; else stabilny = odczyt; poprzedni = odczyt; return stabilny; } // Wykrywanie wciśnięcia przycisku: uint8_t wykryj_klik() { static uint8_t nowy_stan, poprzedni_stan; nowy_stan = sito(); if (nowy_stan < poprzedni_stan) { poprzedni_stan = nowy_stan; return 1; } else { poprzedni_stan = nowy_stan; return 0; } } I jeszcze pytanie: W podręcznikach poświęconych programowaniu (np. PHP) wyczytałem, że w instrukcji wielokrotnego wyboru "switch ... case", w poszczególnych przypadkach (zdefiniowanych przez "case(x):" - można użyć tylko... jednej instrukcji. Tymczasem (i w moim w/w szkicu - i w Twoich przykładach) pomiędzy "case(x):" i "break;" jest więcej niż jedna instrukcja. To działa. Ale czy to jest poprawne?
  10. To już tylko krótkie 😃 wyjaśnienie. Rzeczywiście brzmi to trochę jak nazwa jakiegoś Uzi. Jednak komora - to w tym przypadku (zupełnie nie nabojowa) oprawa świetlna. A pół-samoczynny - bo sygnał zezwalający na przejazd pociągu włącza dyżurny ruchu z nastawni, a gdy pociąg minie semafor - to semafor samoczynnie przełącza się na sygnał S1 ("Stój"). W odróżnieniu od semaforów samoczynnych SBL (Samoczynna Blokada Liniowa), w której przy torach są czujniki "masy" i semafor wykrywając nadjeżdżający pociąg - sam wyświetla mu odpowiedni sygnał w zależności od "zajętości" torów na kolejnych dwóch odcinkach szlaku kolejowego. Semafora oczywiście budować w domu nie zamierzam. Tylko jego model. Z siedmiu LED ustawionych pionowo: zielona, żółta, czerwona, znowu żółta, biała, żółta i zielona. Ostatnie dwie (dolne) imitują tzw. pas dolny. Pierwsze dwie od góry (zielona i żółta) mogą świecić ciągle, migać lub być wygaszone. Oczywiście każda z nich świeci lub miga oddzielnie - albo jedna albo druga. Pozostałe albo świecą ciągle (jedna z nich lub dwie) albo są wygaszone. Dodatkowo piąta (licząc od góry) biała LED może także migać. Tak więc: wersja minimum to tylko jedna LED świeci lub miga. Wersja maksimum to dwie LED świecą i trzecia świeci lub miga. Jak nic nie świeci ani nie miga - to znaczy że się coś... popsuło 😉 Brzmi to może trochę zawile - ale jak to wygląda można zobaczyć tutaj Użyte tam określenia "pierwsza droga jazdy" i "druga droga jazdy" oznaczają odpowiednio: odcinek torów za mijanym właśnie semaforem (do następnego semafora) oraz odcinek torów za następnym semaforem (do kolejnego semafora).
  11. To nie tak. Rzadko kiedy się denerwuję. Ze mnie jest taki "niespotykanie spokojny człowiek". Raczej nigdy nie denerwuję się gdy mi coś nie wychodzi. A jeśli już taki "wyjątkowy wyjątek" się zdarzy, to denerwuję się tylko na siebie. Więc: 1. Po "pierwsze primo" - nie przepraszaj. Bo nie masz za co. 2. Po "drugie primo" - to ja przepraszam. I Ciebie i pozostałych kolegów z tego Forum. Przepraszam za moje czasami zbyt "impulsywne" wpisy, spowodowane moją niecierpliwością. To prawda, że w "przerwach" mogłem zajrzeć do podręcznika (którego nie mam) lub odpytać "wujka Google"i uzupełnić swoją wiedzę w kwestiach, które były (są) dla mnie "mgliste". Jednak ta "zabawa" zaproponowana przez Ciebie okazała się tak wciągająca, że mając zadaną kolejną "pracę domową" - nie potrafiłem się skupić na czytaniu. Czegokolwiek. 3. Po "trzecie primo"- dziękuję Ci za cierpliwość. Tu chcę również podziękować kolegom z forum o nickach: "deshipu" oraz "Chumanista", którzy w tzw. międzyczasie też próbowali pomóc. Uznałeś mnie za "programistę": Niczego takiego na pewno nigdy i nigdzie nie pisałem. Bo sam o sobie tak nie myślę. Co prawda kiedyś w Borland Delphi - chyba 6 (chyba - bo dokładnie nie pamiętam) - napisałem kilka bardzo prostych programów dla Windows (wtedy) Xp. No i te kilka stron www korzystających z PHP 5 z obsługą MySQL. I tylko dlatego ośmieliłem się uznać za... początkującego. Ale tak, jak piszesz: Dalej piszesz: A "chwilę dalej" piszesz: I podajesz przykład kodu: int glowny_fsm(int klik) { static uint8_t fsm_state = LED_OFF; // Zmienna statyczna - to przypisanie wykona sie tylko raz, na początku programu (może być byte lub nawet int :) ) switch(fsm_state) { case LED_OFF: if (klik) fsm_state = LED_ON; break; case LED_ON: if (klik) fsm_state = LED_BLINK; break; case LED_BLINK: if (klik) fsm_state = LED_OFF; break; } return fsm_state; } I ten Twój przykład - to, w zasadzie, wszystko czego potrzeba. No i spróbowałem. Niestety nie obyło się bez problemów. A problemy objawiły się przez nazewnictwo. I to nie tyle zmiennych - ile parametrów funkcji. Do funkcji migaj() mamy przekazać parametr o nazwie "led_mode". A w jednym z ostatnich postów, Ty ten parametr nazwałeś "stan_led". Oczywiście - to tylko kwestia przyjętej konwencji... 🙂 Co nie zmienia faktu, że mamy jeszcze jeden "babol": W jednym z ostatnich postów, proponując kod, który ma być umieszczony w głównej pętli "loop()" napisałeś: uint8_t klik, stan_led; { klik = wykryj_klik(sito()); stan_led = glowna_funkcja(klik); migaj(stan_led); delay(10); } Otóż chyba funkcja "wykryj_klik()" nie może być tak wywoływana. Przy takim zapisie jaki proponujesz - kompilator zgłasza błąd o treści: "too many arguments to function 'unit8_t wykryj_klik()". Nie żebym się "mądrzył", czy żebym chciał uchodzić za takiego, co to "rozumy zjada". Ale jeśli funkcja wykryj_klik() niejako "sama z siebie" w swoim "ciele" wywołuje funkcję sito() - to nie można (przypisując jej wynik do zmiennej o nazwie "klik") wywoływać jej w sposób zaproponowany przez Ciebie. W każdym razie: spróbowałem sklecić cały kod. Potem usunąłem (tak myślę) błędy zgłaszane przez kompilator. I wyszło mi coś takiego: #define pinPrzycisku 2 #define pinLED 13 #define LED_OFF 0 #define LED_ON 1 #define LED_BLINK 2 void setup() { // put your setup code here, to run once: pinMode (pinPrzycisku, INPUT_PULLUP); pinMode (pinLED, OUTPUT); } void loop() { uint8_t klik, led_mode; klik = wykryj_klik(); led_mode = glowny_fsm(klik); migaj(led_mode); delay(10); } void migaj(uint8_t led_mode) { static uint8_t licznik; switch(led_mode) { default: case LED_OFF: digitalWrite(pinLED, LOW); licznik = 0; break; case LED_ON: digitalWrite(pinLED, HIGH); licznik = 0; break; case LED_BLINK: if (++licznik >= 100) // Licznik działa w cyklu 100 licznik = 0; if (licznik < 10) digitalWrite(pinLED, HIGH); else digitalWrite(pinLED, LOW); break; } } // Odkłocanie przycisku uint8_t sito() { const uint8_t czas_odbijania = 5; static uint8_t licznik_opoznienia, poprzedni, stabilny; int odczyt = digitalRead(pinPrzycisku); if (odczyt != poprzedni) licznik_opoznienia = czas_odbijania; if (licznik_opoznienia) licznik_opoznienia--; else stabilny = odczyt; poprzedni = odczyt; return stabilny; } // Wykrywanie wciśnięcia przycisku: uint8_t wykryj_klik() { static uint8_t nowy_stan, poprzedni_stan; nowy_stan = sito(); if (nowy_stan < poprzedni_stan) { poprzedni_stan = nowy_stan; return 1; } else { poprzedni_stan = nowy_stan; return 0; } } // Funkcja glowny_fsm od której wszystko zależy :-) uint8_t glowny_fsm(uint8_t klik) { static uint8_t fsm_state = LED_OFF; // Zmienna statyczna - to przypisanie wykona się tylko raz, // na początku programu. switch(fsm_state) { case LED_OFF: if (klik) fsm_state = LED_ON; break; case LED_ON: if (klik) fsm_state = LED_BLINK; break; case LED_BLINK: if (klik) fsm_state = LED_OFF; break; } return fsm_state; } Jak widać powyżej - "nie taki diabeł straszny jak go malują". Mam tu na myśli zastąpienie typu (bliżej nieokreślonego) "int" typem (dokładnie określonym) "uint8_t" 😃 Potem wgrałem ten kod do mojego Arduino UNO i odpaliłem go. Czyli "na sprzęcie". Cały kod - od początku do końca. Od razu. I... działa. I działa tak, jak... miało działać. Po wgraniu powyższego szkicu do mojego Arduino UNO - program startuje od stanu LED "wyłączona". Wciśnięcie przycisku powoduje zmianę stanu LED na "włączona" (świeci ciągle). Kolejne wciśnięcie przycisku powoduje zmianę stanu LED na "migaj" (wypełnienie: przez 100 ms świeć, przez 900 ms zgaś). Każde kolejne wciśnięcie przycisku powoduje (sekwencyjnie) przejście LED do kolejnego stanu. Cykl stanów LED to: LED zgaszona --> LED świeci --> LED miga. I w obojętnie, w którym stanie LED by nie była - układ natychmiast reaguje na wciśnięcie przycisku. I to niezależnie od tego, czy przycisk wcisnę na bardzo krótko (kilik), czy trochę dłużej (krótkie wciśnięcie), czy na bardzo długo (wciśnięcie i trzymanie wciśniętego przycisku). FAJNE! 😃 Już mnie "nęci" samodzielne przystosowanie tego kodu do tego, żeby ten 1 przycisk sterował w taki sposób 2 różnymi LED-ami "podpiętymi" do 2 pinów na płytce Arduino. Czyli żeby dojść do tego o co pytałem - zadając moje pytanie. Albo - idąc dalej - żeby układ rozróżniał "klik" od "wciśnięcia", a "wciśnięcie" od "wciśnięcia i przytrzymania"... 😉 A gdybym chciał z pomocą Arduino UNO zbudować "symulator" kolejowego (znanego ze szlaków PLK) pół-samoczynnego semafora 5 komorowego (potrzeba 7 LED-ów), zmieniającego wyświetlany sygnał (1,2,3 LED-y świecące ciągle, lub 2 LED-y świecące ciągle i 1 LED migająca, albo tylko 1 LED migająca) sekwencyjnie po wciśnięciu 1 przycisku, i jeszcze do tego dla każdego sygnału wyświetlić (początkowo w Monitorze portu szeregowego - a docelowo na dołączonym wyświetlaczu LCD 16x2) - opis każdego kolejnego sygnału semafora - to myślę, że już będę wiedział jak to zrobić. Marku - wielkie dzięki! Przede wszystkim za cierpliwość dla mnie. Ale także - za wskazanie sposobu. Za pokazanie drogi (zapewne jednej z wielu możliwych), którą należy podążać aby osiągnąć coś, co z pozoru wydaje się być "nieosiągalne". Napisałeś gdzieś w trakcie: Tak było. Zresztą nie wiem, czy użycie czasu przeszłego jest w moim przypadku do końca zasadne. Być może należałoby w dalszym ciągu powiedzieć: "tak jest". Bo dalej nie tylko, że "nie rozumiem" struktury mikrokontrolera - to nawet jej... nie znam. Braki mojej wiedzy w tym temacie - uzupełnię. Nie będę tu obiecywał, że "najszybciej jak się da". Ale tak mnie to zaciekawiło i "wciągnęło" - że po prostu muszę się dowiedzieć najwięcej jak tylko będę mógł. I to nie po to, żeby komuś, czy sobie, cokolwiek udowadniać. Po prostu - mogę mieć wieczorem problem z zaśnięciem, gdy będę miał świadomość, że "dziś mogłem się jeszcze czegoś więcej dowiedzieć, przeczytać..." 😃 A co najbardziej przeszkadza takim "początkującym z mikrokontrolerami" jak ja? To czy ktoś kiedykolwiek "programował" cokolwiek dla komputera PC - to z jednej strony trochę pomaga. Bo tak naprawdę wszystkie języki programowania "wysokiego poziomu" są do siebie podobne. Czy to Pascal, czy C, czy C++, czy Java, czy PHP, czy inne... W każdym języku są algorytmy, pętle, warunki, warunki wielokrotnego wyboru, itp, itd. Cała różnica polega tylko na niuansach związanych ze składnią danego języka (sposobem wydawania poleceń). Więc to ogólnie pomaga. Bo taki człowiek rozumie już na wstępie co to są stałe, zmienne, zasięg zmiennych, przesłanianie zmiennych... Rozumie zapis "for...", "if...", "while..." itp, itd. Ale jednocześnie przeszkadza. I to tym bardziej, że w internecie (na youtube też) - aż roi się od poradników i tutoriali, w których autor odpowiadając na pytanie "czym jest Arduino?" albo "czym jest mikrokontroler? - stwierdza: "tak naprawdę to miniaturowy komputer". W domyśle: klasy PC. A na pytanie "co mogę zrobić korzystając z Arduino?" lub "co mogę zrobić wykorzystując mikrokontroler?" - odpowiada: "wszystko, co tylko podsunie ci wyobraźnia". I to w sumie prawda. Ale jak blisko jest stąd do skrótu myślowego, że mikrokontroler to miniaturowy komputer PC? Mikrokontroler różni się od komputera tym, że nie ma systemu operacyjnego. I w danej chwili potrafi zrobić tylko jedną rzecz... Oczywiście wykonując wiele takich "pojedynczych rzeczy" dostatecznie szybko - możemy "udawać", że mikrokontroler ma... "wielowątkowość". Ale trzeba wiedzieć, jak to zrobić. Tymczasem i w internecie i w książkach o Arduino - jak "grzyby po deszczu" mnożą się proste przykłady "zrobienia" prostych rzeczy, które wprost sieją funkcją delay(). Ta funkcja - sama z siebie - nie jest zła. Tylko trzeba jej używać "z głową" 😉
  12. Po kolei: Tu zacznę, sorki za wyrażenie, "od tyłu". 1. Moja funkcja będzie działała pod warunkiem, że dostaje wartości 0 lub 1. Przepraszam za (może głupie) pytanie - ale co innego ta moja funkcja może dostać? Co innego oprócz 0 lub 1 może dostać, jeśli wywoływana w niej funkcja sito() może zwrócić tylko 0 lub 1? 2. "Nie projektujemy tu rakiet" - no, to wiadomo 🙂 "A operatory logiczne opanujesz po pierwszym przeczytaniu i użyciu. Dobra, biegłość - po dziesiątym." -----------------------I TU WAŻNA UWAGA ---------------------------------------------------------- Chyba się nie rozumiemy. A to zapewne przez definicję słowa "początkujący". Gdybym określił siebie definicją "zupełnie zielony" - to nic by nie dało. Mógłbym nawet określić siebie definicją: "tylko zielonkawy, ledwo wykiełkowany". Ale to też by nic nie dało. Przez to, że w temacie zaawansowania w programowaniu mikrokontrolerów: Twoje_definicje != Moje_definicje; ------------------------------------------------------------------------------------------------------ Operatory logiczne, matematyczne, porównania, przypisania - znam. I wydaje mi się, że rozumiem, jak działają. To nie operatory są istotne, tylko to, co napisałem w poprzednim poście: "(...) Widzę też, że wybierając dział do zadania pytania - zbyt optymistycznie uznałem, że jestem początkujący. Powinienem był zapytać w dziale Zupełnie zieloni... Inaczej mówiąc: jeśli przykład z mojego pytania da się dokończyć przy pomocy takich podstawowych ("piaskownicowych"?) poleceń, jak w funkcjach obsługi LED czy przycisku, to możemy kontynuować. Jeżeli jednak w kolejnych etapach będę miał stworzyć kod, w którym koniecznością jest używanie poleceń odnoszących się bezpośrednio do linii, portów oraz bitów (i operowania na bitach) - to dalszy ciąg musimy odłożyć do czasu, gdy będę o takich poleceniach wiedział więcej (i to dużo więcej) niż tylko to, że istnieją, są dostępne i jak (z grubsza) wyglądają w treści kodu programu. (...)" ------------------------------------------------------------------------------------------------------ Pisząc tak zupełnie wprost: 1. Nie mam zupełnie pojęcia o zmiennych typu: uint8_t, uint16_t, uint32_t i uint64_t plus o ich odpowiednikach ze znakiem: int8_t, int16_t. 2. Nie mam zupełnie pojęcia o liniach, potach i bitach. 3. Polecenia typu: "PINC & 0x3F" lub "((~PINB & 0xC0) >> 3) | (~PINA & 0x07))" - są dla mnie kompletnie niezrozumiałe. No może poza tym, że PIN oznacza nóżkę mikrokontrolera. C, B lub A określa, która to nóżka (port "wyjście" albo "wejście"). Ale reszta - to dla mnie "ciemna magia" 😉 4. Nie zadawaj mi też proszę "utrudnień" pisząc o liczbie bitów, np: 4, 6, albo 8. O tym też nie mam zielonego pojęcia! Bo jestem tylko "początkujący". Czy teraz już rozumiesz mój "poziom zaawansowania"? Oczywiście z mojej strony - projekt kolejnej funkcji nastąpi. Choć z oczywistych względów (opisanych powyżej) raczej nie użyję typu "uint8_t". Mam nadzieję, że się nie obrazisz. Chcę poznać dalszy ciąg, i dzięki temu nauczyć czegoś nowego. Ale ja naprawdę jestem "zupełnie zielony". Albo nawet "zielonkawy, ledwo wykiełkowany". I już choćby już tylko z tego powodu jest mi trudno. Nie dawaj mi zadań typu: "żeby było trudniej..." albo: "żeby było ciekawiej...". I proszę: nie pisz o rzeczach, które dla Ciebie są pewnie trywialne, ale o których ja (jako początkujący) nie mam jeszcze... zielonego pojęcia.
  13. No tak. Czasem najciemniej bywa pod latarnią... "Dobrych stron" jest więcej: teraz już wiem jak bardzo łatwo zgubić z oczu główny cel, kiedy zacznie się przyglądać rzeczom z pozoru ważnym, a ostatecznie zupełnie nieistotnym. Proste rzeczy "programuję" i analizuję "w głowie". Bardziej złożone (czyli z cyklu: "to się w głowie nie mieści...") - na papierze. "Na sprzęcie" zwykle testuję dopiero to, co uważam za "zakończony" szkic programu. Teraz - w razie potrzeby - będę tak sprawdzał także pojedyncze funkcje programu (szkicu). Widzę też, że wybierając dział do zadania pytania - zbyt optymistycznie uznałem, że jestem początkujący. Powinienem był zapytać w dziale Zupełnie zieloni... Inaczej mówiąc: jeśli przykład z mojego pytania da się dokończyć przy pomocy takich podstawowych ("piaskownicowych"?) poleceń, jak w funkcjach obsługi LED czy przycisku, to możemy kontynuować. Jeżeli jednak w kolejnych etapach będę miał stworzyć kod, w którym koniecznością jest używanie poleceń odnoszących się bezpośrednio do linii, portów oraz bitów (i operowania na bitach) - to dalszy ciąg musimy odłożyć do czasu, gdy będę o takich poleceniach wiedział więcej (i to dużo więcej) niż tylko to, że istnieją, są dostępne i jak (z grubsza) wyglądają w treści kodu programu. Zakładając jednak, że z tego typu utrudnień możemy zrezygnować, to kolejna funkcja wydaje mi się bardzo prosta. Podejrzewam, że będzie ona wywoływana tak samo jak pozostałe: co 10 ms. Nie muszę tu na nic czekać, więc nie będzie licznika. Przy każdym wywołaniu funkcji do zmiennej nowy_stan przypisuję wartość, którą zwraca funkcja sito(). Jeśli przycisk nie jest wciśnięty to mam 1 (bo INPUT_PULLUP). Wciśnięty to 0. Czyli interesuje mnie tylko sytuacja, kiedy stan zmienia się z 1 na 0. Sprawdzam więc czy nowy_stan jest mniejszy niż poprzedni_stan. Jeśli tak, to było kliknięcie i zwracam 1. W każdym innym przypadku uznaję, że kliknięcia nie było i zwracam 0. W obu przypadkach przepisuję też wartość zmiennej nowy_stan do zmiennej poprzedni_stan. int wykryj_klik() { static int nowy_stan, poprzedni_stan; nowy_stan = sito(); if (nowy_stan < poprzedni_stan) { poprzedni_stan = nowy_stan; return 1; } else { poprzedni_stan = nowy_stan; return 0; } }
  14. Jeszcze jedna próba 😕 Zakładając, że drgania styków objawiają się tylko i wyłącznie "naprzemiennym ciągiem jedynek i zer" - tzn. nie jest możliwa sytuacja, że uda się złapać po kolei dwa (lub więcej) zera albo dwie (lub więcej) jedynki - to odkłócanie "niesfornego przycisku" powinna załatwić funkcja w takiej postaci: #define pinPrzycisku 2 int sito() { const int czekaj = 5; static int zlicz, poprzedni, stabilny; int odczyt = digitalRead(pinPrzycisku); if (odczyt != poprzedni) { ++zlicz; if (zlicz < czekaj) { return stabilny; } if (zlicz == czekaj) { zlicz = 0; if (odczyt != stabilny) { stabilny = odczyt; poprzedni = odczyt; return stabilny; } } } else { poprzedni = odczyt; return stabilny; } }
  15. No fakt. Umknęło mi to. Jeśli wywołam funkcję gdy zlicz będzie miał wartość z zakresu od 0 do 4, to aktualny będzie zawsze 0. Jeśli stabilny będzie "pamiętał" też 0, to nic złego się nie stanie: zwrócę z funkcji ten sam stabilny. Ale jeśli stabilny będzie "pamiętał" 1, to zmienię i zwrócę z funkcji nową wartość zmiennej stabilny bez... sprawdzenia stanu przycisku. Teraz powinno być dobrze: #define pinPrzycisku 2 int sito() { const int czekaj = 5; static int zlicz, stabilny; int aktualny = digitalRead(pinPrzycisku); if (aktualny != stabilny) { if (++zlicz == czekaj) { zlicz = 0; stabilny = aktualny; return stabilny; } else return stabilny; } else return stabilny; } Chyba, że znów coś przeoczyłem 😉
×
×
  • Utwórz nowe...

Ważne informacje

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