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

Jak działają przerwania? Problem z kodem.

Jakub17 14 Lis 2016 21:17 2211 34
  • #1 16061539
    Jakub17
    Poziom 6  
    Widzę że wywiązała się bardzo ciekawa debata. Skoro mój wątek przybrał takie wielotematyczne formy to może pomożecie mi z czymś innym. Po co zakładać nowy temat i śmiecić na forum.

    Otóż ogarniam sobie przerwania teraz i kombinuje. Napotkałem na mały opór i prosiłbym Was o wytłumaczenie mi dlaczego myślę źle. Mam kod który za pomocą przerwania teoretycznie powinien zaplać i gasić diodę:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    Rozumiem to tak: po zezwoleniu na przerwanie sei() rozpoczyna się procedura przerwania i dioda zostaje zapalona. Następnie program wraca do miejsca po sei(), dociera linii wygaszenia diody i funkcja main się kończy. Tymczasem dioda nie mignie nawet raz... Dlaczego?
    Nie chodzi mi tu o to jaki sens ma pojedyncze mignięcie diodą tylko o zrozumienie wykonywania procedury... Nawiasem mówiąc zastanawiałem się jak zrobić miganie diody w nieskończoność ale nie bardzo wiem. Na pewno muszę dodać jakąś pętle nieskończoną np. while(1) ale nie wiem gdzie ją umieścić i co w niej zawrzeć bo np. coś takiego dodane po sei()

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Spowoduje że dioda w ogole nie miga. Nie dziwiłoby mnie to, bo w końcu pętla jest nieskończona, ale przed nią występuje uruchomienie przerwania, zatem dioda wedle mojego rozumienia znowu powinna raz mignąć, a następnie zamilknąć na wieki tymczasem tak się nie dzieje.... Dioda cały czas jest zgaszona, po zastosowaniu powyższej pętli.

    Moderowany przez tmf:

    Posty niezwiązane z oryginalnym wątkiem wydzieliłem do nowego tematu. Na przyszłość proszę pamiętać, aby dla nowego problemu założyć nowy wątek. Ułatwia to prowadzenie dyskusji i utrzymuje porządek na forum. Pamiętaj, że wątek czyta nie tylko autor, ale wiele osób szukających pomocy.

  • #2 16061546
    Konto nie istnieje
    Konto nie istnieje  
  • #3 16061570
    Jakub17
    Poziom 6  
    Okej działa ale połowicznie bo teraz dioda pali się w nieskończoność zamiast nie palić się w nieskończoność, ale chodzi mi bardziej o zrozumienie tego...

    sei(); -> wykonuje się procedura przerwania -> program wraca do miejsca "po sei();" i dociera do pętli nieskończonej i co dalej? Pętla będzie się wykonywać w nieskończoność to jak dokona się ponowne przerwanie? Możesz mi szczegółowo opisać jak widzi to kompilator bo nie mogę tego zrozumieć...
  • #4 16061590
    Konto nie istnieje
    Konto nie istnieje  
  • #5 16061883
    Jakub17
    Poziom 6  
    Wiem co robi przerwanie, problem w tym że nie potrafię określić jednoznacznie gdzie ono się rozpoczyna, gdzie zostaje zainicjowane. Czy przerwanie rozpoczyna się zaraz po zezwoleniu sei(); ?
  • #6 16061910
    tmf
    VIP Zasłużony dla elektroda
    Jakub17 napisał:
    Wiem co robi przerwanie, problem w tym że nie potrafię określić jednoznacznie gdzie ono się rozpoczyna, gdzie zostaje zainicjowane. Czy przerwanie rozpoczyna się zaraz po zezwoleniu sei(); ?


    Skoro użyłeś przerwania przepełnienia licznika, to wystąpi ono w chwili przepełnienia TCNT0. sei nie ma nic do rzeczy - to tylko zezwala na obsługe przerwania przez MCU. Licznik liczy od momentu jego uruchmienia. Odpal sobie ten kod w symulatorze i prześledź jego działanie ustawiając breakpointa w przerwaniu i krokowo wykonując program.
  • #7 16061928
    Konto nie istnieje
    Konto nie istnieje  
  • #8 16062448
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    Wiem co robi przerwanie, problem w tym że nie potrafię określić jednoznacznie gdzie ono się rozpoczyna

    Nie gdzie, tylko kiedy.

    Załóżmy taką sytuację:

    Dowódca X obserwuje przedpole, na którym spodziewa się ataku wroga.

    Żołnierz A ukryty i odległy o 500m dostał zadanie zliczania obcych żołnierzy.
    Gdy doliczy do 256 ma poinformować telefonicznie o tym fakcie dowódcę X i rozpocząć liczyć od zera oraz ma wystawić z okupu w kierunku dowódcy X świecącą latarkę, którą ma zgasić dopiero po każdej rozmowie z dowódcą lub na żądanie dowódcy X przekazane w postaci mrugnięcia przez dowódcę X jego własną latarką.

    Dowódca włącza telefon i obserwuje przedpole.

    Gdy żołnierz A doliczył do 256 dzwoni do dowódcy jednocześnie rozpoczynając nowe liczenie od zera oraz obserwuje pozycję dowódcy, by stwierdzić, czy ten mrugnie swoją latarką.

    Są die możliwości:

    Przypadek 1:

    Dowódca przerywa obserwowanie przedpola i odbiera telefon i meldunek żołnierza A.
    Żołnierz A wyłącza latarkę, bo meldunek został odebrany.



    Przypadek 2:

    Jeśli dowódca X wyłączy telefon, to żołnierz A nadal wykonuje zadanie, meldunek nie dociera do dowódcy w postaci rozmowy telefonicznej (przerwania).
    Dowódca natomiast może stwierdzić, czy żołnierz doliczył do 256 poprzez sprawdzenie, czy żołnierz A zaświecił latarkę.
    Jeśli to stwierdzi może mrugnąć żołnierzowi A latarką, by ten wyłączył swoją.

    ------

    Dowódca to jednostka centralna wykonująca program.
    Obserwacja przedpola przez dowódcę to pętla główna programu.
    Żołnierz A to timer, który gdy do liczy do 256 przepełnia się i ustawia flagę (w twoim przypadku TOVn) przerwania od przepełnienia timera.
    Latarka żołnierza A to flaga przerwania (TOVn).
    Latarka dowódcy X to "ręczne - programowe" gaszenie flagi przerwania.
    Rozmowa telefoniczna to funkcja przerwania (ISR).


    sei() włączenie telefonu przez dowódcę.
    cli() to wyłączenie telefonu przez dowódcę.


    Teraz już rozumiesz zależności?


    Czytaj i nabywaj wiedzę: http://mikrokontrolery.blogspot.com/p/spis-tresci.html
  • #9 16062454
    Jakub17
    Poziom 6  
    Wkradła się pewna nieścisłość. Racja: nie "gdzie" tylko "kiedy" występuje przerwanie. Niestety to nadal nie rozwiązuje mojego problemu, dlatego że rozumiem przerwanie tak jak to opisałeś a mimo wszystko zachowuje się to wszystko nieco inaczej...
    Jeszcze raz:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wedle tego co powiedziałeś przerwanie jest generowane zależnie od zliczeń timera, więc domyślnie w main diody są cały czas wygaszone, gdy timer zliczy 255 impulsów następuje wykonanie procedury przerwania w której jest zapalenie diody, następnie program z powrotem wraca do funkcji main, gdzie diody są na stałe wygaszone. Ale po wgraniu kodu powyżej dioda się nie pali w ogóle...

    Druga sprawa:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jest sama pętla while(1) bez wygaszania diody w main() a w przerwaniu jest zapalenie diody, więc diody palą się bez przerwy, to mnie nie dziwi. Ale jeżeli przesunę sei(); za pętle while(1) to już nie działa, diody są zgaszone na amen. Kłóci się to troche z tym jakoby miejsce "gdzie" wystąpi przerwanie nie miało znaczenia, bo tutaj ewidentnie ma... Timer sobie liczy, zezwolenie na przerwanie jest tylko w innym miejscu, to dlaczego ono nie występuje? Dlaczego diody nie palą się cały czas jak poprzednio?
  • #10 16062458
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    Wedle tego co powiedziałeś przerwanie jest generowane zależnie od zliczeń timera, więc domyślnie w main diody są cały czas wygaszone, gdy timer zliczy 255 impulsów następuje wykonanie procedury przerwania w której jest zapalenie diody, następnie program z powrotem wraca do funkcji main, gdzie diody są na stałe wygaszone. Ale po wgraniu kodu powyżej dioda się nie pali w ogóle...

    Ależ oczywiście że diody zapalają się w przerwaniu, tylko po kilku milionowych częściach sekundy są gaszone przez pętlę główną, ponieważ Twój mikrokontroler działa co najmniej na 1MHz.

    Jakub17 napisał:
    Ale jeżeli przesunę sei(); za pętle while(1) to już nie działa, diody są zgaszone na amen. Kłóci się to troche z tym jakoby miejsce "gdzie" wystąpi przerwanie nie miało znaczenia, bo tutaj ewidentnie ma... Timer sobie liczy, zezwolenie na przerwanie jest tylko w innym miejscu, to dlaczego ono nie występuje? Dlaczego diody nie palą się cały czas jak poprzednio?

    Bo to co jest za niekończącą się pętlą główną nigdy się nie wykona.

    Nadal mylisz miejsce z momentem - przeczytaj jeszcze raz mój post o żołnierzach.
  • #11 16062464
    Jakub17
    Poziom 6  
    Piotrus_999 napisał:
    Jakub17 napisał:
    Wiem co robi przerwanie, problem w tym że nie potrafię określić jednoznacznie gdzie ono się rozpoczyna

    No właśnie chyba nie do końca. Dlatego proponuję trochę poczytać o przerwaniach.


    Uwierz mi że zanim zakładam temat naprawdę czytam, bo zakładanie kolejnych tematów jest czasochłonne.
    http://mikrokontrolery.blogspot.com/2011/04/problemy-c-przerwania.html
    czytałem ten artykuł jak i wiele innych, tylko tutaj jest napisane że faktycznie miejsce wystąpienia przerwania nie jest istotne a czas:

    W punkcie "Flagi - rozwiązaniem problemu"

    "Takie rozwiązanie ma oczywiście także pewną wadę.
    Mianowicie, kod który zostanie wykonany w odpowiedzi na przerwanie nie jest wykonywany dokładnie w momencie rozpoczęcia wykonywania funkcji przerwania. Dzieje się tak dlatego, że przerwanie ustawia jedynie flagę, a pętla główna wykonuje się w bliżej nieokreślonym miejscu. Musi więc dojść do momentu sprawdzania flagi i dopiero wtedy wykona się właściwy kod przerwania."

    Dodano po 48 [sekundy]:

    @dondu


    Prescaler jest ustawiony na podział 1024 plus dodatkowy podział wewnątrz przerwania z if() więc chyba musiałbym cokolwiek zauważyć...
  • #12 16062471
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    http://mikrokontrolery.blogspot.com/2011/04/problemy-c-przerwania.html
    czytałem ten artykuł jak i wiele innych, tylko tutaj jest napisane że faktycznie miejsce wystąpienia przerwania nie jest istotne a czas:

    W punkcie "Flagi - rozwiązaniem problemu"

    "Takie rozwiązanie ma oczywiście także pewną wadę.
    Mianowicie, kod który zostanie wykonany w odpowiedzi na przerwanie nie jest wykonywany dokładnie w momencie rozpoczęcia wykonywania funkcji przerwania. Dzieje się tak dlatego, że przerwanie ustawia jedynie flagę, a pętla główna wykonuje się w bliżej nieokreślonym miejscu. Musi więc dojść do momentu sprawdzania flagi i dopiero wtedy wykona się właściwy kod przerwania."


    To opis do innego przypadku a konkretnie użycia flagi w postaci zmiennej. Opis ten dotyczył przykładu:


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Flagą jest tutaj zmienna flaga_1



    Jakub17 napisał:
    @dondu
    Prescaler jest ustawiony na podział 1024 plus dodatkowy podział wewnątrz przerwania z if() więc chyba musiałbym cokolwiek zauważyć...

    Jeszcze raz przeczytaj to:

    dondu napisał:
    Ależ oczywiście że diody zapalają się w przerwaniu, tylko po kilku milionowych częściach sekundy są gaszone przez pętlę główną, ponieważ Twój mikrokontroler działa co najmniej na 1MHz.


    Innymi słowy, co z tego że zapalasz diodę co 1 sekundę (1MHz / 256 / 1024 /4 ≈ 1Hz), skoro po kilku milionowych częściach sekundy ją wyłączasz.
  • #13 16062483
    Jakub17
    Poziom 6  
    Tak wiem, dotarło to do mnie co napisałem jak już opublikowałem post. Prescaler ustawia tylko częstotliwość występowania przerwań. No tak... przerwanie trwa tylko tyle czasu ile potrzebuje na wykonanie instrukcji... Dobra, to da się to w ogóle jakoś osiągnąć poza zastosowaniem zmiany stanu ^= w przerwaniu?

    I jeszcze mam do Ciebie takie podstawowe pytanie:

    czyli while(1) tak naprawdę sprawia że funkcja main() nigdy się nie kończy?
    Więc gdyby było tak w pętli while(pozostała częsć kodu bez zmian)

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To teoretycznie zapalenie diody w przerwaniu i jej gaszenie w main() wykonywałoby się tylko że w niezauważalnie krótkim czasie, tak?
  • #14 16062485
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    Tak wiem, dotarło to do mnie co napisałem jak już opublikowałem post. Prescaler ustawia tylko częstotliwość występowania przerwań. No tak... przerwanie trwa tylko tyle czasu ile potrzebuje na wykonanie instrukcji... Dobra, to da się to w ogóle jakoś osiągnąć poza zastosowaniem zmiany stanu ^= w przerwaniu?

    Co konkretnie chcesz osiągnąć?
  • #15 16062487
    Jakub17
    Poziom 6  
    dondu napisał:
    Jakub17 napisał:
    Tak wiem, dotarło to do mnie co napisałem jak już opublikowałem post. Prescaler ustawia tylko częstotliwość występowania przerwań. No tak... przerwanie trwa tylko tyle czasu ile potrzebuje na wykonanie instrukcji... Dobra, to da się to w ogóle jakoś osiągnąć poza zastosowaniem zmiany stanu ^= w przerwaniu?

    Co konkretnie chcesz osiągnąć?


    Migotanie diody w ten sposób że na stałe w main() jest ona wygaszona(post powyżej) w przerwaniu jest zapalana. I to bez użycia operatora zmiany stanu ^=
  • #16 16062497
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    Migotanie diody w ten sposób że na stałe w main() jest ona wygaszona(post powyżej) w przerwaniu jest zapalana. I to bez użycia operatora zmiany stanu ^=

    Tak to właśnie zrobiłeś, ale w pętli głównej wygaszasz diodę wiele tysięcy razy na sekundę.
    Aby to spowolnić musiałbyś w pętli głównej dodać opóźnienie.

    Pomijam oczywiście sensowność takiego algorytmu, bo jak rozumiem robisz to tylko dla testów.
  • #17 16062540
    Konto nie istnieje
    Poziom 1  
  • #18 16063057
    Jakub17
    Poziom 6  
    emarcus napisał:
    Jakub17 napisał:
    Wiem co robi przerwanie, problem w tym że nie potrafię określić jednoznacznie gdzie ono się rozpoczyna, gdzie zostaje zainicjowane. Czy przerwanie rozpoczyna się zaraz po zezwoleniu sei(); ?


    Mechanizm inicjowania przerwań jest z jednej strony relatywnie prosty, lecz dostatecznie zabezpieczony przed przypadkowym jego uruchomieniem.

    Aby uruchomic jakikolwiek interrupt (przerwanie), potrzebujesz 2 (dwa) zezwolenia.
    Pierwsze to globalne dotyczace wszystkich interruptów, zlokalizowane jako bit7 w rejestrze SREG - Status Register - (w datasheet referowany literą I).
    'Wydanie' takiego zezwolenia polega na ustawieniu (1) tego bitu, bądź to bezpośrednio w rejestrze, bądź instrukcją: mnemonic SEI
    Drugie zezwolenie wskazuje konkretnie czego dotyczy; jeżeli jakiejś funkcji timera na przykład: przepełnienie licznika, porównanie licznika z zadaną wartością itp.
    'Wydanie' takiego zezwolenia dokonywane jest również ustawieniem (1) odpowiedniego bitu w rejestrze TIMSK dla mniejszych processorów, lub TIMSKx dla większych, gdzie x - oznacza numer timera.
    Przykład: processor Mega48/88/168/328 potrzebujesz ustawic interrupt 'compare' (porównania zawartości Timera1 z zadaną wartością dla kanału A w trybie CTC ) - znajdziesz go w rejestrze TIMSK1 (bit 1) pod nazwą OCIE1A.
    Posiadanie tych dwóch zezwoleń nie wystarcza jeszcze do uruchomienia interruptu; to są tylko zezwolenia (mogą figurowac od samego startu programu). Na egzekucję interruptu wymagany jest trzeci warunek: - odpowiednia flaga stawiana przez program podczas jego przebiegu i jest wynikiem spodziewanych zdarzeń. Flaga ta powoduje natychmiastowe sprawdzenie istnienia wcześniej omawianych dwóch zezwoleń i w przypadku ich isnienia, program zostaje wstrzymany, zerowane jest tymczasowo zezwolenie globalne (I) i aby się nie pogubic, address ostatniej instrukcji jest odkładany na stack (stos), następuje skok do wykonania zadań określonych w stosownym 'interrupt handler'- w tym przykładzie byłby to: ISR(TIMER1_COMPA_vect) {//tu wszystkie_insrukcje do wykonania }.
    Po wykonaniu zadanych instrukcji processor kasuje flagę, przywraca ustawienie bitu (I) zezwolenia globalnego zdejmuje ze stosu address ostatniej instrukcji i powraca do miejsca w programie gdzie był przed interruptem.
    Wymieniona flaga to zwyczajny bit w odpowiednim rejestrze timera TIFR lub TIFRx podobnie jak interrupt w TIMSK.
    W tym przykładzie byłby to bit-1 (OCF1A) w rejestrze TIFR1.

    To wszystko jest o wiele dokładniej opisane w każdym datasheet.

    e marcus


    Wedle tego co napisałeś, nie spełniłem warunku ustawienia flagi. Czy ma to naprawdę istotny wpływ na działanie przerwania i całego programu? Ponieważ jak dotąd nie zarejestrowałem żadnych anomalii w działaniu. Czyli za sei() powinienem ustawić jeszcze bit flagi?

    Dodano po 12 [minuty]:

    dondu napisał:
    Jakub17 napisał:
    Migotanie diody w ten sposób że na stałe w main() jest ona wygaszona(post powyżej) w przerwaniu jest zapalana. I to bez użycia operatora zmiany stanu ^=

    Tak to właśnie zrobiłeś, ale w pętli głównej wygaszasz diodę wiele tysięcy razy na sekundę.
    Aby to spowolnić musiałbyś w pętli głównej dodać opóźnienie.

    Pomijam oczywiście sensowność takiego algorytmu, bo jak rozumiem robisz to tylko dla testów.


    No tak bo z każdą iteracją pętli dioda zostaje wygaszona, dodając delay wydłużę wygaszenie, ale co z przerwaniem? Ono też trwa bardzo krótko stąd czas zapalenia diody może być niezauważalnie mały a dodawanie delay w przerwaniu to chyba kiepski pomysł, no chyba żeby wyliczyć co ile mniej więcej występują przerwania... Kolejne przerwanie występuję nieco ponad 1,025 ms. Chyba że na jeden delay przypadnie dużo przerwań z zapeleniem diody stąd optycznie dla oka będzie się ona palić przez czas między kolejnymi iteracjami while(1). Jak to interpretować?

    Tak, sensownosć tego programu można pominąć, chcę się tylko upewnić że dobrze rozumiem przerwania.
  • #19 16063107
    dondu
    Moderator na urlopie...
    Generalnie dobrze już kumasz czaczę :)

    Jakub17 napisał:
    No tak bo z każdą iteracją pętli dioda zostaje wygaszona, dodając delay wydłużę wygaszenie, ale co z przerwaniem? Ono też trwa bardzo krótko stąd czas zapalenia diody może być niezauważalnie mały a dodawanie delay w przerwaniu to chyba kiepski pomysł, no chyba żeby wyliczyć co ile mniej więcej występują przerwania... Kolejne przerwanie występuję nieco ponad 1,025 ms.

    Najpierw wiec ustalmy, jak ma działać Twój program, bo na razie masz dwa niezależne procesy - pętlę główną i przerwanie, czyli jednego ludzika, który włącza światło i drugiego który wyłącza, przy czym ponieważ żyją swoim życiem nigdy nie będzie pewności, że dioda będzie świecić zawsze przez ten sam czas.

    Napisz więc jak ma działać Twój program.

    A propos przerwań i opóźnień jawnych i niejawnych: http://mikrokontrolery.blogspot.com/2011/04/problemy-c-przerwania.html


    Jakub17 napisał:
    Wedle tego co napisałeś, nie spełniłem warunku ustawienia flagi. Czy ma to naprawdę istotny wpływ na działanie przerwania i całego programu? Ponieważ jak dotąd nie zarejestrowałem żadnych anomalii w działaniu. Czyli za sei() powinienem ustawić jeszcze bit flagi?

    Wszystko co trzeba już włączyłeś:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #20 16063285
    Konto nie istnieje
    Poziom 1  
  • #21 16063793
    Jakub17
    Poziom 6  
    dondu napisał:

    Najpierw wiec ustalmy, jak ma działać Twój program, bo na razie masz dwa niezależne procesy - pętlę główną i przerwanie, czyli jednego ludzika, który włącza światło i drugiego który wyłącza, przy czym ponieważ żyją swoim życiem nigdy nie będzie pewności, że dioda będzie świecić zawsze przez ten sam czas.

    Napisz więc jak ma działać Twój program.

    [/syntax]


    Zrobiem tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I masz racje, czasami dioda miga jasniej a czasami nie tzn. ma jasnosc taka jak dla 100 ms, a czasami spontanicznie przestawia sie na jasnosc 10 ms opoznienia (wiem, bo sprawdzalem) w petli while. Tzn. ze dziala to tak jak pisalem wczesniej? Tzn na jeden taki delay przypadaka kilka tysiecy przerwan zapalajacych diode przez co powstaje zludzenie ze dioda faktycznie pali sie przez te 100 ms, tak? Czyli gdyby sobie tak to wyobrazic, to ten delay(100) jest "poszatkowany" przerwaniami, w ciagu jego trwania wystepuje mnostwo przerwan zapalajacych diode i stad efekt migania, dobrze rozumiem? Tylko niestety pojawia sie czasami ta rozbieznosc w sile migania o czym mowiles stosujac aluzje do tych ludkow zaplajacych swiatlo...
  • #22 16063992
    Konto nie istnieje
    Konto nie istnieje  
  • #23 16064074
    dondu
    Moderator na urlopie...
    Jakub17 napisał:
    Czyli gdyby sobie tak to wyobrazic, to ten delay(100) jest "poszatkowany" przerwaniami, w ciagu jego trwania wystepuje mnostwo przerwan zapalajacych diode i stad efekt migania, dobrze rozumiem?

    Delay wielokrotnie może zostać przerwany przez przerwania. Czy oraz ile razy w Twoim przypadku jest przerywany można byłoby policzyć znając Twój aktualny program.
  • #24 16064913
    Jakub17
    Poziom 6  
    Program ma zapalać diodę z częstotliwością 1 Hz lub 1 s jak kto woli. Tak jak mówiłem występuje pewna nieregularność trwania stanów niskich tzn. po kilku mignięciach stany niskie stają się coraz krótsze aż w końcu pojawią się ze 2 delikatnie zauważalne mignięcia i po tym następuje znowu ponownie wyraźne miganie diody, czyli że stany niskie trwają dostatecznie długo. Myślę że to dlatego że przerwania są już na "końcówce" delay i zaraz ma nastąpić ponownie linia z wygaszeniem diody(a polecenie to trwa krócej) i dlatego ten czas się skraca.

    Ja rozumiem to tak: Prescaler ustawiony na 1024 stąd 1MHz przez 1024 daje 976 Hz TIMERa - czyli zliczenie 976 impulsow w ciagu sekudny. Wyliczamy ile zajmie zliczenie 255 impulsow: 255/976 = 0,2612 s = 26 ms - co tyle czasu wystepuje 1 przerwanie. Jezeli delay wynosi 1000 ms to w ciągu jego trwania występuje 38 przerwań. Stąd wydaje mi się jakby przez tą jedną sekundę dioda się paliła non stop a w rzeczywistości 38 razy zapala się i gaśnie. Po delay następuje wygaszenie diody PORTC &= ~(1<<LED1);. Nie wiem ile trwa ta operacja, ale
    jest na tyle krótka ze przypadnie na nią zbyt mała ilość przerwań abym zauważył że dioda jest zapalona tzn. w czasie tej operacji dioda zapala się i gaśnie ale dzieje się to ze zbyt małą czestotliwością bym zauważył że dioda się w tym czasie pali, więc w rzeczywistości widzę to jako przerwę między kolejnymi zapalniami. W następnym kroku znowu następuje delay i przez 1 s dioda się pali.

    Czy jest to poprawny tok rozumowania?


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #25 16064925
    dondu
    Moderator na urlopie...
    Twoje obliczenia: 1MHz / 1024 / 256 ≈ 3,81Hz czyli co 262ms
    Wnioski pozostawiam Tobie.

    Skoro ma zapalać diodę co sekundę, to wystarczy przerwanie co pół sekundy i zmiana stanu pinu na przeciwny. Wtedy zawsze będzie mrugać prawidłowo. Ale ponieważ:

    Jakub17 napisał:
    Dobra, to da się to w ogóle jakoś osiągnąć poza zastosowaniem zmiany stanu ^= w przerwaniu?

    ... to wracając do ludzików, musisz jakoś drugiego ludzika (który samodzielnie podejmuje decyzje) zmusić, by odliczał czas od włączenia światła przez pierwszego ludzika. W przeciwnym razie drugi podejmie decyzję w dowolnym momencie.

    W związku z tym pierwszy ludzik musi dać informację drugiemu, że zapaliłem światło więc odliczaj sobie swój stały czas, ...

    ... albo ludzik drugi, musi obserwować przełącznik światła, i gdy wykryje moment jego włączenia odliczyć swój stały czas i wyłączyć światło. Ten drugi sposób to ciągłe sprawdzanie w pętli głównej stanu bitu np. LED1 w PORTC i gdy wykryjesz że został ustawiony odliczyć stały delay i zgasić go.
  • #26 16064995
    BlueDraco
    Specjalista - Mikrokontrolery
    Zieeew.... Jeśli coś prostego i krótkiego ma być robione co jakiś czas - robi się to w przerwaniu timera, nie w pętli zdarzeń. Koniec. Całe dywagacje o zależnościach pomiędzy przerwaniem i pętlą są zbędne i bezzasadne. Nie ma prostszego i elegantszego rozwiązania Twojego problemu, niż użycie timera - bez jakichkolwiek działań w pętli zdarzeń. No i na przyszłość - zapomnij o istnieniu czegoś takiego jak delay(). Im szybciej to zrobisz - tym lepiej.
  • #27 16065069
    dondu
    Moderator na urlopie...
    BlueDraco napisał:
    Zieeew.... Jeśli coś prostego i krótkiego ma być robione co jakiś czas - robi się to w przerwaniu timera, nie w pętli zdarzeń. Koniec. Całe dywagacje o zależnościach pomiędzy przerwaniem i pętlą są zbędne i bezzasadne. Nie ma prostszego i elegantszego rozwiązania Twojego problemu, niż użycie timera - bez jakichkolwiek działań w pętli zdarzeń. No i na przyszłość - zapomnij o istnieniu czegoś takiego jak delay(). Im szybciej to zrobisz - tym lepiej.

    Problem w tym, że autor tematu nie tworzy konkretnego rozwiązania, tylko poznaje przerwania (patrz tytuł) i z tym związane możliwości, zależności lub ich brak, problemy, itp.
  • #28 16065622
    Konto nie istnieje
    Konto nie istnieje  
  • #29 16065780
    dondu
    Moderator na urlopie...
    Piotrus_999 napisał:
    dondu napisał:
    Problem w tym, że autor tematu nie tworzy konkretnego rozwiązania, tylko poznaje przerwania (patrz tytuł) i z tym związane możliwości, zależności lub ich brak, problemy, itp.

    W ten sposób na pewno nie pozna i nie zrozumie niestety. A już jakies kombinacje z delay w pętli glównej + przerwanie timera to należy tępić w Jego głowie w zarodku

    Wręcz przeciwnie. Zdiagnozował problem, widzi objawy i wyciąga wnioski.
    Jednym z nich będzie, że wszystko powinien zrobić na przerwaniach bez użycia delay w pętli głównej.
    Na razie jednak specjalnie chce zrobić inaczej, by dobrze wszystko zrozumieć - mam rację Jakub17?
  • #30 16065792
    Konto nie istnieje
    Poziom 1  
REKLAMA