Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

Obsługa przycisków w stoperze... POMOCY......

tworekjuve
-
-
Posty: 4
Rejestracja: 29 sty 2009, o 17:20
Lokalizacja: Krakow

Obsługa przycisków w stoperze... POMOCY......

Postautor: tworekjuve » 29 sty 2009, o 17:26

Witam.

Mam na zajęcia zrealizować program stopera w programie AVR Studio... I mam problem z obsłużeniem 2 przycisków które nim sterują...

Pierwszy przycisk SW_1 ma resetować stoper
Drugi przycisk SW_2 ma go zatrzymywać (po pierwszym naciśnięciu) i startować dalej (po drugim naciśnięciu) i tak w kółko...

Napisałem obsługę do przycisku SW_1 (w sposób pewnie toporny niektórzy uznają - ale działa )

Na natomiast nie potrafię zapisać obsługi drugiego przycisku SW_2

Zrobiłem w sumie zatrzymywanie czasu ale chyba nie tak to powinno wyglądać...




MÓGŁBY MI KTOŚ POMÓC BO SAM NIE DAM RADY ....


Oto kod programu głównego :

Kod: Zaznacz cały

#include <avr\io.h> // dostęp do rejestrów #include <inttypes.h> // definicje typów uint8... #include <avr\signal.h> // definicje SIGNAL, INTERRUPT #include <avr\interrupt.h> // funkcje sei(), cli() #include "makra.h" #include "harddef.h" #include "czas.h" #define T0_INIT (256-15) #define T1_INIT (65536-5000) uint8_t bufor; int main(void) { // Konfiguracja portów I/O DDR(LED) = 0xff; DDR(SEG) = 1<<SEG_1 | 1<<SEG_2 | 1<<SEG_3 | 1<<SEG_4; DDR(SW) &= ~(1<<SW_1 | 1<<SW_2); TCCR0 = 1<<CS02; TIMSK = 1<<TOIE0 | 1 << TOIE1; TCNT0 = T0_INIT; TCNT1 = T1_INIT; // ustawienie trybów pracy liczników TCCR1A = 0x00; TCCR1B |= (1<<CS11); // globalne odblokowanie przerwań sei(); // nieskończona pętla for(;;) reset(); return 0; } // procedury obslugi przerwania SIGNAL(SIG_OVERFLOW0) { pokaz_czas(); TCNT0=T0_INIT; } SIGNAL (SIG_OVERFLOW1) { akt_czas(); TCNT1 = T1_INIT; }


A to program do obsługi czasu:

Kod: Zaznacz cały

#include "czas.h" #include "harddef.h" #include "makra.h" #include "znaki.h" #include <avr/delay.h> // funkcje opóźniające uint8_t jednostki_msekund = 0, dziesiatki_msekund = 0, jednostki_sekund = 0, dziesiatki_sekund = 0; int r,t1,t2,t3,t4; r=1; void akt_czas(void){ (r==0){ jednostki_msekund++; // zwiększ licznik jednostek milisekund o 1 if(jednostki_msekund == 10) // jeśli licznik jednostek milisekund osiągnął wartość 10 to { jednostki_msekund = 0; // wyzeruj licznik jednostek milisekund dziesiatki_msekund++; // zwiększ licznik dziesiątek milisekund o 1 if(dziesiatki_msekund == 10) // jeśli licznik dziesiątek milisekund osiągnął wartość 10 to { dziesiatki_msekund = 0; // wyzeruj licznik dziesiątek milisekund jednostki_sekund++; // zwiększ licznik dziesiątek sekund o 1 if(jednostki_sekund == 10) // jeśli licznik jednostek sekund osiągnął wartość 10 to { jednostki_sekund = 0; // wyzeruj licznik jednostek sekund dziesiatki_sekund++; // zwiększ licznik dziesiątek sekund o 1 if(dziesiatki_sekund == 10) // jeśli licznik dziesiątek sekund osiągnął wartość 6 to { dziesiatki_sekund = 0; // wyzeruj licznik dziesiątek sekund } } } } t1=jednostki_msekund; t2=dziesiatki_msekund; t3=jednostki_sekund; t4=dziesiatki_sekund; } } void pokaz_czas(void){ AktWysw++; if(!(PIN(SW) & 1<<SW_2)) { switch(AktWysw){ case 1: { PORT(LED)= Liczby[t1]; // na wyświetlaczu wyświetl odpowiedni znak pobrany z pliku znaki.h PORT(SEG) = WSeg[3]; // włącz pierwszą cyfrę wyświetlcza break; // opuść instrukcję switch } case 2: { PORT(LED)= Liczby[t2]; PORT(SEG) = WSeg[2]; break; // opuść instrukcję switch } case 3: { PORT(LED)= Liczby[t3]; PORT(SEG) = WSeg[1]; break; // opuść instrukcję switch } case 4: { PORT(LED)= Liczby[t4]; PORT(SEG) = WSeg[0]; break; // opuść instrukcję switch } case 5: { AktWysw=0; // zeruj zmienną AktWysw break; // opuść instrukcję switch } } r=1; } else { switch(AktWysw){ case 1: { PORT(LED)= Liczby[jednostki_msekund]; PORT(SEG) = WSeg[3]; break; // opuść instrukcję switch } case 2: { PORT(LED)= Liczby[dziesiatki_msekund]; PORT(SEG) = WSeg[2]; break; // opuść instrukcję switch } case 3: { PORT(LED)= Liczby[jednostki_sekund]; PORT(SEG) = WSeg[1]; break; // opuść instrukcję switch } case 4: { PORT(LED)= Liczby[dziesiatki_sekund]; PORT(SEG) = WSeg[0]; break; // opuść instrukcję switch } case 5: { AktWysw=0; // zeruj zmienną AktWysw break; // opuść instrukcję switch } } } } // PRZYCISK RESETU void reset(void){ if(!(PIN(SW) & 1<<SW_1)) { jednostki_msekund = 0; dziesiatki_msekund = 0; jednostki_sekund = 0; dziesiatki_sekund = 0; r=0; } }

BARDZO PROSZĘ O POMOC

tg3a
-
-
Posty: 243
Rejestracja: 26 maja 2008, o 19:46
Lokalizacja: Warszawa

Postautor: tg3a » 29 sty 2009, o 22:08

Może spróbuję trochę podpowiedzieć.
Trzeba wprowadzić więcej stanów stopera - albo więcej wartości dla zmiennej r, albo wprowadzić dodatkową zmienną stanu.
Przykładowo jeśli wprowadzimy więcej stanów dla r, to jeśli naciskamy SW_2 i jest stan 0, to zmieniamy go na stan 1, i w tym stanie nie naliczamy czasu. Jeśli SW_2 jest zwolniony i stan r jest równy 1, to zmieniamy go na 2, i w tym stanie również nie naliczamy czasu. Jeśli naciskamy SW_2 i stan r jest równy 2, to zmieniamy ten stan na 3, i w tym stanie nie naliczamy czasu. Jeśli SW_2 jest zwolniony i stan r jest równy 3, to zmieniamy go na 0, bez resetu czasu do zera. W stanie 0 ruszy naliczanie czasu od wartości, na której się zatrzymało przed wyjściem ze stanu 0 do 1.
Naciśnięcie przycisku SW_1 tak jak i do tej pory będzie powodowało reset wartości czasu, i przejście do stanu 0, w którym naliczanie czasu ruszy do przodu, jak tylko przycisk SW_1 zostanie zwolniony i czas przestanie być resetowany.
Możliwe są też i inne koncepcje, a także i tę powyższą można przystosować do swoich założeń. W każdym przypadku chyba muszą być co najmniej 3 stany stopera reprezentowane przez jedną lub więcej zmiennych stanu.
Pozdrawiam, i życzę sukcesu.

tworekjuve
-
-
Posty: 4
Rejestracja: 29 sty 2009, o 17:20
Lokalizacja: Krakow

Postautor: tworekjuve » 29 sty 2009, o 23:32

Hmmmmmmmm no co prawda to prawda:

Napisałem kod ktory temu odpowiada (tak na szybko):

Kod: Zaznacz cały

void pauza(void) { if(PIN(SW) & 1<<SW_2 & r==1) { r=2; if(!(PIN(SW) & 1<<SW_2) & r==2) { r=3; if(PIN(SW) & 1<<SW_2 & r==3) { r=0; } } } }

Tylko teraz pojawia sie glowny problem bo cos juz takiego kombinowalem:

DRGANIE STYKÓW przycisku...

Podobno można tego uniknąć stosując opóźnienia...
Ale gdy je zastosowałem momentami program mi głupiał (startował sie i sam zatrzymywał) co podobno było spowodowane przerwaniami w tym pierwszym pliku od TIMEROW...
Właśnie tego nie rozumiem...

tg3a
-
-
Posty: 243
Rejestracja: 26 maja 2008, o 19:46
Lokalizacja: Warszawa

Postautor: tg3a » 31 sty 2009, o 16:20

Z drganiami styków nie mam dużego doświadczenia, ale chyba zrobiłbym to następująco (przedstawiam tu tylko ogólną ideę):
Dodałbym dodatkową zmienną stanu - licznik przerwań, w których przycisk jest naciśnięty. Trzeba też odpowiednio dobrać graniczną wartość licznika, przy której zaliczamy naciśnięcie przycisku. Wydaje się, że ta wartość powinna odpowiadać czasowi ok. 0,2-0,3 sekundy.
We wszystkich sytuacjach, gdy przycisk SW_2 jest zwolniony, ten licznik powinien być zerowany.
Jeśli przykładowo przycisk SW_2 zostanie naciśnięty przy stanie r=0, to zwiększamy licznik o 1, jeśli jego stan jest mniejszy od przyjętej wartości granicznej i nie zmieniamy stanu r na 1. Jeśli naciśnięcie będzie dostatecznie długie, to w końcu licznik za którymś przerwaniem osiągnie wartość graniczną, i zmiany stanu r na 1 dokonamy.
Dalsze zwiększanie wartości licznika nie ma sensu.
Jeśli naciśnięcie przycisku jest krótsze, to przy kolejnym przerwaniu po stwierdzeniu zwolnienia przycisku zerujemy licznik.
Analogicznie trzeba postąpić w przypadku zmiany stanu z 2 na 3 w związku z naciśnięciem SW_2.
Sądzę, że przycisk SW_1 nie sprawia kłopotów z drganiami styków, ale niewątpliwie będzie bardziej "czuły" od SW_2 po wprowadzeniu powyższego rozwiązania. Jeśli to będzie przeszkadzać, lub mylę się co do braku problemów, to będzie trzeba pomyśleć i o tym przycisku.
Pozdrawiam.

ar
-
-
Posty: 56
Rejestracja: 30 maja 2007, o 19:44
Lokalizacja: poznań

Postautor: ar » 1 lut 2009, o 11:01

Dla wyjaśnienia, jakie przerwania chcesz zliczać?
Problem jest dość prosty do rozwiązania. Ponieważ ma to być zegar, więc dysponujesz timerem odmierzającym jednostki czasu które zliczasz. Użyj go do przepatrywania klawiatury np co 20-50ms. Jeżeli dwa kolejne sprawdzenia stanu są takie same uznaj że klawisz jest wciśnięty. Jeżeli wciśnięcie nie zostanie potwierdzone, uznaj że klawisz puszczony. Pamiętaj tylko żeby odzróżnić stan wykrycia wciśnięcia i długiego przetrzymania klawisza, bo możesz zapętlić się na ciągłym obsługiwaniu.

tworekjuve
-
-
Posty: 4
Rejestracja: 29 sty 2009, o 17:20
Lokalizacja: Krakow

Postautor: tworekjuve » 11 lut 2009, o 20:27

Kurcze ale jak mam uzyć tego taimera do przepatrywania klawiatury???

Nie czaje jak to powinno wyglądać... Jaka formuła codu...

ar
-
-
Posty: 56
Rejestracja: 30 maja 2007, o 19:44
Lokalizacja: poznań

Postautor: ar » 11 lut 2009, o 21:00

Co zadany interwał czasowy /np. 20ms/, czytaj stan klawiszy. Sprawdzaj czy któryś jest wciśnięty. Jeżeli tak to zapamiętaj stan i zakończ. W następnym przerwaniu sprawdz czy stan jest taki sam jak poprzednio. Jeżeli tak, to masz wykryte i potwierdzone wciśnięcie. Dalej musisz gdzieś zapamiętać jaki wciśnięty, i czy już na niego zareagowałeś czy nie, by się nie zapętlić na obsłudze jednego klawisz.

tworekjuve
-
-
Posty: 4
Rejestracja: 29 sty 2009, o 17:20
Lokalizacja: Krakow

Postautor: tworekjuve » 11 lut 2009, o 21:22

Czyli cos takiego????

Kod: Zaznacz cały

[code] if(PIN(SW)&(1<<SW_1)) { _delay_ms(100); if(PIN(SW)&(1<<SW_1)) { //Wywołanie funkcji obsługa naciśnięcia przycisku } }
[/code]

ar
-
-
Posty: 56
Rejestracja: 30 maja 2007, o 19:44
Lokalizacja: poznań

Postautor: ar » 11 lut 2009, o 23:13

Wprowadzasz opóźnienie /delay/ pomiędzy kolejnymi sprawdzeniami stanu klawiszy a masz dokonywć odczytu w przerwaniu timera!!! W ten sposób jak robisz musiałbyć tylko odczytywać i czekać i tak w kółko.
Ale w przerwaniu tylko dokonywać odczytu i ewentualnie porównania. Pozostałe operacje związane z obsługą rób już poza przerwaniem, w pętli głównej programu -> obsłuż jeżeli wykryta zmiana /wciśnięcie/ klawisza. Potem pamiętaj że zmiana była obsłużona. Pamiętaj tylko że inaczej należy dokonywać wciśnięcie i puszczenie klawisza.

Wróć do „AVR/AVR32”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 19 gości