logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak poprawnie obsłużyć przerwania w C dla mikrokontrolera z przyciskiem i diodą?

KRZAG 27 Cze 2005 17:44 5386 33
Najlepsze odpowiedzi LABEL_AI_GENERATED

Jak w C na mikrokontrolerze poprawnie obsłużyć jeden przycisk tak, aby pierwsze wciśnięcie zapalało diodę na 3 minuty, a kolejne wciśnięcie w tym czasie ją natychmiast gasilo, bez fałszywych podwójnych przerwań?

Najprościej nie wykorzystywać samego przerwania zewnętrznego od przycisku, tylko odczytywać stan przycisku w przerwaniu timera co ok. 10 ms i filtrować drgania styków, np. uznając naciśnięcie dopiero po kilku kolejnych takich samych odczytach albo po zablokowaniu kolejnych wywołań na 150–500 ms [#1611419][#1612340] Wtedy timer może przekazywać do programu głównego jednorazową informację o poprawnym naciśnięciu, a pętla główna decyduje: jeśli dioda jest zgaszona, zapala ją i uruchamia odliczanie 3 minut, a jeśli świeci — gasi ją i resetuje stan [#1611419] Alternatywnie można w obsłudze przycisku wyłączyć jego przerwanie, uruchomić timer i ponownie włączyć przerwanie dopiero po ok. 300–500 ms, co też eliminuje podwójne impulsy od styków [#3509418][#3509676] Jeśli chcesz uprościć sprzętowo, pomaga też mały kondensator, np. 100 nF przy wejściu przycisku, który ogranicza wielokrotne odbicia styków [#3509676][#1863337]
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA
  • #1 1610884
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    Witam,
    chciałbym napisać program. Urządzenie składa się z 1 przycisku i 1 diody
    po wcisnieciu przycisku raz dioda ma się zapalic na 3 min, po wcisnieciu tego samego przycisku w trakcie trwania tych 3 min powoduje zgaszenie diody i powrot do poczatku
    Próbowałem w C z przerwaniami od tego przycisku ale w zaleznosc od tego na jakie zbocze reaguje mikrokontroler dostawalem prawie zawsze dwa sygnaly co moze byc tego przyczyna. Może jakoś nie poprawnie konfiguruję te przerwania ( a w zasadzie ich obsługę)
    main()
    {
    DDRB=0xff;
    PORTD=1<<PD2;
    MCUCR=_BV(ISC10);
    GIMSK=_BV(INT0);
    SREG=0x80;
    for(;;){}
    }
    SIGNAL(SIG_INTERRUPT0)
    {
    if(swieci==1)
    {
    swieci=0;
    zgas();
    }else
    {
    swieci=1;
    zapal();
    czekaj(3);
    zgas();
    swieci=0;
    }

    }
    dodam ze funcke zapal zgas sa oczywiste (ustawiaja poprostu bit na 0 lub 1) natomiast czekaj(3) zapetla program na 3 min sprawdzajac wciaz stan swieci gdy jest rowne zero to przerywa sie petla
    Ma ktoś pomysł co namąciłem nie tak?
    dzięki za opinię
  • REKLAMA
  • #2 1611053
    boodoo
    Poziom 12  
    Posty: 41
    Pomógł: 3
    Nie wiem, co znaczy 2 sygnały, ale może winą jest to, że:

    Przycisk ma to do siebie, że drży, tzn. podskakuje. Trudno nacisnąc przycisk raz.
    Najlepiej ustawic jakiś timer i kotnrolowac czas, po którym możliwa jest ponowna zmiana stanu diody.
  • REKLAMA
  • #3 1611125
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    DWA sygnaly tzn zachowuje sie jakby reakowal na oba zbocza naraz.
    kurcze myslalem ze zrobienie przerzutnika typu T na tak zaawanasowanym sprzecie jak atmega8 to pikus wiec dodalem mu bajer z czasem a tu lipa to wcale nie takie proste
    dla pewnosci zapytam
    czy ISC10 oznacza reakcje na jedno zbocze tak? czyli teoretycznie zwierajac przycisk i trzymajac uzyskuje przerwanie,
    gdy puszcze to sie nic nie dzieje, gdy znow wcisne to dostaje kolejne przerwanie, mam rację?

    bo dzieje się tak ze wciskam i ok zwiera ale kolejne przerwania nie wchodza, czy mozna je zagniezdzac?
    tzn obsluge przerwania przerwac kolejnym przerwaniem o tym samym poziomie? moze tu lezy haczyk?
  • #4 1611172
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    Nim zdążysz pomyśleć, kolejne przerwania się pojawiają i kończą, tak nawet około 300 na sekundę... ;) Użycie przerwań zewnetrznych to nienajlepszy pomysł na obsługe przycisku. Wystarczy algorytm w pętli + dobrze przemyślana obsługa przerwania timera.
  • #5 1611184
    boodoo
    Poziom 12  
    Posty: 41
    Pomógł: 3
    On nie reaguje najprawdopodobniej na 2 zbocza naraz tylko na kilka impulsów, bo przycisk może podskakuje.
  • #6 1611349
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    heh a co rozumiesz przez stwierdzenie dobrze przemyslana obsluga timera????
  • REKLAMA
  • Pomocny post
    #7 1611419
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    1. Sprawdzasz stan przycisku co jakiś czas, co przerwanie timera, np. 10ms (w przepełnieniu licznika np. Timer0 Overflow można regulować czasem pomiędzy przerwaniami, wpisując na początku obsługi przerwania odpowiednią wartość licznika, oraz wybierając preskaler w odniesieniu do częstotliwości zegara systemowego {1; 8; 64; 256; 1024}). Procedura timera może informowac o stanie przycisku pętlę główną za pomocą jakiejś pomocniczej zmiennej.
    2. Tworzysz za pomocą innej zmiennej licznik zmniejszający się co przerwanie do 0, ale nieprzekręcający się.
    3. W momencie naciśnięcia przycisku ustawiasz ten licznik na odpowiednią wartość, równoważną czasowi "odpluskwiania", np. 150ms, czyli w praktyce dopiero puszczenie przycisku pozwala na rozpoczęcie odliczania czasu. Naciśnięcia przycisku przechodzą test, tylko, gdy licznik jest wyzerowany, w pozostałych przypadkach są odrzucane i procedura przerwania nie informuje o tym pętli głównej. Aby wiec zachodził przypadek wykrycia wciśnięcia, w procedurze przerwania - najpierw test przycisku i dajemy znać do pętli głównej, gdy licznik = 0, potem zawsze przy wciśniętym ustawiamy od nowa licznik.
    --
    Pozdrawiam, Daniel
  • #8 1611494
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    hmm dzięki to zaczynam wertowanie pdf brzmi rozsądnie :) mam nadzieję żę moja znajomość anglickiego pozwoli mi wprowadzić w życie to co napisałeś :))
  • #9 1612340
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Możesz też spróbować zrobić tak:
    1. Stan przycisku odczytujesz w przerwaniu od Timer-a, na przykład co 10ms.
    2. Jeżeli trzy (lub więcej, zależnie od potrzeb) ostatnie odczyty są takie same, to uznajesz ten stan za stabilny - czyli przycisk naciśnięty lub zwolniony.

    W ten sposób eliminujesz drgania styków, a reakcja na nacisnięcie przycisku jest natychmiastowa, nie musisz czekać na puszczenie go.
  • #10 1613103
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    arturt134 napisał:
    W ten sposób eliminujesz drgania styków, a reakcja na nacisnięcie przycisku jest natychmiastowa, nie musisz czekać na puszczenie go.
    Pragnę zauważyć, że w moim rozwiazaniu reakcja jest jak najbardziej natychmiastowa, program reaguje natychmiastowo na "pierwsze"(gdy nie było innych od jakiegoś skończonego, umownego czasu) naciśnięcie, a dalsze odrzuca, licznik nie wyzeruje się, dopóki przez zadany czas nie bedzie klawisz puszczony.
    Natomiast w proponowanym rozwiązaniu :
    1. Mogą być dalej problemy, zwłaszcza, gdy przycisk się "wyrobi".
    2. Mimo wszystko jest opóźnienie potrzebne na policzenie tych "3 lub więcej" stanów "stabilnych".
    3. Nie widzę mechanizmu eliminacji nadmiaru informacji o wciśnięciu - program główny potrzebuje tylko jednokrotnej informacji o naciśnięciu, aby odpowiednio zareagować, reszta jest zbędna. Jeżeli jest potrzebna informacja o długotrwałym wciśnięciu, to również przekazujemy ją do programu głównego jednokrotnie, a oceną parametrów czasowych naciśnięcia zajmuje się odpowiednia procedura z licznikiem w obsłudze przerwań timera.
    --
    Pozdrawiam, Daniel
  • #11 1613130
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    1. Moga byc dalej problemy, zwłaszcza, gdy przycisk się "wyrobi".

    Nie wydaje mi się - niby dlaczego?


    2. Mimo wszystko jest opóźnienie potrzebne na policzenie tych "3 lub więcej" stanów "stabilnych".

    Oczywiście, że tak. Ale opóźnienie rzędu nawet 300ms jest dla człowieka niezauważalne.


    3. Nie widzę mechanizmu eliminacji nadmiaru informacji o wciśnięciu - program główny potrzebuje tylko jednokrotnej informacji o naciśnięciu, aby odpowiednio zareagować, reszta jest zbędna.

    Nie pisałem o tym, bo to nie było przedmiotem dyskusji. Najprościej jest blokować wykrywanie naciśnięcia przycisku po stwierdzeniu, że został on naciśnięty - na przykład na 300-500ms
  • #12 1613278
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    1. Przykład (eksteremalny) :
    Stan "stabilny"; przerwa w dostawie stabilności; znowu stan stabilny itd... Ile razy nacisneliśmy przycisk (w ciągu 100ms) ? ;)
    2. Proponuję ekspryment - stworzyć prosty licznik naciśnięć filtrowany w/g twojej metody... Ja już to przerabiałem, więc to co piszę to nie jest czysta teoria, a 300ms jest jak najbardziej do rozróżnienia, umowną granicą jest 100ms (0,1s), ale i taki czas w niektórych aplikacjach bywa krytyczny (np. pomiar refleksu u kierowcy).
    3. Przedmiotem dyskusji jest eliminacja drgań przycisków na potrzeby programu, więc jak najbardziej należałoby o tym pomyśleć.
    W własnych konstrukcjach kombinowałem na różne sposoby i najprostszy i najskuteczniejszy wydaje mi się ten przedstawiony wcześniej w moim poście.
    Blokowanie po stwierdzeniu, że jest naciśnięty owszem, jak najbardziej, ale czas zaczynamy liczyć od momentu, jak zostanie puszczony, a jeżeli znowu za wcześnie zostanie naciśnięty, to przedłużamy blokowanie.
  • #13 1613286
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    ehhh wszystko fajnie ale jak to wcielić w życie, okazało się że moja znajomość angileskiego niewiele tu pomogła :)
    ale się nie załamuję :)
    powiedzcie mi tylko czy do tych przerwań od zegara potrzeba dodawać rezonator kwarcowy czy isnieje jakaś funkcją której muszę się doczytać aby zrealizować to co piszecie?
  • #14 1613310
    karlos79
    Poziom 33  
    Posty: 1768
    Pomógł: 254
    Ocena: 77
    Nie musisz dodawać rezonatora, wystarczy pobierać impulsy z zegara systemowego i przepuścić je przez preskaler.
    Wszystko robisz programowo oczywiście.
    Kolega Light'I już o tym pisał kilka postów wyżej.
    Pozdrawiam
  • #15 1613396
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    Trochę kodu, aby namieszać ;) :
    - nagłówki i deklaracje (nie zapomnieć o F_CPU w Makefile) :
    #ifndef Tdiv1
    #define Trise		0x07 // exz. ((1<<CS02)|(1<<CS01)|(1<<CS00))
    #define Tfall		0x06
    #define Tdiv1024	0x05 // prescaler dzielący częstotliwość  zegara
    #define Tdiv256		0x04 // systemowego (kwarcu lub wewnętrznego oscylatora RC)
    #define Tdiv64		0x03
    #define Tdiv8		0x02 
    #define Tdiv1		0x01
    #define Tstop		0x00
    #define usDiv		1000000	// microsecond divisor
    #define msDiv		1000	// milisecond divisor
    #endif
    //---------Tutaj manipulujemy czasem pomiedzy przerwaniami i preskalerem----------
    #define T0div		Tdiv64
    #define T0Tick		10
    #define T0TickDiv	msDiv // usDiv or msDiv
    //---------------------------------------------------------------------------------
    #ifndef T0cnt
    	#if (T0div==Tdiv1024)
    		#define T0Scale	1024
    	#elif (T0div==Tdiv256)
    		#define T0Scale	256
    	#elif (T0div==Tdiv64)
    		#define T0Scale	64
    	#elif (T0div==Tdiv8)
    		#define T0Scale	8
    	#elif (T0div==Tdiv1)
    		#define T0Scale	1
    	#endif
    	#ifdef T0Scale
    		#define T0ovr1	(T0Tick*F_CPU)
    		#define T0ovr2	(T0TickDiv*T0Scale)
    		#define T0ovr	(T0ovr1/T0ovr2)
    		#define T0cnt	(0xFF-(T0ovr%0xFF))
    	#endif
    #endif
    - inicjalizacja przerwania :
    void InitOvrTimer0(void)
    	{
    	TCCR0=(unsigned char)T0div;
    	TIFR=1<<TOV0;
    	TIMSK=1<<TOIE0;
    	TCNT0=(unsigned char)T0cnt;
    	asm("sei");
    	}
    - szkielet procedury przerwania
    SIGNAL(SIG_OVERFLOW0)
    	{
    	TCNT0=(unsigned char)T0cnt;
    	//Tutaj dalsze operacje w przerwaniu od przepełnienia licznika
    	}
    Zastrzegam, że w C nie jestem mocarzem, na co dzień param się w asm, poprawki mile widziane... ;)
  • #16 1614861
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Ja w każdym razie obsługuję klawiaturę w moich urządzeniach w sposób jaki opisałem. Nigdy nie miałem problemów z tą metodą odczytywania stanu klawiszy (testowałem nawet na mocno zużytych klawiaturach). Być może w aplikacjach, gdzie czas jest krytyczny, lepiej byłoby zastosować inną metodę.

    A jeszcze jedno pytanie do Light'a: A co z EMC? przecież w ten sposób "łapiesz" każde zakłócenie (np. strzał ESD) jako nacisnięcie klawisza...
  • #17 1614912
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    arturt134 napisał:
    A jeszcze jedno pytanie do Light'a: A co z EMC? przecież w ten sposób "łapiesz" każde zakłócenie (np. strzał ESD) jako nacisnięcie klawisza...
    1. Przeważnie przycisk jest dość dobrze odizolowany i nie mam z tym problemu.
    2. Zakłócenie musiałoby nastąpić dokładnie w chwili badania przycisku, czego procent prawdopodobieństwa jest niewielki, chyba że mamy do czynienia z zakłóceniami długotrwałymi.
    Oczywiście kilkukrotne badanie stanu przycisku można użyć tutaj dodatkowo.
  • #18 1616527
    szel
    Poziom 20  
    Posty: 515
    Pomógł: 13
    Ocena: 10
    Można (dla pojedynczych przycisków) zastosować obwody RC współpracujące z przyciskiem i wciśnięcie przycisku generuje wtedy tylko pojedynczy impuls lub zmianę stanu na wejściu. Wystarczy wtedy, co jakiś czas kontrolować stan tego wejścia dla sprawdzenia, czy przycisk został wciśnięty.
  • #19 1622727
    chrobot
    Poziom 16  
    Posty: 211
    Pomógł: 8
    Ocena: 36
    ostatnio robiac cos do samochodu ( trudne warunki pracy zakłócenia )
    pomogla mi n/z procedura :

    //frgment kodu
    if (buf) //jeśli rezultat różny od 0 - sprawdź
    {
    Delay(50); //opóźnienie 50 ms dla samochody sprawdzam TRZY razy
    if (buf) //jeśli rezultat różny od 0 - sprawdź
    {
    Delay(50); //opóźnienie 50ms
    if (buf) //jeśli rezultat różny od 0 - sprawdź
    {
    Delay(50); //opóźnienie 50ms

    if (buf == KbdRead()) //ponowny odczyt klawisza i akcja,
    { //jeśli nadal wciśnięty
    switch ( KbdRead ())
    {
    case 0xC0:

    Tu kod programu .......
    break;
    } } }

    i po trzykrotny sprawdzaniu czy i jaki klawsz wcisnieto dalej.......
    Dopiero 3 x sprawdz. dalo poprawna prace uP.
  • REKLAMA
  • #20 1664425
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    Light ale co tak właściwie robi Twój fragment kodu? generuje przerwania co kilka ms??
    jakbyś mógł jeszcze powiedzieć co rozumiesz przez stwierdzenie "Tutaj manipulujemy czasem pomiedzy przerwaniami i preskalerem"
    ehh tyle tych pytań :)
  • #21 1671524
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    KRZAG napisał:
    Light ale co tak właściwie robi Twój fragment kodu? generuje przerwania co kilka ms??
    Ano jak wyżej zauważyłem liczymy czas od puszczenia klawisza, więc w obsłudze przerwania zmniejszamy stan licznika aż do zera. Szczegóły należą do Ciebie... ;)
    KRZAG napisał:
    jakbyś mógł jeszcze powiedzieć co rozumiesz przez stwierdzenie "Tutaj manipulujemy czasem pomiedzy przerwaniami i preskalerem"
    Wybieramy którego preskalera używamy i czas pomiędzy przerwaniami, jednostkę tego czasu (milisekundy lub mikrosekundy). Nic Tobie nie mówią nazwy symboliczne definicji ?
  • #22 1672229
    szel
    Poziom 20  
    Posty: 515
    Pomógł: 13
    Ocena: 10
    Dajcie spokój - jeden opór i kondensator wyeliminuje wielokrotne odbicia styków.
  • #23 1673327
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    niestety nie probowalem analizowac to z pdf ale moja znajomosc angielskich nazw technicznych wymieka
    wrzucilem twoj fragment kodu do procka ale cos nie dziala tzn kompiluje sie i wogole ale dalej jest ten problem ze stanami nieustalonymi i mogiła ehh
  • #24 1673368
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    Wcale nie pisałem, że jest to gotowa procedurka, tylko, że trzeba samemu się pobawić, ja tylko opisałem, co trzeba zrobić. Gotowego kodu nie mam, bo zależy on od konkretnej konfiguracji przycisków, no i programuję w asm, a C to tak "tykam dla zabawy"...
  • #25 1675502
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    hmm czy C nie jest bardziej czytelny niż asembler? z tego co wiem to chyba wszystko co sie robi w asm mozna i w c :)
  • #26 1676013
    LordBlick
    VIP Zasłużony dla elektroda
    Posty: 5438
    Pomógł: 549
    Ocena: 69
    Z tą czytelnością, to kwestia przyzwyczajenia, spróbuj tak z marszu odczytać chińskie krzaczki, a przecież są ludzie, dla których jest to czytelniejsze od naszych łacińskich znaków... ;) Mi jest łatwiej w AVRasm2, bo go znam dobrze i wykorzystuję jego pełnię możliwości. Dla mnie jest poręczniejszym narzędziem do przemawiania bezpośrednio procesorowi do rozsądku... ;)
  • #27 1850801
    viki
    Poziom 16  
    Posty: 262
    Pomógł: 11
    Ocena: 3
    a co myślicie o pomyśle starym jak elektronika?
    Załączniki:
    • Jak poprawnie obsłużyć przerwania w C dla mikrokontrolera z przyciskiem i diodą? drgania.gif (1.06 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #28 1851943
    paw789
    Poziom 18  
    Posty: 298
    Pomógł: 20
    Ocena: 68
    no wlaśnie, niech ktoś sprawdzi i sie wypowie czy to rozwiązanie jest dobre i jakiej pojemności powinien być kondensator, 100nF wystarczy?
  • #29 1863337
    szel
    Poziom 20  
    Posty: 515
    Pomógł: 13
    Ocena: 10
    Współpraca przycisków z układami cyfrowymi.
    Układ generuje jeden impuls sterujący po chwilowym przyciśnięciu przycisku P1 - dodatni lub ujemny. Wykluczając tzw. zjawisko odbicia styków, czyli powstawania wielokrotnych impulsów sterujących. Układ pozwala na wygenerowanie następnego impulsu sterującego po rozładowaniu się kondensatora C1 w czasie zależnym od wartości elementów RC, a w zasadzie znaczący jest tylko R1 i C1. Większa wartość - większe opóźnienie. Dobrać według potrzeb. Element R2 spełnia rolę oporu podciągającego - ustalającego początkowy poziom wyjściowy, - czyli 0 lub 1. Na opóźnienie ma minimalny wpływ. Punkt (+) połączyć z zasilaniem układu sterowanego. Dioda D1 może zostać pominięta. Kondensator C1 może być dowolnego typu - tu zastosowano elektrolityczny. W układach sterujących można także zastosować uniwibrator sterowany przyciskiem do wygenerowania pojedynczego impulsu sterującego (np.TTL 74121).
    Załączniki:
    • Jak poprawnie obsłużyć przerwania w C dla mikrokontrolera z przyciskiem i diodą? Styki-sterujace6b.jpg (97.37 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #30 1884826
    KRZAG
    Poziom 12  
    Posty: 82
    Ocena: 1
    hmm jak programowo pozbyc sie autopowtarzania przy nacisnieciu przycisku
    problem polega na tym ze jako wejscia uzywam kontaktronu bedzie on zalaczany co ok 3-5 sek ale nie wiem na jak dlugi czas poniewaz dokladnosc tego ustrojstwa jest porazajaca
    tak wiec chcialbym aby minimalny impuls sprawial ze dostaje zmiane na wejsciu, ale takze i bardzo dlugi rzędu kilku sekund
    oto moj dotychczasowy kod (fragment w C)
    ...

    #define tau0 150;//247; //stała czasowa timera0
    #define vliczt0 50; //stała wpisywana do licznika wejść do
    //do przerwania timera0
    unsigned char liczt0; //Licznik wejść do przerwania timera0.
    unsigned char licznik;

    ...

    SIGNAL (SIG_OVERFLOW0) //obsługa przerwania
    //od przepełnienia timera0
    {
    TCNT0=tau0; //odśwież stałą czasowa w TCNT0
    if(--liczt0==0) //czy już czytać klawisze?
    { //tak
    if(!(PIND &1<<PD1)) //czytaj SW4 - <->
    {
    licznik--;
    }
    else
    {
    if(!(PIND &1<<PD0)) //czytaj SW1 - <+>
    {
    licznik++;
    }
    }
    if(licznik==10)licznik=0;
    if(licznik==-1)licznik=9;

    liczt0=vliczt0; //odśwież stan liczt0
    }
    }

    int main(void)
    {
    liczt0=vliczt0;
    licznik=1;
    DDRD=0x60; //PD0-PD4 jako wejściowy, PD5-PD6 - wy
    PORTD=0xff; //z podciąganiem
    DDRB=0xff; //PORTB - wy
    PORTB=0xff; //z podciąganiem
    DDRC=0xff;
    PORTC=0xff;
    TIMSK=1<<TOIE0; //zezwolenie na przerwania od TC0
    TCNT0=tau0; //wpisz stałą czasowa do TCNT0
    TCCR0=3; //preskaler XTAL/1024,

    sei(); //odblokuj globalne przerwania

    while(1)
    {
    POTRB=~licznik;
    }
    }
    calość działa owszem ale pod warunkiem że mniejwiecej znam czas trzymania przycisku

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy poprawnej obsługi przerwań w języku C dla mikrokontrolera (np. Atmega8) w aplikacji z jednym przyciskiem i diodą LED, gdzie naciśnięcie przycisku ma za zadanie zapalić diodę na 3 minuty, a kolejne naciśnięcie w tym czasie ma ją zgasić i zresetować stan. Problemem są wielokrotne wyzwalania przerwań spowodowane drganiami styków przycisku, które powodują generowanie wielu impulsów przy jednym naciśnięciu. Proponowane rozwiązania obejmują eliminację drgań styków (debouncing) programowo poprzez wykorzystanie przerwań od timera, które co określony czas (np. co 10 ms) sprawdzają stan przycisku i filtrują niestabilne sygnały, lub sprzętowo przez zastosowanie kondensatora (np. 100nF) i rezystora RC do wygładzenia sygnału. Wskazano, że przerwania zewnętrzne nie są optymalne do obsługi przycisków ze względu na drgania i powtarzające się impulsy, lepszym podejściem jest odczyt stanu przycisku w przerwaniu timera i implementacja licznika czasowego do odrzucania kolejnych naciśnięć w czasie trwania impulsu. Omówiono także konfigurację przerwań (np. ustawienie MCUCR na ISC10 dla reakcji na zbocze) oraz wykorzystanie preskalerów i wewnętrznego zegara systemowego bez konieczności stosowania rezonatora kwarcowego. Wskazano, że w obsłudze przerwania przycisku można tymczasowo wyłączyć przerwania od przycisku i uruchomić timer do odliczania czasu blokady, co zapobiega wielokrotnemu wyzwalaniu. Dyskutowano także o alternatywnych metodach eliminacji drgań, takich jak wielokrotne sprawdzanie stanu przycisku z opóźnieniami, czy zastosowanie uniwibratorów monostabilnych. Podkreślono, że programowa obsługa debouncingu jest bardziej elastyczna i pozwala na natychmiastową reakcję na naciśnięcie, a sprzętowe filtry RC mogą znacznie poprawić stabilność sygnału. Wskazano, że w praktyce opóźnienia rzędu 100-300 ms są akceptowalne dla użytkownika i skutecznie eliminują fałszywe wyzwolenia. Przykłady kodu i konfiguracji przerwań dla Atmega8 i Atmega16 zostały podane w dyskusji.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA