Pomoc w obsłudze dwóch zdarzeń

Masz problem, z którym nie możesz sobie poradzić? Pisz śmiało!
ODPOWIEDZ
mateuszmp
Młodszy majsterkowicz
Posty: 3
Rejestracja: 10 gru 2014, 21:49

Pomoc w obsłudze dwóch zdarzeń

Post autor: mateuszmp » 21 sty 2015, 21:35

Witam. Mam prośbę do osób znających się na programowaniu Arduino. Chciałbym wykonać program do załączenia pewnej sekwencji diod. Chciałbym, abym miał możliwość włączania i wyłączania sekwencji jednym przyciskiem monostabilnym, jednak natrafiam na problem. W trakcie wykonywania pętli z sekwencją zapalającą diody, mikrokontroler nie reaguje na wciśnięty przycisk i nie przechodzi do pętli sprawdzania stanu przycisku, ponieważ w sekwencji zastosowałem funkcję delay, która jakoby zatrzymuje na jakiś czas działanie programu, jednak bez niej nie potrafię inaczej tego wykonać. Zależy mi na sterowaniu poprzez przycisk monostabilny, ponieważ nie robię tego, aby to złożyć, ale po to, aby doskonalić pisanie programów. Załączam kod i proszę o pomoc i wyrozumiałość dla początkującego.

Kod: Zaznacz cały

#include <Timers.h>
Timers timer(3);
#define ledred 12
#define ledblue 11
#define button 10
#define led 13
int time1 = 100;
int licznik;
void setup() {
pinMode(ledred, OUTPUT);
pinMode(ledblue, OUTPUT);
pinMode(led, OUTPUT);
pinMode(button, INPUT_PULLUP);
digitalWrite(ledred, LOW);
digitalWrite(ledblue, LOW);
digitalWrite(led, LOW);
timer.attach(0, 800, start);
timer.attach(1, 800, stp);
timer.attach(2, 800, spr);
}
void loop() {
timer.process();
}
void start() { //funkcja startu migania świateł
if(licznik%2==0) { //jeśli reszta z dzielenia licznika przez 2 jest równa 0
digitalWrite(led, HIGH);
digitalWrite(ledred, HIGH);
delay(time1);
digitalWrite(ledred, LOW);
delay(time1);
digitalWrite(ledred, HIGH);
delay(time1);
digitalWrite(ledred, LOW);
delay(time1);
digitalWrite(ledblue, HIGH);
delay(time1);
digitalWrite(ledblue, LOW);
delay(time1);
digitalWrite(ledblue, HIGH);
delay(time1);
digitalWrite(ledblue, LOW);
delay(time1);
}
}
void stp() { //funkcja stop; zgaszenie wszystkich diod
if(licznik%2!=0) { //jeśli wartość z dzielenia licznika przez 2 nie jest równa 0
digitalWrite(ledred, LOW);
digitalWrite(ledblue, LOW);
digitalWrite(led, LOW);
}
}
void spr() { //funkcja sprawdzająca stan przycisku
if(digitalRead(button)==LOW) {
while(digitalRead(button)==LOW); //sprawia, że pomimo trzymania przycisku wcisnietego zmiana nastapi tylko raz na pół sekundy
{
delay(500); //czekaj 500ms
}
licznik++; //zwiększ wartość licznika o 1
}
} 

Co miesiąc do wygrania nagrody o wartości ponad 1600 zł!


zgred125
Majsterkowicz
Posty: 88
Rejestracja: 23 gru 2013, 22:39

Re: Pomoc w obsłudze dwóch zdarzeń

Post autor: zgred125 » 21 sty 2015, 22:33

Skorzystaj z przerwania zewnętrznego albo zamiast używać funkcji delay skorzystaj z funkcji millis.
stiven
Złota rączka
Posty: 1644
Rejestracja: 13 maja 2014, 08:47
Lokalizacja: Zielona Góra

Re: Pomoc w obsłudze dwóch zdarzeń

Post autor: stiven » 21 sty 2015, 22:35

Kod: Zaznacz cały

long czas_poprzedni = 0;		//deklaracja przed pętlą setup


void spr() { //funkcja sprawdzająca stan przycisku
  if((digitalRead(button)==LOW) && (millis() - czas_poprzedni > 500)) 
  {
    czas_poprzedni = millis();
    licznik++; //zwiększ wartość licznika o 1
  }
} 
Funkcja millis() zwraca czas w milisekundach od uruchomienia programu. Zmienna licznik zostanie zwiększona o 1 kiedy jest wciśnięty przycisk i jednocześnie minie 500 ms od poprzedniego wciśnięcia.


Napisałeś coś takiego:

Kod: Zaznacz cały

while(digitalRead(button)==LOW); //sprawia, że pomimo trzymania przycisku wcisnietego zmiana nastapi tylko raz na pół sekundy
{
delay(500); //czekaj 500ms
}

Pierwsza sprawa, jak dasz średnik na końcu while:

Kod: Zaznacz cały

while(digitalRead(button)==LOW);
to to co jest dalej w klamerkach zostanie wykonane dopiero jak skończy się while a nie "w ramach" while. Tak jak po ifie przed klamerkami nie stawia się średnika, tak samo po while. Ale czy byś napisał:

Kod: Zaznacz cały

while(digitalRead(button)==LOW);
{
delay(500); //czekaj 500ms
}
czy to:

Kod: Zaznacz cały

while(digitalRead(button)==LOW)
{
delay(500); //czekaj 500ms
}
to komentarz przy while:

Kod: Zaznacz cały

//sprawia, że pomimo trzymania przycisku wcisnietego zmiana nastapi tylko raz na pół sekundy
jest nieprawdziwy.

Warunek w while jest prawdziwy zawsze i dopóki wciśnięty jest przycisk, czyli jeśli wciśniesz przycisk i będziesz go na przykład trzymał 10 minut, to zmiana nastąpi tylko jeden raz, dopiero po puszczeniu przycisku. Dopóki przycisk będzie wciśnięty, to program będzie zatrzymany na tym while'u. Średnik blokuje wykonanie tego co jest w klamerkach, czyli dopiero po puszczeniu przycisku zostanie wykonane to co jest w klamerkach no i pozostały kod. Bez średnika while będzie powodował wykonywanie tego co jest w klamerkach dopóki będzie wciśnięty przycisk. Jak minie 500 ms, a przycisk będzie dalej wciśnięty, to delay() zostanie wykonany ponownie itd.
Przy korzystaniu z timerów i przerwań takiego blokowania przez delay i while nie można robić, bo to może spowodować "wysypanie" programu.
mateuszmp
Młodszy majsterkowicz
Posty: 3
Rejestracja: 10 gru 2014, 21:49

Re: Pomoc w obsłudze dwóch zdarzeń

Post autor: mateuszmp » 22 sty 2015, 01:00

No tak, z tą funkcją while i tym średnikiem to moje niedopatrzenie. Widocznie jak kopiowałem kod, to musiałem przez pomyłkę coś jeszcze dopisać, ale dziękuję bardzo za szybką i wyczerpującą odpowiedź i znalezienie błędu. Doceniam to i postaram się bardziej zwracać uwagę na te szczegóły. Problem jednak pojawia mi się w pętli start, gdzie jest ona wykonywana na okrągło, a jej okres wynosi 800ms. Tak więc funkcja spr nie może się uruchomić, dopóki pętla start nie wykona się cała. Mówiąc najprościej, stan przycisku może zostać zczytany dopiero, gdy wykona się ostatnia linijka pętli start. Jeśli w ciągu tego czasu "nie trafię" w odpowiedni moment, to pętla wykonuje się od początku. Pytanie moje brzmi, jak mogę ustalić czas stanu wysokiego lub niskiego na diodach nie używając funkcji delay, aby nie zatrzymywać pracy mikrokontrolera. Rozumiem, że muszę to wykonać za pomocą funkcji millis(), lecz nie wiem dokładnie jak.
ODPOWIEDZ

Strony partnerskie: