Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy
Wałaszek |
©2024 mgr Jerzy Wałaszek
|
Na płytce do portu P0 podłączony jest przycisk, który w momencie naciśnięcia go przez użytkownika zwiera port P0 do masy, czyli wymusza niski stan logiczny 0.
Elementy | Ilość | Uwagi |
Dioda LED | 4 | 3mm czerwona |
Opornik 470Ω | 4 | 0,25W |
Przycisk TACT | 1 | |
Goldpiny męskie długie 1x3 | 1 | |
Goldpiny męskie 1x5 | 1 |
ds002_tht.sch | : | schemat ideowy w Eagle |
ds002_tht.brd | : | projekt płytki drukowanej w Eagle |
ds002_tht_a.png | : | obrazek z widokiem elementów na płytce |
ds002_tht_b.png | : | obrazek spodu płytki |
ds002.svg | : | plik Inkscape do wydruku na drukarce laserowej |
Elementy | Ilość | Uwagi |
Dioda LED | 4 | SMD czerwona, 0805 |
Opornik 470Ω | 4 | SMD 0805 |
Przycisk TACT | 1 | SMD |
Goldpiny męskie długie 1x3 | 1 | |
Goldpiny męskie 1x5 | 1 |
ds002_smd.sch | : | schemat ideowy w Eagle |
ds002_smd.brd | : | projekt płytki drukowanej w Eagle |
ds002_smd_a.png | : | obrazek z widokiem elementów na płytce |
ds002_smd_t.png | : | obrazek góry płytki |
ds002.svg | : | plik Inkscape do wydruku na drukarce laserowej |
W poprzednim rozdziale zajmowaliśmy się programowaniem wyjść portów P0...P4. W tym rozdziale zajmiemy się programowaniem wejść, a ściślej jednego wejścia P0.
Każdy port
Digisparka może pracować jako wyjście lub wejście. Praca portu
jako wejście umożliwia odczyt danych. Aby port działał jako
wejście lub wyjście, należy go odpowiednio skonfigurować na
początku programu. Najczęściej wykonuje się to w funkcji
Płytka DS002 jest tak skonstruowana, iż do portu P0 podłączony jest przycisk, a do portów P1, P2, P3 i P4 podłączone są diody LED. Mikrokontroler Digisparka należy tak skonfigurować, aby port P0 pracował w trybie wejścia, czyli pozwalał odczytywać stan logiczny panujący na P0, a pozostałe porty pracowały w trybie wyjścia.
Podłącz płytkę DS002 do modułu Digispark.
Uruchom środowisko Arduino i utwórz szkic dla Digisparka.
Przekopiuj do edytora poniższy program, a następnie prześlij go do Digisparka (pamiętaj o procedurze programowania modułu Digispark, którą opisaliśmy w poprzednich rozdziałach).
// Odbiornik pola bioenergetycznego // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście pinMode(0,INPUT); // Ustawiamy porty P1...P4 jako wyjścia for(char i = 1; i <= 4; i++) pinMode(i,OUTPUT); } // Pętla główna programu //---------------------- void loop() { char v; v = digitalRead(0); // Czytamy stan portu P0 // Zapisujemy ten stan do portów P1...P4, które // sterują diodami LED. for(char i = 1; i <= 4; i++) digitalWrite(i,v); } |
Program ten działa dziwnie. Przeanalizujmy go:
W funkcji setup() ustawiamy tryb pracy wszystkich portów. Port P0 zostaje ustawiony w tryb wejścia (ang. INPUT), tzn. mikrokontroler będzie mógł odczytywać stan logiczny linii P0, do której podpięty jest przycisk. Przycisk normalnie jest rozwarty, zatem linia P0 wisi sobie i nie jest do niczego podłączona, jeśli nie naciskasz przycisku. Więcej o tym piszemy dalej.
Pozostałe porty P1...P4 zostają ustawione w znany nam z poprzedniego rozdziału tryb wyjścia (ang. OUTPUT).
W pętli głównej odczytujemy stan portu P0 za pomocą funkcji bibliotecznej digitalRead(0). Odczytany stan portu P0 (niski 0 lub wysoki 1) zapamiętujemy sobie w zmiennej v. Następnie stan ten zapisujemy do portów P1...P4. W efekcie na wyjściach P1...P4 pojawia się ten sam stan logiczny, jaki panuje na wejściu portu P0. I tutaj zaczynają się dziać dziwne rzeczy. Jeśli zbliżysz palec do płytki, to diody LED się zapalają, jeśli palec oddalisz, to gasną. Dlaczego tak jest? Współczesne mikrokontrolery budowane są na bazie tranzystorów polowych. Tranzystory polowe są sterowane napięciem i posiadają olbrzymie oporności wejściowe (idące w megaomy). Linia P0 zachowuje się tutaj jak antena i zbiera zakłócenia z otoczenia. Gdy zbliżasz palec, tworzysz takie zakłócenie i na linii P0 indukuje się napięcie, które trafia na wejście portu P0. A wtedy napięcie na wejściu P0 może wzrosnąć z uwagi na jego dużą oporność wejściową. Taki wzrost napięcia mikrokontroler odczyta jako stan logiczny 1 i diody LED zapalą się, ponieważ stan ten zostanie przekazany na wyjścia portów P1...P4. Gdy wciśniesz przycisk na płytce DS002, to zewrze on linię P0 do masy układu, a więc wymusi na niej stan niski 0. Diody LED zgasną. Gdy zwolnisz przycisk, diody LED znów się zapalą aż nie odsuniesz palca od płytki.
W rezultacie zbudowaliśmy czujnik zbliżeniowy palucha.
Specjalnie umieściłem tutaj ten program, ponieważ musisz takie zjawiska rozumieć, aby odpowiednio projektować swoje urządzenia elektroniczne. Zapamiętaj: linia wejścia nie powinna nigdy "wisieć" niepodłączona, ponieważ zbiera wtedy zakłócenia z otoczenia. Co zatem należy zrobić? Rozwiązanie jest bardzo proste i wbudowano je w każdy mikrokontroler.
Wystarczy linię wejścia podpiąć przez opornik do plusa zasilania:
Gdy przycisk jest rozwarty, to opornik wymusza na wejściu stan wysoki. Gdy przycisk zostanie zwarty przez naciśnięcie, to na wejściu pojawi się stan niski. Opornik powinien być tak dobrany, aby niwelował zakłócenia a jednocześnie nie obciążał zbytnio zasilania przy zwarciu go do masy poprzez przycisk. Oporność równa 10kΩ jest w sam raz. Opornik taki nazywamy opornikiem podciągającym (ang. pull-up resistor), ponieważ "podciąga" napięcie wejścia w górę, gdy przycisk jest rozwarty.
Ponieważ oporniki podciągające stosuje się bardzo często w praktyce, wszystkie mikrokontrolery pozwalają wewnętrznie dołączyć taki opornik do portu pracującego w trybie wejścia.
Użyte tu rozwiązanie pozwala w prosty sposób dołączać przyciski do portów wejścia mikrokontrolera.
Aby otrzymać wejście z opornikiem podciągającym, należy użyć wywołania pinMode(nr_portu, INPUT_PULLUP).
Poniższy program wykorzystuje ten tryb pracy wejścia. Naciśnięcie przycisku powoduje zwarcie wejścia do masy, czyli wymusza stan niski na wejściu portu P0. Ponieważ mikrokontroler kopiuje ten stan na pozostałe porty wyjścia P1...P4, wszystkie diody LED zgasną. Gdy zwolnisz przycisk, opornik podciągający wymusi stan wysoki na wejściu portu P0. Stan zostanie skopiowany na pozostałe porty i diody LED się zaświecą:
// Odczyt stanu przycisku 1 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia for(char i = 1; i <= 4; i++) pinMode(i,OUTPUT); } // Pętla główna programu //---------------------- void loop() { char v; v = digitalRead(0); // Czytamy stan portu P0 // Zapisujemy ten stan do portów P1...P4, które // sterują diodami LED. for(char i = 1; i <= 4; i++) digitalWrite(i,v); } |
Gdy uruchomisz ten program, wszystkie diody LED będą świecić. Zbliżanie palców do płytki nie powoduje żadnych zakłóceń. Zapamiętaj: odczyt przycisków należy wykonywać z opornikami podciągającymi.
Jeśli chcemy mieć zgaszone diody przy rozwartym przycisku i zaświecone przy zwartym, należy odwrócić odczytany stan przycisku na przeciwny. Uzyskasz to za pomocą operatora zaprzeczenia !.
// Odczyt stanu przycisku 2 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia for(char i = 1; i <= 4; i++) pinMode(i,OUTPUT); } // Pętla główna programu //---------------------- void loop() { char v; v = !digitalRead(0); // Czytamy stan portu P0, zaprzeczając go // Zapisujemy ten stan do portów P1...P4, które // sterują diodami LED. for(char i = 1; i <= 4; i++) digitalWrite(i,v); } |
Program mruga diodami LED. Jeśli przycisk jest zwolniony, to diody mrugają wolno. Gdy przycisk jest wciśnięty, diody mrugają szybko.
// Mrugacz 3 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { // Zmieniamy stan portów P1...P4 na przeciwny for(char i = 1; i <= 4; i++) digitalWrite(i,1^digitalRead(i)); // Opóźnienie uzależniamy od stanu przycisku if(digitalRead(0)) delay(200); // Przycisk rozwarty else delay(50); // Przycisk zwarty } |
Możesz się zastanawiać, dlaczego w tym programie używamy funkcji digitalRead() do odczytu portów P1...P4, skoro porty te są skonfigurowane jako wyjścia. Funkcja ta czyta stan, jaki panuje na linii portu. Jeśli port pracuje jako wyjście, to stan ten ustala mikrokontroler przez zapis do portu za pomocą funkcji digitalWrite(). Zatem w tym przypadku funkcja digitalRead() zwraca nam to, co w poprzednim wywołaniu funkcji loop() zostało zapisane do portu. Odczytany stan portu negujemy poprzez operację 1^digitalRead(...). Operator ^ jest operatorem tzw. różnicy symetrycznej, czyli funkcji logicznej o następujących własnościach:
a | b | a ^ b |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
Zwróć uwagę, że jeśli jeden z argumentów operatora ^ ma wartość 1, to wynik jest zaprzeczeniem logicznym drugiego argumentu. To właśnie wykorzystujemy w tym programie do mrugania diodami LED. Program odczytuje stan portu, neguje go za pomocą operatora ^ i wynik zapisuje z powrotem do portu. W efekcie diody LED cyklicznie zapalają się i gasną. Częstotliwość tego mrugania zależy od opóźnienia, które wstawimy pomiędzy zmianami stanu portów. Opóźnienie to zależy od stanu przycisku, który badamy instrukcją warunkową if.
Zamiast operacji 1^... możesz użyć operatora negacji !, efekt będzie taki sam:
// Mrugacz 3 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { // Zmieniamy stan portów P1...P4 na przeciwny for(char i = 1; i <= 4; i++) digitalWrite(i,!digitalRead(i)); // Opóźnienie uzależniamy od stanu przycisku if(digitalRead(0)) delay(200); // Przycisk rozwarty else delay(50); // Przycisk zwarty } |
Kolejnym problemem jest wykorzystanie przycisku do włączania/wyłączania. Działa to w ten sposób, iż pierwsze naciśnięcie przycisku włącza, a drugie naciśnięcie wyłącza.
// Włączanie/wyłączanie 1 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { // Czekamy na naciśnięcie przycisku while(digitalRead(PRZYCISK)); // Czekamy na zwolnienie przycisku while(!digitalRead(PRZYCISK)); // Włączamy/wyłączamy świecenie diod for(char i = 1; i <= 4; i++) digitalWrite(i,!digitalRead(i)); } |
Dwie pierwsze pętle while służą do obsługi przycisku. Obie odczytują stan portu przycisku, czyli P0. Pierwsza wykonuje się dotąd, aż użytkownik wciśnie przycisk, czyli stan portu zmieni się z 1 (przycisk niewciśnięty) na 0 (przycisk wciśnięty). Zadaniem drugiej petli jest odczekanie aż użytkownik przestanie naciskać przycisk, czyli stan portu zmieni się z 0 na 1. Gdy obie pętle zakończą się, wystąpi cykl: przyciśnięcie-zwolnienie przycisku. Wtedy przystępujemy do działania, czyli zmieniamy stan świecenia diod LED na przeciwny.
Gdy uruchomisz program, to po chwili zabawy płytką DS002 stwierdzisz, że coś jest nie tak. Czasem przycisk włącza/wyłącza diody, a czasem tego nie robi. Dlaczego?
Wyjaśnieniem jest zjawisko drgania styków (ang. bouncing). Przycisk jest urządzeniem mechanicznym. Wewnątrz zawiera parę styków, które w momencie naciśnięcia główki przycisku zwierają się ze sobą. Czasem styki odbijają się od siebie i wykonują serię krótkich drgań, zanim nastąpi trwałe złączenie/rozłączenie. Jest to zjawisko powszechnie znane. Wykres czasowy załączania/wyłączania przycisku wygląda następująco:
Wynika z niego, że tuż po włączeniu lub wyłączeniu przycisku jego styki mogą wykonywać przez około 5 ms drgania powodujące zwieranie i rozwieranie obwodu. Mikrokontrolery są bardzo szybkie. Gdy mikrokontroler wykryje spadek napięcia na linii portu wejściowego (zwarcie przyciskiem do masy), to wychodzi z pierwszej pętli while:
while(digitalRead(PRZYCISK)); |
i wchodzi w drugą pętlę while:
while(!digitalRead(PRZYCISK)); |
która wykonuje się dotąd, aż napięcie na porcie wróci do stanu wysokiego. Jeśli teraz styki drgają, to pętla odkryje wzrost napięcia i zakończy swoje działanie. Gdy to się stanie mikrokontroler zapali lub zgasi diody LED i wróci do pierwszej pętli while. Jeśli styki wciąż drgają, to pętla ta może się ponownie zakończyć i nastąpi przejście do drugiej pętli while. A ta napotkawszy wysokie napięcie na linii portu znów się zakończy i mikrokontroler ponownie zmieni stan diod LED. W efekcie jedno naciśnięcie przycisku może wywołać kilkakrotne, szybkie zaświecenie/zgaszenie diod LED, a zatem czasem zostaną one zaświecone, a czasem zgaszone. Nie jest to poprawne działanie programu, ponieważ powinien on być wykonywany wg sekwencji:
naciśnięcie przycisku → zwolnienie przycisku → zapalenie/zgaszenie diod LED |
Jak sobie z tym poradzić? Otóż problem wywołują niekontrolowane drgania styków przycisku. Najprostszym rozwiązaniem jest po prostu odczekanie tych 5 ms, aż drgania styków wygasną. 5 ms jest bardzo krótkim okresem czasu i użytkownik go nie zauważy.
Poprawiony program wygląda następująco:
// Włączanie/wyłączanie 2 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { // Czekamy na naciśnięcie przycisku while(digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Czekamy na zwolnienie przycisku while(!digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Włączamy/wyłączamy świecenie diod for(char i = 1; i <= 4; i++) digitalWrite(i,!digitalRead(i)); } |
Teraz program działa prawidłowo, jednak aby włączyć lub wyłączyć diody LED, musisz nacisnąć przycisk i zwolnić go. Dopiero wtedy diody LED zmieniają swój stan. Jak uzyskać zmianę stanu diod w momencie naciśnięcia przycisku, co jest bardziej intuicyjne?
Odpowiedź jest prosta: wystarczy przenieś drugą pętlę while na koniec lub na początek funkcji loop():
// Włączanie/wyłączanie 3 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { // Czekamy na zwolnienie przycisku while(!digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Czekamy na naciśnięcie przycisku while(digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Włączamy/wyłączamy świecenie diod for(char i = 1; i <= 4; i++) digitalWrite(i,!digitalRead(i)); } |
Dzięki temu wciśnięcie przycisku spowoduje przejście do zmiany stanu diod LED, a dopiero w następnej kolejności program poczeka na zwolnienie przycisku:
Jeśli druga pętla while znajdzie się na początku funkcji loop(), to działanie będzie identyczne, ponieważ funkcja loop() wykonywana jest cyklicznie w pętli.
Wykorzystajmy nabyte umiejętności do napisania programu, który przesuwa na diodach LED punkt świetlny po każdym naciśnięciu przycisku.
// Przesuwanie punktu świetlnego // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } // Diodę 1 zaświecamy digitalWrite(1,HIGH); } // Pętla główna programu //---------------------- void loop() { // Czekamy na zwolnienie przycisku while(!digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Czekamy na naciśnięcie przycisku while(digitalRead(PRZYCISK)); // Czekamy na wygaśnięcie drgań styków delay(5); // Przesuwamy punkt o 1 pozycję char LED4 = digitalRead(4); // Zapamiętujemy stan LED 4 for(char i = 4; i > 1 ; i--) digitalWrite(i,digitalRead(i - 1)); digitalWrite(1,LED4); } |
Działanie programu jest następujące:
Ustawiamy porty:
P0 jako wejście z opornikiem podciągającym
P1...P4
jako wyjścia sterujące diodami LED
Diody LED 2..4 gasimy. Diodę LED 1 zaświecamy:
W pętli głównej czekamy na wciśnięcie przycisku. Gdy wykryjemy wciśnięcie, przesuwamy punkt świetlny następująco:
Zapamiętujemy stan diody LED 4 w zmiennej pomocniczej LED4 (na rysunku stany diod oznaczyłem różnymi kolorami, aby pokazać, jak będą się przemieszczać):
Idąc od końca, kopiujemy stan diody i-1 do i:
Na koniec kopiujemy zapamiętany stan LED4 do 1:
Zwróć uwagę, że stany diod przed i po operacji są przesunięte o 1 pozycję, a pierwsza dioda ma stan diody ostatniej:
PRZED: | |
PO: |
Wykorzystajmy przesuwanie stanu diod w następnym programie, który po naciśnięciu przycisku generuje efekt strzału:
// Strzał 1 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Pętla główna programu //---------------------- void loop() { delay(20); digitalWrite(1,!digitalRead(PRZYCISK)); // Przesuwamy punkt o 1 pozycję for(char i = 4; i > 1 ; i--) digitalWrite(i,digitalRead(i - 1)); } |
W pętli głównej stany diod LED są cyklicznie przesuwane. Przed przesunięciem pierwsza dioda LED otrzymuje zaprzeczony stan przycisku. Jeśli przycisk jest zwolniony, to dioda będzie zgaszona. Jeśli przycisk jest wciśnięty, to dioda zostanie zaświecona. W następnych obiegach stan ten zostanie przeniesiony na kolejne diody LED.
Program ma pewną "wadę". Jeśli przytrzymasz przycisk, to wszystkie diody zostaną zaświecone. Zróbmy, tak aby przy naciśnięciu przycisku był oddawany "pojedynczy" strzał, a nie cała seria. W tym przypadku nie wystarczy kopiowanie stanu przycisku do portów wyjściowych. Należy zapamiętywać stan przycisku i reagować tylko w momencie, gdy się on zmienia. Do tego celu będziemy potrzebować zmiennej globalnej, która jest tworzona poza funkcjami i zachowuje swoją zawartość pomiędzy wywołaniami funkcji.
// Strzał 2 // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Stan przycisku, HIGH = nienaciśnięty char przycisk = HIGH; // Pętla główna programu //---------------------- void loop() { // Czytamy stan przycisku char p = digitalRead(PRZYCISK); // Sprawdzamy, czy różni się od stanu poprzedniego if(p != przycisk) { // Różni się, sprawdzamy, czy jest wciśnięty, // a jeśli tak, to zapalamy diodę 1 if(!p) digitalWrite(1,HIGH); // Zapamiętujemy nowy stan przycisku przycisk = p; } delay(25); // Przesuwamy punkt o 1 pozycję for(char i = 4; i > 1 ; i--) digitalWrite(i,digitalRead(i - 1)); // Gasimy diodę 1 digitalWrite(1,LOW); } |
W kolejnym programie wykorzystamy metodę wykrywania naciśnięcia przycisku w locie. Program przesuwa cyklicznie punkt świetlny. Gdy naciśniesz przycisk, to nastąpi zmiana kierunku przesuwania punktu.
// Przesuwanie w prawo/lewo // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } // Zaświecamy diodę 1 digitalWrite(1,HIGH); } // Stan przycisku, HIGH = nienaciśnięty char przycisk = HIGH; // Kierunek przesuwu char kierunek = 1; // Pętla główna programu //---------------------- void loop() { // Czytamy stan przycisku char p = digitalRead(PRZYCISK); // Sprawdzamy, czy różni się od stanu poprzedniego if(p != przycisk) { // Różni się, sprawdzamy, czy jest wciśnięty, // a jeśli tak, to zmieniamy kierunek przesuwu if(!p) kierunek ^= 1; przycisk = p; // Zapamiętujemy nowy stan przycisku } delay(75); // W zależności od kierunku przesuwamy odpowiednio punkt if(kierunek) { char LED4 = digitalRead(4); for(char i = 4; i > 1 ; i--) digitalWrite(i,digitalRead(i - 1)); digitalWrite(1,LED4); } else { char LED1 = digitalRead(1); for(char i = 1; i < 4 ; i++) digitalWrite(i,digitalRead(i + 1)); digitalWrite(4,LED1); } } |
Ostatni program jest symulacją detonatora ładunku wybuchowego (spokojnie, nic tutaj nie wybucha).
Działanie będzie następujące. Przycisk uruchamia odliczanie. Co 2 sekundy będzie się zaświecać kolejna dioda LED. Gdy zaświecą się wszystkie cztery diody i minie kolejne 2 sekundy, nastąpi "eksplozja" i detonator powróci do stanu nieaktywnego. Jeśli w trakcie odliczania naciśniesz ponownie przycisk, to odliczanie zostanie przerwane.
Sprawdzanie stanu przycisku jest tutaj wykonywane co 1/20 sekundy. Dzięki temu odliczanie jest przerywane prawie natychmiast i program nie gubi naciśnięć.
// Detonator // (C)2018 mgr Jerzy Wałaszek //--------------------------- // Port przycisku #define PRZYCISK 0 // Konfigurujemy mikrokontroler //----------------------------- void setup() { // Ustawiamy port P0 jako wejście z opornikiem podciągającym pinMode(0,INPUT_PULLUP); // Ustawiamy porty P1...P4 jako wyjścia i gasimy wszystkie diody for(char i = 1; i <= 4; i++) { pinMode(i,OUTPUT); digitalWrite(i,LOW); } } // Funkcja zapala diody od 1 do n, a gasi diody od n+1 do 4. // Czeka 1/20 sekundy. //---------------------------------------------------------- void zapalDiody(char n) { for(char i = 1; i <= 4; i++) digitalWrite(i,(i <= n)); delay(50); } // Stan przycisku char przycisk = HIGH; // Tryb pracy detonatora char zliczanie = 0; // Licznik detonatora char licznik = 0; // Licznik obiegów pętli char obieg = 0; // Pętla główna programu //---------------------- void loop() { // Czytamy stan przycisku char p = digitalRead(PRZYCISK); // Sprawdzamy, czy różni się od stanu poprzedniego if(p != przycisk) { // Różni się, sprawdzamy, czy jest wciśnięty, // a jeśli tak, to zmieniamy tryb pracy detonatora if(p == LOW) { zliczanie ^= 1; // Detonator włączony? if(zliczanie) { // Tak, inicjujemy licznik i numer obiegu licznik = 1; obieg = 0; } else licznik = 0; // Nie, zerujemy licznik } // Zapamiętujemy nowy stan przycisku przycisk = p; } // Wyświetlamy aktualny stan licznika zapalDiody(licznik); // Jeśli zliczanie, to uaktualniamy licznik po upływie 2 sekund: if(zliczanie) { if(obieg < 40) obieg++; // 40 obiegów = 2 sekundy else { obieg = 0; // Po 40 obiegach zerujemy licznik obiegów licznik++; // Zwiększamy licznik detonatora if(licznik > 4) // Jeśli zliczył ponad 4 { licznik = 0; // Zerujemy licznik for(char i = 0; i < 8; i++) // Eksplozja { zapalDiody(0); zapalDiody(4); } zliczanie = 0; // Detonator w stan nieaktywny } } } } |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.