czujka wibracji – elektroniczna kostka do gry

Kolejny raz podstawy – czyli rozmawialiśmy oo doborze odpowiedniego opornika dla układu zasilanie-LED. Mierzyliśmy napięcia (czyli spadki napięć) oraz prądy. Każdy musi przez to prześć, dlatego zachęcam do zabawy w wirtualnym Arduino (jest tam multimetr, płytka stykowa i różne LEDy – proszę nie zlekceważyć tego ćwiczenia!).

Czujka drgań

Bardzo prosta, ale ile zabawy 😉 Prosta, bo ma trzy pin-y: VCC i GDN (czyli zasilanie, z przedziału 3.3V-5V) oraz pin Dout – sygnał cyfrowy informujący o drganiu. Cena to kilka złotych, zależnie od miejsca kupna.

Do czego? no wiele zastosowań, ale… takie śmieszniejsze (ale czy oby na pewno?) to alarm otwartej szuflady. Czyli: jeśli chcemy mieć pewność, że nasz młodszy brat nie będzie grzebać w naszej szufladzie, to … montujemy taki układ do wnętrza szuflady i jeśli jednak będzie próba jej otwarcia – to odezwie się alarm (lub taki incydent zostanie zapisany w pamięci). Potem można przejrzeć „dziennik zdarzeń” i przekonać się, czy faktycznie braciszek nie myszkował w naszej szufladzie 😉

To bardzo czuły czujnik

Właściwie to wystarczy stuknąć w stół i te minimalne drgania wprawią w działanie nasz czujnik. Pirwszy, prosty programik:

byte czujka=7;

void setup(){
  pinMode(czujka, INPUT);
  Serial.begin(9600);
}

void loop(){
  if (digitalRead(czujka)==0)
    Serial.println("czujka! drgania!");
}

Nie pomyslilem się – rejestrujemy drgania gdy odczytujemy napięcie LOW (czyli zero). Gdy brak drgań – odczytujemy stan HIGH (1). A może tak rozbudować program, aby zliczał liczbę drgań?

byte czujka=7;
unsigned int licz=0;

void setup(){
  pinMode(czujka, INPUT);
  Serial.begin(9600);
  licz=0;
}

void loop(){
  if (digitalRead(czujka)==0){
    licz++;
    Serial.print("czujka! drgania!  ");
    Serial.println(licz);
  }
}

Proszę uruchomić powyższy programik i zaobserwować, jak szybko nasz licznik (zmienna licz) rośnie. Przy okazji przekoanliśmy się na własne oczy, co się dzieje gdy przepełnimy licznik (testowaliśmy to na zmiennej typu byte, która zlicza liczby od 0..255 – łatwo taki licznik przepełnić!).

Kostka do gry – liczby losowe, nie pseudo-losowe!

Pokazałem państwu swój kolejny układ – elektroniczną kostkę do gry. Drgania powodują tworzenie liczb losowych (prawdziwie losowych, nie pserudo-losowych). Jak? wymyśliłem sobie tak: zliczam liczbę drgań, a gdy drgania ustaną – wynik wyświetlam z operacją modulo 6 + 1 (modulo 6 – to liczby z zakresu 0..5 więc dodaję jeszcze 1 aby mieć sześcienną kostkę do gry). Całość prezentuję na 7-segmentowym wyświetlaczu (no i dodatkowo „dla bajeru” uruchamiam melodyjkę).

Na powyższej fotce widzimy Arduino UNO (w wersji Ferrari – czerwoniutkie) z nakładką – proto-shieldem (aby nie trzeba było się bawić w oddzielną płytkę stykową). Roboczo wszystko połączone jest przewodami ze skrętki, ale całość nieźle trzyma się kupy 😉

Praca domowa

Proponuję pobawić się w wirtualnym Arduino i poćwiczyć wyświetlanie liczba na 7- segmentowym wyświetlaczu – to może się jeszcze wielokrotnie przydać!Nie zapomnijcie zapisać wyników Waszej pracy by potem pochwalić się nimi!

(c) KG 2018

RGB LED – PWM (podstawy)

Niby podstawy – ale jakie kolorowe 😉 No i bardzo przyszłościowe – niebawem się okaże, jak barwne mogą być nasze elektroniczne gry zręcznościowe!

Sprawa jest prosta – w tej diodzie RGB są właściwie TRZY diody – czerwona, niebieska i zielona. Dzięki mieszaniu trzech kolorów otrzymujemy każdy inny, dowolny kolor – w tym także biały. Właśnie biały to bardzo ważny kolor – potrzbny nam do codziennego życia – dlatego też właśnie w 2014 r. uchonorowano Japończyków nagrodą Nobla za zrobienie niebieskiego lasera.

RGB LEDy występują z dwoma typami obudowy – matową (polecam) oraz przezroczystą. Ta pierwsza daje światło bardziej rozproszone, trudno nawet zobaczyć te trzy oddzielne LEDy.

Wspólna anoda, wspólna katoda.

RGB LED ma cztery „nóżki” (wyprowadzenia): skoro sa tam trzy LEDy (czerwony, zielony i niebieski) to niepotrzebną rozrzutnością było by mocowanie sześciu nóżek – po dwie dla każdej diody. Oczywiście dioda ma mieć możliwość oddzielnego sterowania (włącznaia), dlatego te trzy nóżki muszą być – natomiast resztę (też 3) można ze sobą uwspólnić – czyli połączyć. Tym oto sposobem zredukowaliśmy nadmiar wyprowadzeń i mamy dwie odmiany RGB LEDa: wspólna katoda (czyli wspólny minus), oraz wspólna anoda (czyli wspólny plus). Wiele mówiący rysunek:

Podłączenie – pamiętaj o oporniku dla KAŻDEGO LEDa!

Niby oczywiste, ale warto o tym przypominać… Wybieramy rezystory 220 Ohma (bo takie mamy pod ręką) – co nie jest idealne, gdyż każdy LED ma inne napięcie przewodzenia… My to świadomie ignorujemy i dla prostoty (czytaj: wygodny) używamy tych samych oporników. Ale coś za coś – nie będziemy mieć tej samej jasności każdego LEDa (płynie przez nie inny prąd!) a więc biały nie będzie taki biały…

(Może znajdę czas i dopiszę tu kiedyś konkretne wartości oporników dla każdego LEDa)

Pierwszy program

Proponuję zdefiniować trzy zmienne (byte, int – jakkolwiek, oczywiście #define będzie też OK) dla każdej nóżki diody RGB (ja swoje podłączyłem do pinów 11,10 i 9). Dzięki temu będziemy wiedzieli, co właściwie robimy.

byte ledR=11;
byte ledG=10;
byte ledB=9;

void setup(){
  pinMode(ledR, OUTPUT);
  pinMode(ledG OUTPUT);
  pinMode(ledB, OUTPUT);
}

void loop(){
  digitalWrite(ledR, LOW); //włączamy czerowny kolor
  delay(1000);
  digitalWrite(ledR, HIGH); //wyłączamy czerowny kolor
  delay(1000);
  digitalWrite(ledG, LOW); //włączamy zielony kolor
  delay(1000);
  digitalWrite(ledR, HIGH); //wyłączamy zielony kolor
  delay(1000);
  digitalWrite(leB, LOW); //włączamy niebieski kolor
  delay(1000);
  digitalWrite(ledB, HIGH); //wyłączamy neiebieski kolor
  delay(1000);

  //a teraz mieszamy kolory
  digitalWrite(ledB, LOW); //włączamy niebieski kolor
  digitalWrite(ledR, LOW); //włączamy niebieski kolor... mamy FIOLET!
  delay(1000);
  digitalWrite(ledB, HIGH); 
  digitalWrite(ledR, HIGH); 
  delay(1000);
}

Nie pomyslilem się – włączamy LEDy wyłączając napięcie – komendy digitalWrite(ledX, LOW) – bo program dotyczy RGB LEDa ze wspólną anaodą. Napięcie na wspólnej nóżce wynosi 5V dlatego muszę podać napięcie mniejsze (LOW) na drógą nóżkę, aby prąd płynął (nie płynie, jeśli nie ma różnicy napięć! jak woda, która się nie przelewa gdy tern jest płaski).

Mieszanie kolorów ułatwia poniższa grafika:

Warto trochę pobawić się w rozbudowę programu i uzyskać ciekawe kolorki… to na prawdę fajne!

Drugi program – mieszanie z „czułością” 😉

Pamiętamy działanie cyfrowych pinów PWM? Są one oznaczone tyldą (~, „falką”) i w przypadku LED-a umożliwiają płynną zmienę jasności świecenia. Ja od razu do podłączenia wybrałem właśnie piny PWM więc mogę przystąpić do zabawy w zmienę jasności

byte ledR=11;
byte ledG=10;
byte ledB=9;

void setup(){
  pinMode(ledR, OUTPUT);
  pinMode(ledG OUTPUT);
  pinMode(ledB, OUTPUT);
}

void loop(){
  for (i=255; i>0; i--){
     analogWrite(ledR, i); //powoli włączamy czerowny kolor
     delay(10);
  }
  for (i=255; i>0; i--){ 
     analogWrite(ledB, i); //powoli włączamy niebieski kolor 
     delay(10); 
  }   
  delay(1000);
}

Fajna i prosta sprawa, nieprawdaż? Ci, którzy nie pamiętają o co chodzi – zachęcam do uruchomienia Przykłady -> 01 Basics -> Fade z Arduino IDE.

Prąd pobierany z Arduino

Każdy kolor to około 20mA, więc ustawiając światło białe mamy około 60mA prądu. Oznacza to, że nasze Arduino UNO nie pociągnie za dużo takich LEDów (bez kombinowania, ale o tym później).

1 RGB LED = 3 piny PWM !!!

Oczywiście, jeśli chcemy mieć możliwość kontrolowania jansności. To dużo – Arduino UNO ma tylko (aż?) 6 takich pinów. Co więc zrobić, aby świecić 5 RGB LEDami? albo 10? Nie da się? Da się, da. Na kolejnych zajęciach właśnie się tym zajmiemy. Zapraszam! 

Praca domowa

Proponuję poćwiczyć programowanie struktularne – stworzyć funkcję

void rgb(byte red, byte green, byte blue),

która ustawi trzy LEDy na zadane wartości – niech dodatkowo podawane wartości będą z przedziału 0..100, a więc należy dokonać odpowieniej konwersji na liczby z przedziału 0..255. Jeśli tak zrobomy, to wówczas rgb(30,0,0) oznacza lekki kolor czerwony, rgb(0,100,0) to jansy kolor zielony a rgb(77,0,77) jasno-fioletowy. Proszę pobawić się w wirtualnym Arduino!

(c) KG 2018

Prototyp – gra zręcznościowa + (ponownie) podstawy

Pam Maksymilian rozbudował program o karanie za zbyt wczesne wciśnięcie przycisku – gratulacje! Wgrał owoce swojej pracy z wirtualnego Arduino do naszego prototypu i… działa! 

Mamy też nowych zainteresowanych Fi-BOTem- z Wydziału Mat-Inf – dlatego przy tej okazji wróciliśmy do podstaw (pinMode, digitalWrite). 

Za tydzień (10 kwietnia) będą ponownie podstawy – piny PWM – ale… z diodami RGB, oraz (popularnymi) listwami RBG. Wszystko to ma rozbudzić w nas twórczość nowego propotypu gry zręcznościowej. Zapraszam!

(c) KG 2018

Projekt — wirtualny, choć całkiem realny ;-)

Całe zajęcia poświęciliśmy wirtualnemu Arduino – aby każdy z nas miał swoją kopię układu nad którym pracujemy oraz… aby popracować samodzielnie w domu i zabłysnąć na kolejnych zajęciach 😉

Niestety – okazało się, że tinkercad.com nie oferuje sterownika HD44780 do obsługi popularnego LCD16x2 – musieliśmy wykorzystać komunikację UART (obiekt Serial). Troszkę szkoda…

W realu wygląda to tak:

Prawie ostateczna wersja oprogramowania (z kilkoma udziwnieniami – potencjometrami do konfigurowania trudności (szybkości) losowych zdarzeń) ale bez liczenia RUND i licznika czasu do końca gry:

byte btns[6]={2,3,4,5,6,7};
byte leds[5]={12,11,10,9,8};
byte i;
int czas_staly, czas_los;

void setup()
{
  Serial.begin(9600);
  for (i=0;i<6; i++)
    pinMode(btns[i], INPUT_PULLUP);
  for (i=0;i<5; i++)
    pinMode(leds[i], OUTPUT);
  Serial.println(analogRead(A5));
  srand(analogRead(A5));
  
  czas_staly=2*analogRead(A0);
  czas_los=2*analogRead(A1);
  Serial.print("KONFIG:");
  Serial.print("czas stały=");
  Serial.println(czas_staly);
  Serial.print("czas los=");
  Serial.println(czas_los);
  delay(1000);
}

byte los;
unsigned long int t1,t2;
void loop()
{
  delay(czas_staly+rand()%czas_los);
  los=rand()%5;
  Serial.print("los=");
  Serial.println(los);

  digitalWrite(leds[los], HIGH);
  
  t1=millis();
  while(digitalRead(btns[los])==HIGH);//nic nie rób, czekaj na klik!
  t2=millis();
  digitalWrite(leds[los], LOW);
  
  Serial.print("refleks=");
  Serial.println(t2-t1);
  delay(2000);
  czas_staly=2*analogRead(A0);
  czas_los=2*analogRead(A1);
}

Warte podkreślenia jest użycie tablic – to zdecydowanie ułatwiło losowanie LED-a i sprawdzenie, czy odpowiedni przycisk został wciśnięty czy nie. 

Do zrobienia:

  • rozbudowa softu o monitorowanie czasu reakcji – jeśli przekroczymy pozostały czas, to gra powinna się automatycznie zakończyć (i wyświetlić jakieś podsumowanie, a potem – rozpocząć się od początku)
  • rozbudowa softu o zabezpieczenie przez „strategią małpy” – klikanie wszystkich przycisków, aż któryś się trafi i będzie bardzo krótki czas reakcji. To już troszkę trudniejsze zadanie
  • niby kto powiedział, że ma to być tylko gra refleks? warto pomyśleć także o grze memory – i zaprogramować sekwencje błysków (przygotowane wcześniej lub może losowo?), które należy powtarzać i zdobywać punkty. Można w setupie() zadać pytanie o wybór gry: reflex czy memory (wybór odczytujemy klikając jeden albo drugi przycisk) a wówczas loop() będzie uruchamiał odpowiedni kod…

(c) KG 2018

P.S. Radek (pracowity gimnazjalisto) – skontaktuj się ze mną emailem, czekam! KG

Dzień chłopaka… pomysły…

Chwila „dłubaniny” w ten wyjątkowy dzień 😉 W końcu każdy ma w sobie odrobinę dziecka, a co dopiero faceci ;-D Mam nadzieję, że wiecie, do czego to będzie służyło?

Teraz „tylko” 1) podłączyć, 2) oprogramować i… można rozpoczynać seryjną produkcję, która z pewnością okaże się światowym hit-em 😀

Do zobaczenia 20-tego marca (przypominam: 13-tego nie ma mnie w Bstoku, Fi-BOT odwołany).

(c) KG 2018

Ekranik LCD 16×2 oraz komunikacja I2C

Kontynuujemy projekt zabawki mierzącej refleks (także pamięć – „memory”). Potrzebujemy sposobu komunikacji z użytkownikiem (innego niż podłączony komputer PC do Arduino) – wybór padł na ekranik LCD 16×2.

LCD 16×2

Układ ten to szesnaście znaków w dwóch wierszach – stąd nazwa 16×2. Są także inne, obejrzyjcie dla przykładu magazyny botland.com.pl

Schemat podłączenia ładnie opisany jest na oficjalnych stronach Arduino – zapraszam do lektury. Nasze układy po złożeniu wyglądały tak:

Program polega na użyciu wbudowanej bibliotyki LiquidCrystal.h — poniżej program:

//LCD16x2 sterowany przez Arduino

#include <LiquidCrystalC.h> // dolaczenie pobranej biblioteki dla LCD

LiquidCrystal lcd(, 2, 11, 12, 4, 5, 6, 7);

void setup(){
  lcd.begin(16,2);   // Inicjalizacja LCD 2x16
  
  lcd.setCursor(0,0); // Ustawienie kursora w pozycji 0,0 (pierwszy wiersz, pierwsza kolumna)
  lcd.print("pomidor!");
  delay(500);
  lcd.setCursor(0,1); //Ustawienie kursora w pozycji 0,0 (drugi wiersz, pierwsza kolumna)
  lcd.print("LCD 16x2");
}
void loop() {
}

Warte podkreślenia jest tutaj fakt wykorzystania aż 6-ciu cyfrowych pinów do obsługi tego wyświetlacza. To dużo! Nie ma sprawy, gdy tylko „bawimy” się modułem ekraniku, ale gdy już coś budujemy, podłączamy LED-y czy przyciski – to wówczas spotykamy się z deficytem pinów w Arduino UNO. Ale są lepsze sposoby na podłączenie takiego wyświetlacza.

Komunikacja I2C (IIC, TWI)

To bardzo popularny interface komunikacyjny, obsługujący za pomocą tylko 2 linii aż 127 urządzeń! tymi pinami są SDA (w Arduino pin A4) oraz SDC (w Arduino pin A5). Oznacza to, że gdy podłączamy coś na I2C to łączamy to coś dwoma przewodami z Arduino, podłączając do wejść A4 i A5 – jednocześnie „tracimy” te piny (A4 i A5) – nie możemy z nich korzystać. Trudno – coś za coś. Zresztą, to nic nowego – podobnie jest z komunikacją UART – Serial.begin(xxx) – „zabiera” nam cyfrowe piny #o (TX) i #1 (RX). Przy czym UART to tylko komunikacja z jednym urządzeniem – a tutaj 2 piny i możliwość obsługi do 127 urządzeń!

Moduł hd44780 (i2c)

Jako przykład komunikacji I2C użyliśmy wyświetlacza LCD 16×2 z dodatkowym sterownikiem hd44780. Taki sterownik jest tani a bardzo użyteczny. 

Całe podłączenie polega na połączeniu VCC i GND ze steronika do VCC i GND z Arduino, oraz pinów SDA, SDC ze sternika – do SDA i SDC w Arduino. Przy okazji dowiedzieliśmy się, że piny A4 i A5 w Arduino mają swoje „klony” w szeregu pinów cyfrowych, powyżej #13, GDN, ARFE.

Musimy użyć nowej biblioteki do obsługi tego modułu – ja zdecydowałem się na LiquidCrystal_I2C.h autorstwa Franka de Brabandera. Nie jest standardowo zainstalowana więc trzeba ją samodzielnie doinstalować. Przykładowy program:

//LCD16x2 sterowany przez I2C Arduino

include <Wire.h>   // standardowa biblioteka Arduino
#include <LiquidCrystal_I2C.h> // dolaczenie pobranej biblioteki I2C dla LCD

LiquidCrystal_I2C lcd(0x27, 16, 2);
//LiquidCrystal_I2C lcd(0x3f, 16, 2);


void setup(){
  lcd.init();
  lcd.begin(16,2);   // Inicjalizacja LCD 2x16
  
  lcd.backlight(); // zalaczenie podwietlenia 
  lcd.setCursor(0,0); // Ustawienie kursora w pozycji 0,0 (pierwszy wiersz, pierwsza kolumna)
  lcd.print("pomidor!");
  delay(500);
  lcd.setCursor(0,1); //Ustawienie kursora w pozycji 0,0 (drugi wiersz, pierwsza kolumna)
  lcd.print("LCD 16x2 I2C -- hd44780");
}
void loop() {
}

i2cScanner

To bardzo użyteczny program (aż mnie dziw bierze, że nie jest standardowo dodany do Arduino IDE!) więc trzeba go ręcznie zgrać z internetu i uruchomić. Dzięki niemu poznajemy adres swojego urządzenia – bo skoro magistrala i2c obsługuje aż do 127 urządzeń, to jak je rozpoznaje? które urządzenie jest które? a jeśli chcemy mieć 2, 3 lub 4 wyświetlacze LCD w jednym projekcie? Właśnie po to są adresy!

W naszej pracowni występują dwa rodzaje urządzeń – o adresach 0x27 oraz o 0x3f. Koniecznie sprawdź u siebie! W naszym przykładowym kodzie adres zapisany jest w linii 6 (kolejna linia przygotowuje na inny adresik).

Pomiar prądu

Warto zdawać sobie sprawę z użycia prądu – jak widać z poniższych zdjęć wykonaliśmy pomiar i odnotowaliśmy różnicę w poborze prądu w zależności od trybu działania ekraniku LCD – bez podświetlenia (około 6 mA) oraz z podświetleniem (około 26 mA).

A tutaj pomiar prądu z włączonym podświetleniem:

Projektując swój układ warto brać pod uwagę „prądożerność” każdego urządzenia. Ale to na przyszłość. My przećwiczyliśmy mierzenie prądu 😉

(c) KG 2018

Uwaga: koło Fi-BOT w nowych godzinach!

Zmieniam godziny naszych cotygodniowych spotkań – od najbliższych zajęć (wtorek, 6 marzec) widzimy się w godzinach 14:15-15:45 (plus/minus ewentualne przedłużenia do 16-tej). Jak zawsze zajęcia we wtorki w sali 1064. Do zobaczenia!

KG

Przycisk + dioda + random = REFLEKS!

Na zajęciach wykorzystaliśmy proste elementy do zbudowania prototypu maszyny badającej nasz refleks. Ale od początku.

Moduł z przyciskiem

Moduł posiada trzy piny – GND oraz Vcc to zalsilanie, S to stygnał wysyłany przez płytkę (na innych płytkach często oznaczony OUT). My używamy modułów firmy RobotDyn (o nazwie Button Switch module) i trzeba przyznać im dobrą jakość wykonania. Na dodatek układy te mają wbudowanego LED-a informującego o wciśnięciu przycisku.

Najpierw sprawdzamy, czy po wciśnięciu przycisku Arduino „zobaczy” jedynkę (stan HIGH) czy „zero” (stan LOW). Prosty programik poniżej:

#define gdzie 7
void setup(){
  pinMode(gdzie, INPUT);
  Serial.begin(9600);
}
void loop(){
   Serial.println(digitalRead(gdzie));
   delay(100);
}

Liczby losowe – rand()

Bibliotyki Arduino wyposażone są w funkcje pseudo losowe – czyli takie, które generują liczby „udające” prawdziwe liczby losowe. Mowa tu o funkcji rand() – aby to sprawdzić piszemy poniższy kod:

void setup(){
  Serial.begin(9600);
}
void loop(){
   Serial.print("czas= ");
   Serial.print(millis());
   Serial.print(" los=");
   Serial.printtln(rand());
   delay(100);
}

Widzimy więc duuuuuże (i losowe!) liczby całkowite, które wyświetlają się co 100ms. Aby z takich liczb zbudować coś konkretnego, np. typowy rzut kostki do gry – trzeba to lekko zmodyfikować przez użycie funkcji reszta z dzielenia całkowitego (tzw. modulo, symbol % w języku C/C++):

void setup(){
  Serial.begin(9600);
}
void loop(){
   Serial.print("czas= ");
   Serial.print(millis());
   Serial.print(" kostka=");
   Serial.printtln(1 + rand()%6);
   delay(100);
}

Jak to działa? Reszta z dzielenia całkowitego przez 6 zwraca liczby z przedziału 0..5, ale my dodajemy jeszcze jedynkę – otrzymujemy liczby 1…6 – czyli naszą kostkę do gry. W ten właśnie sposób możemy modyfikować wynik funkcji rand() i dopasowywać ją do naszych potrzeb.

Zapalenie LED-a co losowy czas

Podłączyliśmy niebieskiego LED-a bezpośrednio do pinu 13 Arduino i GND – bez dodatkowego, wymaganego opornika. Nie jest to poprawne połączenie (brak opornika = uszkodzenie LED-a), ALE niebieskie LEDy mają (wysokie) napięcie przewodzenia, około 3V. Arduino zasili je jednak 5V – co jest za dużo – i uszkadzamy naszego LED-a, ale go nie zniszczymy (celowo wybrałem niebieski LED, a nie inny – inne LEDy pracuą na napięciu ~2V, więc 5V by je zniszczyło). Zależy mi tutaj na prostocie budowy układu więc darowałem sobie niezbędny opornik (no i nie chiałem korzystać z wbudowanego LEDa #13 – bo jest mały i niewyraźny).

Chwilowo odłożyliśmy moduł z przyciskiem i zaprogramowaliśmy włączenei LED-a po losowym czasie od 5s, do 15s:

#define LED 13
void setup(){
  pinMode(LED, OUTPUT);
}
int i;
void loop(){
   //odczekanie 5..15 sekund
   delay(5000+ rand()%10000);
   //wlaczenie LED-a
   digitalWrite(LED, HIGH);
   delay(1000);
   digitalWrite(LED, LOW);
   //miganie - znak, ze za chwile powtarzamy zabawe
   for (i=0; i<4; i++){
       digitalWrite(LED, HIGH); 
       delay(200); 
       digitalWrite(LED, LOW);      
       delay(200);
   }//miganie
}

Warto pobawić się z tym programem, uzupełniając go o dodatkowe informacje wyświetlane przez monitor portu szeregowego – informujące, że trwa losowe czekanie, a potem, że włączono LEDa i na koniec – że zabawa od początku się zaczyna.

Program „badamy refleks”

Wracamy do przycisku – rozbudowujemy poprzedni program o odczytanie momentu wciśnięcia przycisku. Użytkownik ma to zrobić w momencie zapalenia się niebieskiego LEDa — tylko, że nie wiadomo, kiedy to dokładnie nastąpi (losowy czas z poprzedniego programu). Na koniec wyświetlimy czas jego reakcji – jego refleksu 😉

#define LED 13
#define gdzie 7
void setup(){
  pinMode(gdzie, INPUT);   
  pinMode(LED, OUTPUT);
  Serial.begin(9600);
}
int i;
unsigned long int t1,t2;
void loop(){
   Serial.println("START!");
   //odczekanie 5..15 sekund
   delay(5000+ rand()%10000);
   t1=millis();
   //wlaczenie LED-a
   digitalWrite(LED, HIGH);
   while (digitalRead(gdzie)== HIGH);
   t2=millis();
   digitalWrite(LED, LOW);
   Serial.print("Rekacja (refleks)=");
   Serial.print(t2-t1);
   Serial.println(" ms");
   delay(500);
   //miganie - znak, ze za chwile powtarzamy zabawe
   for (i=0; i<4; i++){
       digitalWrite(LED, HIGH); 
       delay(200); 
       digitalWrite(LED, LOW);      
       delay(200);
   }//miganie
}

Kluczowa jest linia #17 – to w niej następuje zatrzymanie działania programu i oczekiwanie na rekację użytkownika. Zrealizowałem to za pomocą pętli podczytującej przycisk – w moim module naciśnięcie przycisku powoduje odczyt stanu LOW, natomiast stan HIGH oznacza brak wciśnięcia. Jak widać ta pętla NIC nie robi. Właśnie o to mi tu chodziło – pętla nic nie robi, więc ponownie wracamy do sprawdzenia warunku pętli while – bez straty czasu. I tak w kółko, aż w końcu naciśnięty zostanie przycisk. 

A jak mierzę czas? Za pomocą funkcji millis() – która zwraca czas (w milisekundach) od uruchomienia Arduino. Robię to dwukrotnie – przed odczytaniem przycisku zapisuję do zmiennej t1, a po naciśnięciu przycisku – do zmiennej t2. Różnica tych czasów jest właśnie Twoim czesem reakcji – Twoim refleksem.

Pomysły

Program należy rozbudować – o dwa przyciski, dwa LEDy. To wzbogaci zabawę, bo losowo zapali się albo jeden LED, albo drugi. Warto wybrać dwa kolory LED-ów i dwa kolory przycisków. To będzie dodatkowe utrudnienie dla użytkownika – ma on bowiem wcisnąć odpowiedni przycisk (np. LED żółty – to i przycisk żółty, a nie niebieski. Niebieski to dyskwalifikacja! I na odwrót).

Inna modyfikacja polega na wychwyceniu falstartu – zapobiegnięciu sytuacji, że użytkownik bezmyślnie „klika” przyciskiem w nadziei, że gdy LED się zaświeci – on właśnie wcisnął przycisk i otrzymał bardzo krótki czas reakcji. Trzeba tak zrobić, aby wciśnięcie przycisku PRZED zaświeceniem kończyło zabawę. Podpowiedź: zamiast funkcji delay() w linii #13 trzeba sprytnie wykorzystać pętlę while…

(c) KG 2018