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

[Atmega16][asm]Przerwania zewnętrzne.

maciej_333 18 Lis 2010 22:41 3307 15
  • #1 8761421
    maciej_333
    Poziom 38  
    Wstyd się do tego przyznać, ale nie mogę sobie z tym poradzić. Chcę by przerwanie INT0 było wyzwalane zboczem opadającym. Kod źródłowy programu znajduje się poniżej:
    .nolist
    .include "m16def.inc" ;dołączenie listy stałych
    .list
    .cseg
    
    ;konfiguracja przerwań zewnętrznych
    .EQU ISC0 = 2 ;ISC00 i ISC01 aktywne zbocza opadające dla INT0 i INT1
    .EQU ISC1 = 2 ;ISC10 i ISC11
    .EQU MCUCR_ = 4*ISC1 + ISC0
    
    .EQU PIN_INT0 = 1 ;zezwolenia na INT0 i INT1
    .EQU PIN_INT1 = 0
    .EQU GICR_ = 128*PIN_INT1 + 64*PIN_INT0
    
    .EQU LED = 7
    
    .org 0x0000 rjmp RESET
    .org 0x0002 rjmp INTERRUPT_INT0
    .org 0x0004 rjmp INTERRUPT_INT1
    
    	INTERRUPT_INT0:
    		cbi PORTA,LED
    	reti
    
    	INTERRUPT_INT1:
    	reti
    
    RESET:
    ldi R18,low(RAMEND)
    out SPL,R18
    ldi R18,high(RAMEND)
    out SPH,R18
    
    ldi R18,MCUCR_
    out MCUCR,R18
    
    ldi R18,GICR_
    out GICR,R18
    
    sbi DDRA,LED
    sbi PORTA,LED
    
    sei
    
    stop:
    rjmp stop
    

    Jednak pojawiające się zbocze nie zgłasza przerwania. Ponadto ręczne ustawienie flagi w trakcie debuggowania powoduje brak reakcji, lub czasem reset mikrokontrolera.
  • #2 8761606
    korrus666
    Poziom 40  
    Przecież nigdzie nie ustawiasz przerwań.
    
    ;konfiguracja przerwań zewnętrznych
    .EQU ISC0 = 2 ;ISC00 i ISC01 aktywne zbocza opadające dla INT0 i INT1
    .EQU ISC1 = 2 ;ISC10 i ISC11
    .EQU MCUCR_ = 4*ISC1 + ISC0
    
    .EQU PIN_INT0 = 1 ;zezwolenia na INT0 i INT1
    .EQU PIN_INT1 = 0
    .EQU GICR_ = 128*PIN_INT1 + 64*PIN_INT0 
    

    To definiuje tylko wartości zmiennych
  • #3 8763188
    maciej_333
    Poziom 38  
    korrus666 napisał:
    Przecież nigdzie nie ustawiasz przerwań.
    
    ;konfiguracja przerwań zewnętrznych
    .EQU ISC0 = 2 ;ISC00 i ISC01 aktywne zbocza opadające dla INT0 i INT1
    .EQU ISC1 = 2 ;ISC10 i ISC11
    .EQU MCUCR_ = 4*ISC1 + ISC0
    
    .EQU PIN_INT0 = 1 ;zezwolenia na INT0 i INT1
    .EQU PIN_INT1 = 0
    .EQU GICR_ = 128*PIN_INT1 + 64*PIN_INT0 
    

    To definiuje tylko wartości zmiennych

    To nie są zmienne tylko stałe ! Wyliczone w trakcie prekompilacji stałe są wprowadzane do rejestrów MCUCR i GICR, przez Atmege w trakcie pracy programu. Zobacz to:
    Cytat:
    ldi R18,MCUCR_
    out MCUCR,R18

    ldi R18,GICR_
    out GICR,R18

    Stałe MCUCR_ i GICR_ są ładowane bezpośrednio do R18, a potem do GICR i MCUCR. Wynika to z tego, że nie da się bezpośrednio czegoś załadować do wspomnianych rejestrów, bo znajdują się w obszarze adresowym "wyjścia". Załamała mnie Twoja wypowiedź kolego korrus666... Widać programowanie w językach wysokiego poziomu strasznie Cię okaleczyło. Napisz trochę programów w asemblerze, a wyjdzie Ci to na dobre. Zrozumiesz działanie procesora (choć Atmega to już mikrokontroler) i będziesz pisał lepsze programy w swoim C, Javie, lub co gorsza Bascomie.

    Problem rozwiązałem. Przerwanie jest już obsługiwane. Program był poprawny. Trzeba jeszcze było ustawić podciągnięcie dla pinu INT0 i wymusić tam stan wysoki, tak by zbocze opadające miało szansę się pojawić.

    Choć dziwne jest to, że przy debuggowaniu nie da się wymusić sztucznie zgłoszenia przerwania. Czemu tak jest ?
  • #4 8763380
    omicronNs
    Poziom 21  
    Przecież ten program działa. Może wymuszasz zbocze na PORTD zamiast na PIND albo na złym pinie.
  • #5 8763438
    maciej_333
    Poziom 38  
    omicronNs napisał:
    Może wymuszasz zbocze na PORTD zamiast na PIND

    Przerwanie sztucznie chiałem zgłosić, ustawiając flagę INTF0 w GIFR. Oczywiście pracuję z JTAG ICE. Zresztą program działa to już zauważyłem jak uruchomiłem go bez debuggowania.
  • Pomocny post
    #6 8764231
    Andrzej__S
    Poziom 28  
    Cytat:

    Przerwanie sztucznie chiałem zgłosić, ustawiając flagę INTF0 w GIFR.

    A tak z ciekawości, jak to chciałeś zrobić? Czytałeś to?
    Atmel napisał:

    The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.

    Wpisywanie logicznej jedynki zeruje flagę, a nie ustawia. Wpisywanie zera nic nie zmienia, niezależnie od tego, czy flaga jest ustawiona, czy nie.
  • #7 8764307
    omicronNs
    Poziom 21  
    Wpisanie 1 ją kasuje, jeśli jest już ustawiona. A co się dzieje jak przy wpisywaniu, stan tego bitu to 0? Poza tym kolega ma JTAG i coś mi się wydaje(nie znam dokładnie JTAG-a), że ma sprzętowy dostęp do wszystkich rejestrów uK, niezależnie od tego co dzieje się w programie.
  • #8 8764515
    Andrzej__S
    Poziom 28  
    omicronNs napisał:

    Wpisanie 1 ją kasuje, jeśli jest już ustawiona. A co się dzieje jak przy wpisywaniu, stan tego bitu to 0?

    Też ją zeruje.

    omicronNs napisał:

    Poza tym kolega ma JTAG i coś mi się wydaje(nie znam dokładnie JTAG-a), że ma sprzętowy dostęp do wszystkich rejestrów uK.

    No właśnie ja też nie znam JTAG-a, dlatego pytałem.
  • #9 8764877
    maciej_333
    Poziom 38  
    Stosując interfejs JTAG mamy właśnie sprzętowy dostęp do wszystkich rejestrów, jakie by one nie były. Można np. załączyć debuggowanie, potem wymusić 0 (sprzętowo - zwierając tą linię do masy) na jakieś linii portu. Będzie to widać w AVR Studio - zmieni się stan PINn. Można też zmieniać wartości pszczególnych rejestrów, flag np. słowa stanu (odpowiednik PSW z 8051, nie pamiętam jak to się tu nazywa). Możemy też zaglądać do pamięci RAM, zmieniać wartości komórek itd.

    Podłączyłem do Atmegi impulsator, o nie znanym typie. Odlutowałem go z monitora CRT. Poniżej kod:
    .nolist
    .include "m16def.inc" ;dołączenie listy stałych
    .list
    .cseg
    
    ;konfiguracja przerwań zewnętrznych
    .EQU ISC0 = 2 ;ISC00 i ISC01 aktywne zbocza opadające dla INT0 i INT1
    .EQU ISC1 = 2 ;ISC10 i ISC11
    .EQU MCUCR_ = 4*ISC1 + ISC0
    
    .EQU PIN_INT0 = 1 ;zezwolenia na INT0 i INT1
    .EQU PIN_INT1 = 0
    .EQU GICR_ = 128*PIN_INT1 + 64*PIN_INT0
    
    .EQU LED = 7
    .EQU IN_IMPULSATOR = 6
    
    .org 0x0000 rjmp RESET
    .org 0x0002 rjmp INTERRUPT_INT0
    .org 0x0004 rjmp INTERRUPT_INT1
    
    	INTERRUPT_INT0:
    		rcall delay
    		sbis PIND,IN_IMPULSATOR
    		rjmp zapal
    			cbi PORTA,LED
    		zapal:
    
    		sbic PIND,IN_IMPULSATOR
    		rjmp zgas
    			sbi PORTA,LED
    		zgas:
    	reti
    
    	INTERRUPT_INT1:
    	reti
    
    	delay: ;ok. 19,5ms
    		ldi R18,255
    		del:
    			ldi R17,100
    			del2:
    				dec R17
    			brne del2 ;1+(1+2)*100+1=302
    			dec R18
    		brne del ;1+(302+1+2)*255+1=77777
    	ret
    RESET:
    ldi R18,low(RAMEND)
    out SPL,R18
    ldi R18,high(RAMEND)
    out SPH,R18
    
    ldi R18,MCUCR_
    out MCUCR,R18
    
    ldi R18,GICR_
    out GICR,R18
    
    ldi R18,0xFF
    out PORTA,R18
    out DDRA,R18
    
    in R16, SFIOR
    ori R16, 1<<PUD
    out SFIOR, R16
    
    ldi R18,(1<<IN_IMPULSATOR)|(1<<PD2)|(1<<PD3)
    out PORTD,R18
    out DDRD,R18
    
    sei
    
    stop:
    rjmp stop
    

    Ten kod powinien zapalać diodę przy kręceniu impulsatorem w jedną stronę, a gasić, gdy kręcimy w drugą. Tak się dzieje, jednak czasem jak kręcę szybko impulsatorem, to źle Atmega rozpoznaje kierunek. Jak dobrze odtłumić drgania styków w tym przypadku ?
  • #10 8765052
    Andrzej__S
    Poziom 28  
    Nie wiem, jak chciałeś osiągnąć detekcję zmiany kierunku odczytując stan jednego pinu. Żeby to osiągnąć, potrzebujesz co najmniej 2 bity w kodzie Greya, czyli na wejście należy podać sekwencję 00, 01, 11, 10, 00, 01 itd. Wtedy zmiana kodu z 01 na 00, z 11 na 01, z 10 na 11, z 00 na 10 będzie oznaczać np. lewe obroty, a zmiana kodu z 00 na 01, z 01 na 11, z 11 na 10, z 10 na 00 - prawe obroty.

    EDIT:
    Zapomniałem dodać, że moim zdaniem stosowanie przerwań do obsługi styków wymagających programowego debouncingu nie jest dobrym pomysłem. Lepiej odczytywać cyklicznie stan portu w przerwaniu timera i po n-krotnym uzyskaniu tego samego wyniku uznać, że stan jest stabilny. Jaki odstęp czasu pomiędzy odczytami i wartość n-krotności należy ustalić doświadczalnie w zależności od rodzaju i stanu styków. Oczywiście nie wolno przesadzić, bo przy zbyt długich czasach i/lub wysokich krotnościach, można gubić krótkie impulsy.
  • #11 8765569
    mirekk36
    Poziom 42  
    maciej_333 napisał:
    ...Załamała mnie Twoja wypowiedź kolego korrus666... Widać programowanie w językach wysokiego poziomu strasznie Cię okaleczyło. Napisz trochę programów w asemblerze, a wyjdzie Ci to na dobre. Zrozumiesz działanie procesora (choć Atmega to już mikrokontroler) i będziesz pisał lepsze programy w swoim C, Javie, lub co gorsza Bascomie.


    OOO Matko! A mnie załamała twoja wypowiedź kolego maciej_333...

    Używając twojego języka, to ciebie z kolei chyba okaleczyły debugery. Może właśnie przez to, że do tak banalnej rzeczy musisz używać aż Debugera - sam nie rozumiesz do końca działania procesora/mikrokontrolera. Zamiast więc kogoś besztać wystarczyło wyjaśnić jak zrobiłeś to na początku. A ja proponuję ci przeprowadzać więcej testów na samym procesorze niż tylko w sumulatorach i debugerach wtedy ty lepiej zrozumiesz działanie procesora i będziesz pisał lepsze programy w swoim "najlepszym z najlepszych" ma się rozumieć języku asembler. Życzę ci więcej dystansu do narzędzia czy języka, którym się dziś posługujesz i szerszego spojrzenia na różne języki programowania. Więcej na tym zyskasz i szybciej się pewnych rzeczy nauczysz.

    Wystarczyłoby żebyś np chociaż raz zadał sobie trud - tak tylko dla przykładu napisania takiego programu w C (nie po to żeby się go zaraz uczyć bo przecież ten język jest beee) , ale po kompilacji widać pięknie kod w asemblerze tego co on zrobił. Gwarantuję ci że szybciej byś się dzieki temu samego asemblera nauczył. Nie wspominając już o tym, że twoje pętle opóźniające idące aż w milisekundy w trakcie przerwań, świadczą, o tym, że na prawdę jak na razie większość twoich programów to tylko asembler ale w symulatorze/debugerze mający niewiele wspólnego z rzeczywistością. Nie bój się sprzętu kolego i innych narzędzi, których nie znasz i nie wyżywaj się na kimś kto w dyskusji chce pomóc ale sam popełni błąd - wygłaszając jakieś bezsensowne teorie o wyższości języków programowania.
  • #12 8765702
    korrus666
    Poziom 40  
    Nie zauważyłem przepisania stałych do odpowiednich rejestrów bo nazwałeś je bardzo podobnie. Mój błąd. A tak w ogóle to nigdy nie napisałem żadnego programu na AVR lub PIC w niczym innym jak tylko w asemblerze i wiem dobrze jak działa procesor. Piszę w asemblerze żeby dokładnie wiedzieć co się dzieje.
  • #13 8765712
    maciej_333
    Poziom 38  
    mirekk36 napisał:
    maciej_333 napisał:
    ...Załamała mnie Twoja wypowiedź kolego korrus666... Widać programowanie w językach wysokiego poziomu strasznie Cię okaleczyło. Napisz trochę programów w asemblerze, a wyjdzie Ci to na dobre. Zrozumiesz działanie procesora (choć Atmega to już mikrokontroler) i będziesz pisał lepsze programy w swoim C, Javie, lub co gorsza Bascomie.


    OOO Matko! A mnie załamała twoja wypowiedź kolego maciej_333...

    Używając twojego języka, to ciebie z kolei chyba okaleczyły debugery. Może właśnie przez to, że do tak banalnej rzeczy musisz używać aż Debugera - sam nie rozumiesz do końca działania procesora/mikrokontrolera. Zamiast więc kogoś besztać wystarczyło wyjaśnić jak zrobiłeś to na początku. A ja proponuję ci przeprowadzać więcej testów na samym procesorze niż tylko w sumulatorach i debugerach wtedy ty lepiej zrozumiesz działanie procesora i będziesz pisał lepsze programy w swoim "najlepszym z najlepszych" ma się rozumieć języku asembler. Życzę ci więcej dystansu do narzędzia czy języka, którym się dziś posługujesz i szerszego spojrzenia na różne języki programowania. Więcej na tym zyskasz i szybciej się pewnych rzeczy nauczysz.

    Wystarczyłoby żebyś np chociaż raz zadał sobie trud - tak tylko dla przykładu napisania takiego programu w C (nie po to żeby się go zaraz uczyć bo przecież ten język jest beee) , ale po kompilacji widać pięknie kod w asemblerze tego co on zrobił. Gwarantuję ci że szybciej byś się dzieki temu samego asemblera nauczył. Nie wspominając już o tym, że twoje pętle opóźniające idące aż w milisekundy w trakcie przerwań, świadczą, o tym, że na prawdę jak na razie większość twoich programów to tylko asembler ale w symulatorze/debugerze mający niewiele wspólnego z rzeczywistością. Nie bój się sprzętu kolego i innych narzędzi, których nie znasz i nie wyżywaj się na kimś kto w dyskusji chce pomóc ale sam popełni błąd - wygłaszając jakieś bezsensowne teorie o wyższości języków programowania.


    Nie mówię tu o wyższości takiego czy innego języka programownia. Działanie procesora znam i rozumiem. Wcześniej pracowałem z 8051. Zrezygnowałem z niego z kilku powodów, jednym z nich był brak możliwości debuggowania (choć jest jakaś wersja 8051 z JTAG, ale zbyt droga). Kiedyś długo szukałem błędu w pewnym programie i to było dość bolesne. Procedury obsługi przerwań powinny być możliwie krótkie, ale skoro impulsator ma zastosowanie do nastawy pewnych parametrów, to w czasie ich nastawy inne przerwania nie muszą być u mnie obsługiwane. To wystarczy... Sam JTAG zastosowałem tu trochę też dla zabawy, bo zabawa nim jest Ciekawa. Można zmusić mikrokontroler niemal do wszystkiego.

    Andrzej__S napisał:
    Nie wiem, jak chciałeś osiągnąć detekcję zmiany kierunku odczytując stan jednego pinu. Żeby to osiągnąć, potrzebujesz co najmniej 2 bity w kodzie Greya, czyli na wejście należy podać sekwencję 00, 01, 11, 10, 00, 01 itd. Wtedy zmiana kodu z 01 na 00, z 11 na 01, z 10 na 11, z 00 na 10 będzie oznaczać np. lewe obroty, a zmiana kodu z 00 na 01, z 01 na 11, z 11 na 10, z 10 na 00 - prawe obroty.

    To o czym mówisz to chyba enkoder. Urządzenie jakie ja mam działa generując dwa sygnały na dwóch liniach. Trzeci pin jest wspólny - u mnie połączony do masy. Wspomniane sygnały są prostokątne i przesunięte w fazie względem siebie o 1/4 okresu. Dlatego też jeżeli wykryję zbocze opadające na jednym wyprowadzeniu impulsatora, to na drugim będzie 0 lub 1 - zależnie od kierunku obrotów. Zwyczajnie to który sygnał pojawia się wcześniej zależy od kierunku obrotów. Zresztą gdyby miał tam się pojawiać kod Greya, to pewnie dałoby się poszczególne stany wykryć omomierzem. Tak jednak nie jest.

    [edit]
    Mój impulsator zachowuje się tak jak ten model, choć to co ja mam jest firmy ALPS. Chętnie zrobiłbym to z Timerem, ale jak ? Ten sposób z przerwaniem znalazłem kiedyś właśnie na elektrodzie.
  • #14 8766196
    Andrzej__S
    Poziom 28  
    Cytat:

    Wspomniane sygnały są prostokątne i przesunięte w fazie względem siebie o 1/4 okresu.

    No to jest właśnie 2-bitowy kod Greya. Przeanalizuj sobie jakie kombinacje stanów logicznych pojawią się po kolei i porównaj z tym co napisałem w poprzednim poście. Zresztą zobacz Electrical Characteristics w dokumencie, do którego podałeś link w poprzednim poście.

    Cytat:

    Dlatego też jeżeli wykryję zbocze opadające na jednym wyprowadzeniu impulsatora, to na drugim będzie 0 lub 1 - zależnie od kierunku obrotów. Zwyczajnie to który sygnał pojawia się wcześniej zależy od kierunku obrotów.

    No to ma sens. Problem w tym, że nie zastanowiłem się dokładnie co to jest IN_IMPULSATOR. Sądziłem, że w przerwaniu robisz debouncing pinu, na którym pojawiło się przerwanie.
    Jeżeli nie masz na wyjściu impulsatora poprawnego sygnału prostokątnego bez drgań styków, proponuję jednak zrezygnować z przerwań INT. Chyba, że potrzebujesz tylko rozróżnienie kierunku bez zliczania impulsów. Wtedy może się udać.
    Cytat:

    ...czasem jak kręcę szybko impulsatorem, to źle Atmega rozpoznaje kierunek.

    Jeżeli masz na wyjściu impulsatora poprawny sygnał bez drgań styków lub zastosujesz sprzętowy debouncing, to rozwiązaniem problemu powinno być zmniejszenie lub może nawet usunięcie 'delay' z procedury obsługi przerwania.
  • #15 8766635
    maciej_333
    Poziom 38  
    Muszę rozpoznawać kierunek, ale nie mogę gubić impulsów (skoków). Impulsator będzie służył do nastawy pewnych parametrów. Ma to być na zasadzie jeden skok dekrementacja/inkrementacja - zależnie od kierunku. Dodatkowo impulsatorem będę sterował pewne menu wykonywanego urządzenia. Mój impulsator ma też wbudowany przycisk, więc jest do tego wręcz stworzony. Co do sprzętowego odtłumiania drgań myślałem o jakichś kombinacjach z przerzutnikiem RS, ewentualnie dwa NE555 jak przerzutniki monostabilne. MC14490 jest ciekawy, ale go nie mam.
  • #16 8767128
    Andrzej__S
    Poziom 28  
    Gdyby założyć, że w momencie zmiany na jednym pinie, na drugim jest stan stabilny, to może udałoby się to zrobić tak jak próbowałeś. Myślę tylko, że i tak powinieneś nieco zmienić procedurę obsługi przerwania. Po pierwsze po delay należałoby najpierw sprawdzić stan pinu, który wywołał przerwanie, żeby stwierdzić, czy to nie był jakiś stan niestabilny. Po drugie w czasie 'delay', kiedy jest prawdopodobne drganie styków, może zostać ustawiona flaga tego przerwania, w związku z czym należałoby na koniec obsługi przerwania wyzerować jego flagę (poprzez wpisanie 1, jak już wyżej pisałem), by po zakończeniu program nie wchodził do obsługi przerwania ponownie.
    Spróbuj to jakoś przetestować. Jak zmniejszysz nieco wartość opóźnienia, powinno być lepiej przy szybszym kręceniu. Obawiam się jednak, że i tak taki program może nie działać zbyt stabilnie. Jak znajdę nieco więcej czasu, spróbuję opisać mniej więcej taki algorytm na timerze. Robiłem kiedyś taki dwukierunkowy licznik impulsów w assemblerze, ale już za dokładnie tego nie pamiętam.
REKLAMA