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

[ATmega8] [ATmega8][C] - Timer2 blokuje program po zgaśnięciu diody, jak to naprawić?

yogu$ 21 Lis 2012 19:41 2256 14
REKLAMA
  • #1 11557435
    yogu$
    Poziom 9  
    Witam

    W programie wykorzystuję dwa timery: Timer0 i Timer2. 0 służy do zliczania zmiennej powstającej w czasie programu i do jego działania (narazie) nie mam zastrzeżeń.
    Problem jest z Timerem2. Służy on do zapalania diody na określony przez użytkownika czas (wartość czasu ustawiana przyciskami +-).
    Po wciśnięciu przycisku zapalającego diodę, świeci się ona tak długo jak został ustawiony czas świecenia, zatem tu jest wszystko ok.
    Jednak po zgaśnięciu diody, na wyświetlaczu LCD nic się nie dzieje; program został "zamrożony" i nie reaguje na żadne przyciski. Czemu to przerwanie wykrzacza mi cały program?

    Zależy mi aby wykorzystać Timer2, z racji tego że jest on 8bitowy i po preskalowaniu /64 wychodzi mi ~1ms na jedno przerwanie, czyli akurat taka jednostka jaką wykorzystuję przy czasie zapalenia diody.

    Jeśli ktoś zna jakiś lepszy sposób na zliczenie tych ustawionych milisekund zapalenia diody bez zablokowania programu (wszelkie delaye odpadają) to proszę, podzielcie się pomysłami :)
    Tymczasem zapoznajcie się z poniższym kodem, może uda wam się wychwycić przyczynę tego buga

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #2 11558073
    Piotr Piechota
    Poziom 22  
    Przerwanie od przycisków nie jest dobrym pomysłem. Odbicie styków powoduje generowanie wielu przerwań co może generować kłopoty. Myślę, że mógłbyś po wykryciu przerwania od klawisza zablokować to przerwanie na np. 100ms.

    Powodzenia
    Piotr
  • #3 11558167
    yogu$
    Poziom 9  
    Zastosowałem hardware'owy debouncing; filtr RC z przerzutnikiem Schmitta. Na oscyloskopie zero zakłóceń. Do uC wchodzi solidne 1.
    No i tak jak mówiłem: timer0 działa sprawnie, ale timer2 wiesza program... Chciałbym żeby on niejako działał w tle: ma zapalić diodę na zadany czas i tą diodę wyłączyć. Równolegle będzie działał drugi timer zliczający czas (ale nie ten sam co w przypadku diody) między przerwaniami INT0 i INT1 i podstawiający tą wartość do wzoru.
    Mógłbym zrobić to co prawda na monostabilnym NE555 i ustawiać czas diody potencjometrem, ale zależy mi by mieć możliwość precyzyjnego sterowania czasem zapalenia diody.
  • REKLAMA
  • #4 11558452
    perlon
    Poziom 20  
    Wg mnie :
    1. sei() wstaw po konfiguracji przerwań a nie przed
    2. preskaler 64 i tryb przepełnienia to po prostu
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    3. w konfiguracji timera2 włączyć go niech sobie chodzi
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    ;
    4.Zaświecenie diody to
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    5. W procedurze obsługi przerwania trzeba tylko zgasić diodę
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    nawet jak przerwanie będzie gasić zgaszoną diodę to i tak od tego ona się nie zapali ;-)
  • #5 11558838
    yogu$
    Poziom 9  
    No dobra, idziemy w dobrym kierunku, już się nie wiesza :D
    Teraz tylko dioda nie chce zgasnąć :|

    1) sei() dałem na początek pętli while(1)

    2) hmmm na pewno od razu ustawi go w tryb przepełnienia? Wydaje mi się że trzeba mu wskazać czy chcemy tryb OCIE czy TOIE, żeby przypadkiem przy kompilacji nie zgłupiał.

    3) W konfigu timera2 ustawiłem:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    4) W przypadku wciśnięcia przycisku zapalającego diodę:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    5) Obsługa przerwania (dodałem pobieranie wartości czasu podanej przez użytkownika)
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Przy okazji zmieniłem maksymalna wartość pobieraną od użytkownika z 300 do 250 (TCNT2 -> 8bitów...)
  • REKLAMA
  • #6 11558865
    Fredy
    Poziom 27  
    Ja bym to "działko" zrobił volatile.
  • REKLAMA
  • #7 11558917
    yogu$
    Poziom 9  
    Już poprawione na volatile int. W sumie dziwię się czemu wcześniej tego nie zrobiłem :| , ale jednak to nie to. Dalej jest gdzieś błąd.
  • #8 11558933
    Fredy
    Poziom 27  
    A co to jest:
    PORTD &= !(1<<PIND5);

    ma być raczej
    PORTD &= ~(1<<PIND5);

    analogicznie zapalanie :
    zamiast PORTD = (1<<PIND5); lepiej PORTD| = (1<<PIND5);

    Czy "fire_isr" jest Volatile?
  • #9 11558970
    yogu$
    Poziom 9  
    Logika przy PORD poprawiona, fire_isr zamienione na volatile unsigned char.
    Nie pomogło.
  • #10 11559427
    perlon
    Poziom 20  
    Dioda ci nie gaśnie ponieważ w ISR(TIMER2_OVF_vect) sprawdzasz czy licznik jest równy działko a przecież wiadomo,że jeżeli jesteś w przerwaniu od przepełnienia licznika TCNT2 to TCNT2 = 0 bo właśnie się przekręcił licznik i została postawiona flaga przerwania od przepełnienia. Zgaszenie nigdy nie nastąpi. Wróć do wersji gdzie w przerwaniu gasisz diodę bezwzględnie. Wtedy świecenie będzie trwało 256 cykli timer2 więc 1ms. Jeżeli chcesz dłużej to zastosuj w procedurze wewnętrzny licznik:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    wtedy masz świecenie na 2ms
    Tryb timera ustawiasz bitami OCIE2/TOIE2. TOIE2 masz ustawione a WGM20 i WGM21 dla trybu normalnego oba są zerami więc nic więcej nie musisz ustawiać.

    Upss.. potrzebna korekta bo w powyższej wersji nie wiadomo na jaki i się trafi. Trzeba by zamiast gaszenia diody w przerwaniu zastosować flagę i ją zliczać w pętli głównej.
  • #11 11559797
    yogu$
    Poziom 9  
    Zmienną unsigned volatile char fire_isr wykorzystałem w przerwaniu timera 2.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kod obsługi przycisku:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    1) Jeśli przycisk zostanie wciśnięty, przejdź do pierwszej pozycji menu
    2) Wyzeruj licznik TCNT2 (żeby rozpoczął zliczanie od nowa)
    3) Wyzeruj licznik fire_isr
    4) Zapal diodę
    5) Jeśli licznik nabijany przerwaniami będzie równy wartości ustawionej przez użytkownika to zgaś diodę.

    fire_isr ma zakres 0-255, zatem mieści się w przedziale czasu ustawianego przez użytkownika (0-250). Zakładam że w miarę płynnie się przepełnia i zeruje.
    Jedno przerwanie generuje 1ms, zmienna fire_isr zwiększa się wtedy o 1. Ilość milisekund z fire_isr jest porównywana z ilością ms z interfejsu menu.
    Dioda dalej nie chce gasnąć. Ja nie wiem jak to można bardziej łopatologicznie zaprogramować...
  • Pomocny post
    #12 11559992
    perlon
    Poziom 20  
    Błąd algorytmu !
    Jeżeli jest prawdą DZ_FIRE i key_dz_fire==0 zerujesz liczniki i zapalasz diodę i ustawiasz key_dz_fire na 1. Oznacza to że w następnych przebiegach pętli głównej nie masz szansy dotrzeć do warunku if(fire_isr==dzialko) bo go odcina nie spełniony warunek if(key_dz_fire==0). Brak jest zerowania flagi DZ_FIRE żeby była szansa wykonania warunku else key_dz_fire=0; ale wtedy w ogóle nie wejdzie do pętli warunkowanej if(DZ_FIRE)

    Nie mówię, że rozwiązanie najlepsze ale powinno zadziałać.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #14 11562225
    yogu$
    Poziom 9  
    Dzięki wsiem za pomoc, pokombinuję jeszcze.
    @tehaceole bardzo fajna stronka, dzięki :)
  • #15 11562299
    tehaceole

    Poziom 28  
    yogu$ napisał:
    @tehaceole bardzo fajna stronka
    Miło mi, że się podoba. Sukcesywnie ją rozbudowuję. Chwilowo nie mam czasu na aktualizację materiałów bo przygotowuję się do obrony pracy magisterskiej. Ale gdzieś w okolicach świąt pojawi się kilka nowych (mam nadzieję) ciekawych artykułów.

    Cieszę się, że mogłem pomóc.
REKLAMA