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

[Atmega32][C] usypianie procka i jego wybudzanie

rsikon 23 Lip 2009 07:19 3978 13
  • #1 6812030
    rsikon
    Poziom 26  
    Witam, usiłuje wprowadzić mój procek w stan "czuwania".

    Korzystam z funkcji zawartych w avr/sleep.h

    Najchętnie to wprowadził bym go w tryb power down.

    Owszem wprowadzam go.

    Ale Wybudzam jedynie ressetując procek - wygnałem na nodze resetu.

    Najchętniej to budził bym go sygnałem na wejściu INT1 - ale niedziała mi to.

    W dokumentacji jest (odnosnie trybu power down): Only INT2 or level interrupt INT1 and INT0.

    Nalezy rozumieć dosłownie: INT2 lub INT1 i INT0? Czyli jak chcę korzystać z INT1 to w sumie muszę "zmostkować" go z INT0 ??


    Rozumiem, że aby uaktywnić procek muszę wcześniej włączyć obsługe przerwań i odpowiednio ją ustawić. Ale chyba funkci obsługi przerwania nie muszę wstawiać bo procek przy obudzeniu się będzie kontynułował działanie programu od poleceń zaraz po sleep_mode.
    Oczywiście nie jak się go budzi resetem :/

    Ktoś coś dopomoże, podpowie?
  • #2 6812102
    kukiz100
    Poziom 14  
    Cytat:
    Only INT2 or level interrupt INT1 and INT0


    Ten tekst oznacza, że w trybie power down procesor może być wybudzony tylko asynchronicznie (tzn procesor nie sprawdza stanu portów w rytm zegara, bo ten nie pracuje). Dla przerwań INT0 i INT1 przerwaniami asynchronicznymi jest poziom niski (np zwarcie nóżki do masy) a dla INT2 jest to zbocze sygnału. Nie musisz "mostkować" przerwań, każde z nich działa niezależnie od drugiego, musisz je tylko odpowiednio ustawić (czyli na poziom niski lub zbocze, odpowiednio do typu przerwania).
    Co do funkcji obsługującej przerwanie to MUSISZ ją napisać, nawet jeśli miałaby być pusta. Dlaczego? Ponieważ procesor po obudzeniu się wykryje, że nastąpiło przerwanie i skoczy do adresu, gdzie powinna być obsługa (tak naprawdę w AVR-kach skacze do odpowiedniego wektora przerwania a tam znajduje się instrukcja skoku do odpowiedniego miejsca w programie, które jest faktycznie odpowiedzialne za obsługę przerwania). Skoczy...i nic tam nie znajdzie a Twój program może się zawiesić. Napisz obsługę przerwania, nawet jeśli ta funkcja miała by być pusta. Wówczas kompilator doda funkcję powrotu po wejściu do przerwania i program powinien działać normalnie.
  • #3 6812124
    rsikon
    Poziom 26  
    Hmmm

    z tego by wynikało, że robiłem wszystko "w miare" dobrze a i tak nie działało:/

    Jesteś w stanie podać krótki sofcik np z jkas dioda i switchem do INT1 , że powiedzmy po x czasie "bezczynności" układ idzie w tryb "sleep"czy cos w tym stylu który testował by to o czym piszemy.

    Teraz nie mam dostepu do swoich wypocin, przykładu nie podam.


    Teraz mam nad czym myslec ... dlaczego mi to nie dzialalo, a fajnie by bylo gdyby jednak działało to po podaniu stanu niskiego na INT1...

    Hmmm moze dlatego , że masa podawana była poprzez diode 1N4148... ale watpie. Układ poprawnie interpretował stany na tym wejsciu. Chyba , że w sleep wymaga "idealnej masy".

    Radek
  • #4 6812139
    kukiz100
    Poziom 14  
    Wg noty katalogowej stan niski jest interpretowany do napięcia maksymalnie 0,2 VCC czyli dla zasilania procka 5V sygnał przez diodę spełnia ten warunek (generalnie lepiej używać diod Schottky-ego bo mają niższy spadek napięcia niż diody krzemowe). Co do kodu to chwilowo nie mam dostępu do kompilatora AVR a nie chciałbym dać Ci błędnego kodu:) Czy pisałeś obsługę przerwania INTx? Jeśli jej nie masz to na 99% gwarantuję Ci, że przez nią program się wiesza. Jeśli nadal nie uda Ci się tego odpalić to wieczorkiem napiszę coś do testów (bo teraz jestem w pracy:)
  • #5 6812353
    rsikon
    Poziom 26  
    W ferworze walki już różnie próbowałem...

    Też właśnie jestem w pracy :)

    zasilam uklad z 4,5V w sumie to Atmega16L - teraz o tym dopiero pomyslałem, że nie miałem Atmegi32L i wsadziłem "szesnastke" ale to raczej nie robi różnicy.

    Ponizej "niby schemat" :/
    [Atmega32][C] usypianie procka i jego wybudzanie
  • #6 6814292
    Brutus_gsm
    Poziom 25  
    W rejestrze przerwania int0 ustawiasz, czy ma występować przy falling down, czy low level. Procesor nie obudzi się przy opadającym zboczu, tylko niski poziom może to zrobić ;) I nigdy nie rób pustych przerwań. Wstaw tam cokolwiek.
  • #7 6814655
    mirekk36
    Poziom 42  
    rsikon - co to za schemat ? ma on coś wspólnego z tym o co pytasz w pierszym poście? czy to jakaś fantasmagoria? ;) (sorry ale to wygląda jak jakiś rysunek z przedszkola - a do tego tajemniczo oznaczone diody - po takim "schemacie" można się spodziewać , że może są one nawet wpięte nieodpowiednio i tylko dlatego coś ci nie działa)

    jeśli masz problemy z prostym wyprowadzaniem zes tanu uśpienia poziomem niskim przez wejście INTx - to po jaką choinkę na początku poznawania tego mechanizmu wprowadzasz sobie kłody pod nogi w postaci jakichś diod itp ?

    nie lepiej najpierw sprawdzić robiąc wszystko po kolei jak należy - a później gdy zadziała - dokonywać swoich modyfikacji ?

    1. skonfiguruj wejście INT0 lub INT1 tak aby było wyzwalane poziomem niskim

    a. ustaw ten pin jako wejście
    b. podciągnij go do VCC

    2. wprowadź procek w stan uśpienia

    3. zewrzyj na chwilę wejście INT0 lub INT1 do masy swoim switchem bez żadnej diody - i jeśli zadziała to jesteś w domu

    jeśli nie zadziała - to wtedy popracuj nad kodem - bo coś na pewno tam naknociłeś niestety ;)
  • #8 6814730
    rsikon
    Poziom 26  
    mirekk36 -> wiem, w durzej mierze masz racje, moze lepiej pisac i nie posilkowac sie schematami niz, robic je w biegu w paincie.
    Diody - nie rysowałem bo pewien ich włączenia nie byłem a nie chciałem dawać powodów do "czepiania się".

    Ogólna zasada ma byc taka, że wciśnięcie któregokolwiek z przycisków ma budzić układ - dlatego sygnały z poszczególnych switchy są "zbierane" poprzez diody na jedno wejście INT1.

    Tak w czasie "testów" robię w miarę możliwości kolejno etapy , niż na hura wszystko na raz.

    Niestety główny problem to brak czasu na swoje "pierdoły" - jak to, żona nazywa.

    Praca, dom, rodzina... a czasu dla siebie nima ;)

    Z tego też powodu szukam szybkiej i szczegółowej pomocy u Was. Aby coś zrobić na "już" a później w przypływie wolnego czasu to poanalizować.

    Postaram sie jutro jakiś listing wrzucić by nie być całkowicie gołosłownym - chyba, że ktoś wcześniej jakiś kod z rozwiązaniem tematu wrzuci.

    Radek
  • #9 6814791
    mirekk36
    Poziom 42  
    rsikon --> eeeh z żonami tak bywa, znam to ;)

    a na poważnie to jakiego ty kodu oczekujesz - nie ma uniwersalnego kodu pod wszystko. Proponuję zrób po kolei te kroki o któeych pisałem - na początku bez żadnych diod ( a swoją drogą , gdybyś pokazał jak je włączyłeś - a nie byłeś pewien czy dobrze to kto miałby się czepiać - po prostu ktoś zwróciłby ci uwagę że są np źle włączone i już - to chyba nie ujma ? )

    jak widzisz - na szybko to nigdy nic nie wyjdzie ;) bo poza samym złym rozwiązaniem sprzętowym możesz mieć jeszcze wiele problemów z kodem - a wbrew pozorom łatwiej pomóc jak ktoś wstawi tu fragment swojego kodu, który uważa za błędny itp

    poza tym już ktoś ci wspominał że musisz mieć zadeklarowaną obsługę tego przerwania żeby program nie wchodził w maliny po wybudzeniu. Bo w przeciwnym wypadku - taki właśnie może być efekt - że twój procek już się wybudza i wszystko dobrze zrobiłeś - ale niestety - po wybudzeniu "idzie w maliny i musi się przez to powiesić" stąd dla ciebie efekt taki jakby trzeba go było resetować

    no ale bez prawidłowego schematu i kawałka kodu to sam widzisz - zgaduj zgadula wychodzi ;)
  • #10 6815921
    kukiz100
    Poziom 14  
    Brutus_gsm napisał:
    I nigdy nie rób pustych przerwań. Wstaw tam cokolwiek.

    A tu się z Tobą nie zgodzę, jest takie coś (przynajmniej w WinAVR)
    EMPTY_INTERRUPT(vector)

    i czasem dobrze jest tego użyć
  • #11 6817648
    Brutus_gsm
    Poziom 25  
    kukiz100 napisał:
    A tu się z Tobą nie zgodzę, jest takie coś (przynajmniej w WinAVR)
    EMPTY_INTERRUPT(vector)

    i czasem dobrze jest tego użyć


    No o tym wiem, zapomniałem dodac i nie chciałem już mącić poczatkującemu ;) Tylko chodziło mi o to, że nie można robić przerwań typu

    ISR(TIMER1_OVERFLOW)
    {}
  • #12 6817783
    rsikon
    Poziom 26  
    Cóż....

    Wstyd mi ;)

    Na spokojnie wykonałem testowy programik ponownie i co mogę powiedzieć. Banał. Wszystko działa jak chciałem. W czym był wcześniej problem nie wiem.


    
    #define F_CPU 8000000UL
    
    #include <inttypes.h> 
    #include <avr/io.h> 
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    
    #define led_2_switch 	PORTA ^= _BV(5) 
    #define led_2_off 	PORTA &= ~_BV(5) 		
    #define led_2_on 	PORTA |= _BV(5) 
    
    #define led_3_switch 	PORTA ^= _BV(6) 
    #define led_3_off 	PORTA &= ~_BV(6) 		
    #define led_3_on 	PORTA |= _BV(6) 
    
    
    
    
    #define klawisz_1_on		bit_is_clear(PIND,2)
    #define czekaj_klawisz_1_off	loop_until_bit_is_set(PIND,2)
    
    uint64_t do_sleep =0;
    
    
    SIGNAL (SIG_INTERRUPT1) 
    {
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    
    }
    
    
    
    int main(void)                        // program główny
    {
    
    DDRA|=_BV(5);		// wyj LED 2
    PORTA|=_BV(5);
    
    DDRA|=_BV(6);		// wyj LED 3
    PORTA|=_BV(6);
    
    
    led_2_off;
    led_3_off;
    
    
    
    DDRD&=~_BV(6);
    PORTD|=_BV(6);
    
    DDRD&=~_BV(2);
    PORTD|=_BV(2);
    
    MCUCR = (0<<ISC11) | (0<ISC10);  
    GICR =_BV(INT1);          
    
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    
    
    led_2_on;
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    led_2_off;
    led_3_on;
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    led_3_off;
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    
    while (1){
    if (do_sleep==0)led_3_on;
    
    do_sleep++;
    
    		/* obsluga klawisza 1 */
    				if (klawisz_1_on){
    				_delay_ms(100);
    				if (klawisz_1_on){
    				czekaj_klawisz_1_off;
    					led_2_on;
    					_delay_ms(100);
    					_delay_ms(100);
    					_delay_ms(100);
    					do_sleep=0;
    					led_2_off;
    			} 
    			}
    		/* obsluga klawisza 1 */
    
    
    
    if (do_sleep==6000000) {
    		led_2_off;
    		led_3_off;
    		sei();
    		sleep_mode();
    		cli();
    		do_sleep=0;
    }
    
    if (do_sleep>6000000) do_sleep=6000001;
    
    }
    }
    


    Piekny kod moze i nie jest ale mial tylko testowac usypianie .

    Dobranoc.
  • #13 6817980
    mirekk36
    Poziom 42  
    rsikon -> nie ma co być wstyd ;) "Na spokojnie..." jak widzisz, to podstawa powodzenia ;)

    a odnośnie kodu - wiadomo testowy - tylko jeśli nie używasz do niczego przerwania to pozostaw ciało procedury puste - kompilator wstawi sobie tylko w odpowiednie miejsce rozkaz RETI i już

    a w ogóle to warto zapamiętać na wieki wieków - że gdzie jak gdzie - ale w procedurach obsługi przerwań - wystrzegaj się jak ognia jakichkolwiek pętli opóźniających swoją drogą ;)
  • #14 6819258
    rsikon
    Poziom 26  
    Co do procedury opozniajacej w przerwaniu:

    dałem ją tam aby układ obudził się po wcisnieciu przycisku ale nie zdarzył wylapac drugi raz, ze przycisk wcisniety i wykonac drugiej funkcji danego klawisza.

    Każdy klawisz w moim układzie ma miec dwie funkcje: budzenie układu oraz drugą różną dla każdego przycisku.
REKLAMA