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

Usypianie i budzenie procesora przerwaniem zewnętrznym (ATMega88 [nie 8] - Int0)

Szopler 30 Cze 2012 20:17 2496 15
  • #1 11058634
    Szopler
    Poziom 21  
    Witajcie!
    Chcę oprogramować przerwanie Int0 w ATMedze88 tak, aby przy wykryciu braku zasilania głównego - zmianie stanu PD2 z niskiego na wysoki procesor przechodził w tryb PowerDown natomiast gdy na PD2 pojawi się stan niski procesor wybudzał się.

    Wykrywanie obecności zasilania zrobiłem następująco:
    Usypianie i budzenie procesora przerwaniem zewnętrznym (ATMega88 [nie 8] - Int0)
    POWER_OK podłączone do PD2, w trakcie normalnej pracy gdy napięcie jest wyższe niż napięcie ustalone przez diodę zenera, tranzystor typu nmos zwiera PD2 do masy. W przypadku zaniku zasilania głównego zasilanie ma tylko procesor z baterii, a zewnętrzny rezystor pullup wymusza na wejściu stan wysoki...

    Napisałem taki oto kod w C (AVR Studio) - proszę o przejrzenie i sprawdzenie:
    Inicjalizacja przy uruchamianiu procesora:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Obsługa przerwania:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Pytania:
    1 - Czy lepiej w tym przypadku wyzwalać przerwanie (do usypiania) zmianą stanu czy zboczem rosnącym?
    2 - Czy prawidłowo robię usypianie i budzenie?
    3 - Co byście zmienili poprawili...?
  • #2 11059545
    Krauser
    Poziom 26  
    Zasadniczy błąd to usypianie w przerwaniu. Wyłączone są przerwania, a ty usypiasz i procesor się nie wybudzi. Ja nigdy nie usypiam w przerwaniu. Ustaw sobie pomocniczą flagę, którą w pętli głównej odczytaj i wtedy uśpij.
    Jak chcesz zaoszczędzić na bateriach to dołącz
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    i użyj
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    uzywanie cli() i sei() w przerwaniu jak ty masz jest nie potrzebne, bo to jest już robione z automatu. Natomiast jeśli miałbyś
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    to wtedy jak najbardziej, ale raczej zamiast cli() sei() należy używać atomic_block.
  • #3 11060287
    Szopler
    Poziom 21  
    To teraz czekam na tych co się nie zgodzą z tym co napisałeś w punkcie pierwszym :D.

    Usypianie jest tak zrobione bo w przypadku braku zasilania głównego musi zrzucić dane do wewn. eeprom korzystając z energii zgromadzonej w kondensatorach. Nie dopuszczona jest utrata tych danych (do 20 bajtów) w przypadku braku/słabej/wymiany baterii. Dlatego wykorzystałem przerwanie.
  • #4 11060378
    drzasiek
    Specjalista CNC
    Ale zrozum, nie możesz usypiać uC w przerwaniu bo czym go obudzisz?
    Po wejściu w obsługę przerwania, automatycznie przerwania są wyłączane.
    Czyli twój program wyłącza budzik i idzie spać.
  • #5 11061307
    Szopler
    Poziom 21  
    Procek usypia i od razu się budzi, a nie powinien... coś nie widzę błędu.

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


    Obsługa przerwania:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Funkcja usypiająca:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Warunek w pętli głównej:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    PS.
    ISR(INT0_vect, ISR_NOBLOCK) - przez to powinno się dać zrobić bo nie blokuje przerwań, ale jeszcze nie wiem jak ;)
  • #6 11061662
    Krauser
    Poziom 26  
    Może tak.
    Funkcja usypiająca:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Mam nadzieję, że flaga to volatile
  • #7 11061803
    Szopler
    Poziom 21  
    Dziwne rzeczy się dzieją... podłączyłem przełącznik (normalnie zwarty) zamiast diody zenera, żeby ręcznie wywoływać przerwanie.
    Przy przyciśnięciu na PD2 podawany jest stan wysoki - dioda podłączona pod PB2 gaśnie ale wartości na wyświetlaczu dalej się zmieniają... czyli procek nie usypia.
    Po puszczeniu przycisku wymuszany jest stan niski, następuje inicjalizacja wyświetlacza (co widać jako chwilowe przygaszenie) i dioda się zapala.
  • #8 11062733
    Konto nie istnieje
    Poziom 1  
  • #9 11063326
    Szopler
    Poziom 21  
    Jeśli WatchDog jest domyślnie wyłączony to ja go nie konfigurowałem. Także fusebit WDTON jest nie ustawiony.
    Z resztą:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    Nic nowego nie wniosło do działania.

    Usypiam do głębokiego żeby nie zużywać baterii której głównym zadaniem jest podtrzymywać zewnętrzny RTC. Podczas uśpienia utrzymywany jest stan zmiennych w RAM więc po włączeniu nie muszę niczego czytać z EEPROM.
    Sam zapis do EEPROM może być dodany tylko po to, żeby np. przy wymianie baterii nie utracić danych.

    Priorytet przerwania od komparatora ma niski priorytet, dlatego go nie używam.
    Po drodze są ważniejsze przerwania od klawiatury, timerów i SPI - nie ma gwarancji, że wystarczy prądu do obsłużenia tego ostatniego.

    Dzięki za przypomnienie o BrownOut bo w tej chwili mam wyłączony... choć przy podtrzymaniu bateryjnym chyba nie jest konieczny.

    Nie wiem tylko dlaczego procesor nie zasypia...
  • #10 11063697
    LordBlick
    VIP Zasłużony dla elektroda
    Szopler napisał:
    Jeśli WatchDog jest domyślnie wyłączony to ja go nie konfigurowałem. Także fusebit WDTON jest nie ustawiony.
    Z resztą:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    Nic nowego nie wniosło do działania.
    Pragnę zauważyć, że kasowanie bitów WDE i WDIE należy przeprowadzić operacją AND na zanegowanych bitach.
  • #11 11063821
    Konto nie istnieje
    Poziom 1  
  • #12 11063867
    Szopler
    Poziom 21  
    @voytaschec:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    ??
  • #13 11063878
    Konto nie istnieje
    Poziom 1  
  • #14 11063884
    Szopler
    Poziom 21  
    Zamieszczam cały kod...
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Niestety dioda gaśnie a procesor dalej pracuje.
  • #15 11065035
    Krauser
    Poziom 26  
    Ja pisałem:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    a ty dałeś:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    a sleep_enable() tylko ustawia bit SE w rejestrze SMCR i wymaga jeszcze kolejnego kroku, a mianowicie sleep_cpu(), który odpowiada rozkazowi SLEEP.
    sleep_mode() zastępuje 3 kroki podczas usypiania.
    PS.
    Nie zauważyłem i powtórzyłem błędnie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    ta linia nic nie zmieni:
    Powinno być:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    ale to na marginesie bo w kodzie masz to dobrze
  • #16 11065128
    Szopler
    Poziom 21  
    Dzięki! Nie zauważyłem tego :|
    Po zmianie procesor faktycznie zasypia i się budzi jak trzeba.

    I tu mała uwaga - nawet uśpiony w przerwaniu budzi się prawidłowo - poniżej kod który działa:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
REKLAMA