Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

PIC 16F877A przerwanie zewnętrzne int - problem z obsługą

lisek_lichu 17 Lip 2010 01:22 2882 7
  • #1 17 Lip 2010 01:22
    lisek_lichu
    Poziom 11  

    Witam,

    zbudowałem prosty układ do testowania przerwania zewnętrznego INT/RB0. Według moich założeń układ po wciśnięciu microswitcha powinien wygenerować przerwanie i naprzemiennie zapalać i gasić diodę na porcie D [RD0].

    Problem polega na tym, że nie za każdym razem po wciśnięciu microswitcha dioda reaguje.

    Przeszukując forum trafiłem na podobny temat Link w którym wyczytałem parę przydatnych informacji ale nie rozwiązałem mojego problemu do końca.

    Przerwanie powinno wystąpić przy opadającym zboczu [INTEDG = 0]

    Po podłączeniu zasilania na pinie INT podawane jest cały czas wysokie napięcie. Po wciśnięciu microswitcha (NO - normalnie otwarty) pin INT jest podłączany do GND i otrzymujemy opadające zbocze które powinno wywołać przerwanie. Przerwanie jest czasami wywoływane bo dioda na porcie D zapala się i gaśnie ale nie działa to w 100% bo czasami po wciśnięciu przycisku dioda nie reaguje.

    Dodatkowo wyeliminowałem drgania styku w microswitchu poprzez dodanie pętli opóźniającej w obsłudze przerwania. Wystarczy jedno drgnięcie przy wciskaniu przycisku by dać impuls do przerwania i przejście do jego obsługi a w obsłudze pod koniec dodałem 20ms pętlę która opóźnia wyjście z obsługi przerwania aby przez przypadek nie wchodzić kilka razy do obsługi za jednym przyciśnięciem microswitcha.

    Zamieszczam kod programu oraz schemat podłączenia może ktoś z was zauważy to czego ja nie zauważam.

    W kodzie wykorzystałem makra ze strony Link które ułatwiają przełączanie się pomiędzy bankami. Wykorzystuję proste polecenie BANK0 lub BANK1 aby przełączać banki.

    Code:

    ;***** COMPILATION MESSAGES & WARNINGS *****
       ERRORLEVEL -302    ; register in operand not in bank 0

    ;***** PROCESSOR DECLARATION & CONFIGURATION *****
       LIST P=16F877A, R=DEC
       #INCLUDE "P16F877A.INC"
       __CONFIG _CP_OFF &_WDT_OFF &_BODEN_ON &_PWRTE_ON &_HS_OSC &_WRT_OFF &_LVP_OFF &_DEBUG_OFF &_CPD_OFF
       
    ;***** MEMORY STRUCTURE *****
         ORG     0x00         ; wektor zerowania procesora
         goto    MAIN

       ORG     0x04         ; wektor przerwania
       goto   ISR
       
    ;***** REGISTER DECLARATION *****
    TEMP_W      equ   0x20
    TEMP_STATUS   equ   0x21
    reg_delay_1   equ 0x22
    reg_delay_2   equ 0x23
       




    ;***** INCLUDE FILES *****
       #include "m_bank.asm"

    ;***** INTERRUPT SERVICE ROUTINE *****
    ISR:
       bcf      INTCON, GIE         ; wyłączamy przerwania
       movwf   TEMP_W            
       swapf   STATUS, W
       movwf   TEMP_STATUS
       
       
       clrf   STATUS
       btfsc   INTCON, INTF      ; sprawdzamy czy przerawnie z INT
       goto   INT_INT
       goto   INT_END

    INT_INT:
       BANK0
       movlw   0xFF            ; same jedynki
       xorwf   PORTD, F              ; negujemy poprzednią wartość [zapalamy albo gasimy]
       bcf      INTCON, INTF
       goto   INT_END
       
    INT_END:
       ; opoznienie 20ms aby wyeliminować drgania styków
       movlw   .241
       movwf   reg_delay_1
       movlw   .52
       movwf   reg_delay_2
    delay_loop   
       decfsz   reg_delay_1,F
       goto   delay_loop
       decfsz   reg_delay_2,F
       goto   delay_loop
       nop
       nop
       ; koniec opoznienia 20ms
       
       swapf   TEMP_STATUS, W
       movwf   STATUS
       swapf   TEMP_W, F
       swapf   TEMP_W, W
       bsf      INTCON, GIE         ; włączamy przerwania
       retfie

    ;************** MAIN **************
    MAIN:
       BANK1
       movlw   00110000b         ; opadajace zbocze na pinie RB0/INT wywoluje przerwanie
       movwf   OPTION_REG
       
       movlw   0xFF
       movwf   TRISB            ; jako wejscie
       clrf   TRISD            ; jako wyjscie
       
       BANK0
       clrf   PORTD            ; wylaczenie diody na porcie A
       
       BANK1
       movlw   10010000b
       movwf   INTCON            ; włączamy tylko przerwania z INT i cały układ przerwań

       goto   $               ; petla nieskonczona

       end


    PIC 16F877A przerwanie zewnętrzne int - problem z obsługą

    0 7
  • #2 17 Lip 2010 17:59
    adamwesola
    Poziom 24  

    Zamiast przerabiać Twój, podam taki przykład - diodę dałem na RC0, by uniknąć przełączania banków w przypadku portu D.

    Code:
       LIST P=16F877A
    
       #INCLUDE "P16F877A.INC"
       __CONFIG _CP_OFF &_WDT_OFF &_BODEN_ON &_PWRTE_ON &_XT_OSC &_WRT_OFF &_LVP_OFF &_DEBUG_OFF &_CPD_OFF

       org   0
           goto    MAIN
       org   4
    ;rozpoznawanie zrodla przerwanie jest zbedne, mozliwe jest tylko z RB0
    ;w tym przypadku zachowanie i odtwarzanie STATUS i W jest niepotrzebne
    ;zerowanie GIE jest niepotrzebne, przyjecie przerwania go zeruje
    ;natomiast polecenie RETFIE go ustawia
          clrf   TMR0   
          btfss   TMR0,7
           goto   $-1         ;czekaj 32ms, dla 4MHz
          incf   PORTC,F      ;zapalenie/zgaszenie - dioda na RC0
          
    czyt_port   movfw   PORTB
             xorlw   .255      
             btfss   STATUS,Z   ;puszczony przycisk na RB0 ?
             goto   czyt_port   ;nie !
             bcf      INTCON,INTF      ;kasowanie flagi, mozliwe tylko wtedy gdy dokonasz odczytu portu
             retfie                   
    ;================================      
    MAIN      clrw
             tris   PORTC   ;caly port - wyjscia
             
    ;po resecie procesora, PORTB (inne takze) sa ustawiane jako wejscia
    ;wiec ponowna konfiguracja na wejscia jest zbedna i niczego nie zmienia
          
             movlw    7      ;podzielnik 1:256 do TMR0, podciaganie wlaczone
             option            ;przerwanie na opadajace zbocze
             movlw   90      ;set GIE oraz INTE
             movwf   INTCON   ;przerwanie wlaczone, juz czuwa
    ;---------------------------         
          sleep         ;uspiony, obudzi go przerwanie
           goto   $-1
    ;-----------------------
       end

    0
  • #3 18 Lip 2010 00:02
    lisek_lichu
    Poziom 11  

    hmmm

    dzięki za podpowiedzi co do kodu

    adamwesola napisał:

    ;rozpoznawanie zrodla przerwanie jest zbedne, mozliwe jest tylko z RB0
    ;w tym przypadku zachowanie i odtwarzanie STATUS i W jest niepotrzebne
    ;zerowanie GIE jest niepotrzebne, przyjecie przerwania go zeruje
    ;natomiast polecenie RETFIE go ustawia


    w tym przypadku rozpoznawanie źródła przerwania jest niepotrzebne ale robiłem to żeby później rozbudowywać o kolejne.
    Dlatego tez zapamiętywałem STATUS i W - co dla tego przykładu nie było potrzebne.
    Co do zerowanie GIE i ustawiania na końcu to racja ale wstawiłem to bo gdzieś pisali że lepiej tak zrobić "kombinowałem na wszystkie strony żeby znaleźć dlaczego mi to nie działa to i takie rzeczy wpisywałem w nadziei że pomoże"


    TMR0 używasz jako licznika aby wyeliminować drgania styków [32ms]
    po każdej inkrementacji portu C bit0 zmienią się z 1 na 0 i z 0 na 1 więc mruga

    tu wszystko gra

    i widzę że sprawdzasz na sztywno czy przycisk jest wciśnięty czy nie i dopiero wtedy kończysz obsługę przerwania. Czy tak trzeba robić?? Przecież po to jest bit INTF w rejestrze INTCON aby sprawdzić czy przerwanie zostało wywołane wciśnięciem przycisku.

    ale nie rozumiem dlaczego

    adamwesola napisał:

    bcf INTCON,INTF ;kasowanie flagi, możliwe tylko wtedy gdy dokonasz odczytu portu


    A jak się nie odczyta portu to nie można wyzerować tego bitu? Z tego co wiem to chyba powinno się to robić przy przerwaniu generowanym zmianą stanu na liniach RB4 - RB7 portu PORTB. Wtedy trzeba odczytać port a następnie wyzerować flagę bo inaczej kolejna zmiana nie zostanie zauważona.

    Spróbuję zwiększyć opóźnienie z 20ms do 32 lub więcej aby wyeliminować drgania styków może to coś da. Bo nie mam pojęcia czemu dioda nie reaguje prawidłowo.

    pozdrawiam i dzięki za pomoc. Ewentualnie jakbyś miał czas to powiedz co powinienem zmienić w moim kodzie bo może czegoś nie wyłapałem

    Dodano po 1 [godziny] 8 [minuty]:

    Po wyeliminowaniu diody LED3 problem zmniejszył się bardzo. Teraz przy wciskaniu switcha działa prawie zawsze. Prawie - bo raz na 20-30 wciśnięć nie zadziała.
    Ktoś wie dlaczego ta dioda powodowała takie zachowanie.

    Dodam, że cały układ montuję na płytce stykowej. Taka płytka pewnie na każdym połączeniu powoduje drgania. im mniej elementów podłączonych do switcha tym mniej styków które mogą drgać przy poruszaniu - a może się mylę.

    sprawdzę to inaczej. zamiast switcha podłączę drugi mikrokontroler i zaprogramuję do aby zmieniał stan na RB0 pierwszego mikrokontrolera. wtedy drgań nie będzie i zobaczę czy będzie działać :P

    pozdrawiam

    0
  • #4 18 Lip 2010 00:06
    Doktor_UC
    Poziom 9  

    Program nie jest zły, tylko pomysł z przełączaniem stanu linii z diodą - powiedziałbym - nietrafiony. Jak pewnie zauważyłeś, zwiększenie opóźnienia w pętli wyeliminowało drgania styków, ale przerwanie ma przecież służyć do maksymalnie szybkiej reakcji na zdarzenie. Zaświecenie diody po wykryciu opadającego zbocza na RB0 jest wystarczającym sygnałem, że obsługa przerwania jest dobra.

    0
  • #5 18 Lip 2010 10:58
    gaskoin
    Poziom 38  

    ja mam pytanie trochę z innej beki. Po co się stosuje rezystor szeregowo przy kwarcu? spotkałem się również z rezystorem równoległym między kwarcem a µC

    0
  • #6 18 Lip 2010 17:50
    Doktor_UC
    Poziom 9  

    Rysunek z PICmicro™ Mid-Range MCU Family Reference Manual

    PIC 16F877A przerwanie zewnętrzne int - problem z obsługą

    Dyskusja o zasadności umieszczania rezystora znajduje się w paragrafie 2.3.3.1 tegoż manuala. Ogólnie można powiedzieć, że rezystor ma ułatwić start oscylatora.

    0
  • #7 18 Lip 2010 17:55
    adamwesola
    Poziom 24  

    Sprawdzam czy przycisk zostal puszczony i dopiero wtedy kończę przerwanie. Czy tak trzeba robić ?? niekoniecznie, oczekiwanie na puszczenie klawisza można zrobić w progu glównym, lub spróbuj wogóle to pominąć, teoretycznie powinno dzialać bezblędnie z opóźnieniem na drgania styków.
    Nie skasujesz INTF oraz RBIF, bez odczytania stanu portu, a bez tego po instrukcji RETFIE, natychmiast znów wystąpi przerwanie, rzecz jasna te, które jest wlączone (INTE, RBIE).

    0
  • #8 19 Lip 2010 21:33
    lisek_lichu
    Poziom 11  

    OK po paru modyfikacjach program zaczął lepiej działać ale nadal nie działa w 100% Co któreś kliknięcie dioda tylko mrugnie. Czyli np włączy i od razu wyłączy albo wyłączy i od razu włączy tak jakby wykonane zostały 2 przerwania.

    według programu działanie powinno być takie:

    • po podłączeniu zasilania dioda się nie pali
    • przy wciśnięci guzika (opadające zbocze) dioda powinna się zapalić
    • przy puszczeniu guzika nic się nie powinno dziać (i tu właśnie chyba tkwi błąd)

    Przy puszczaniu guzika styki tez mogą zadrżeć i wtedy wykonywana jest obsługa przerwania. jest jakaś możliwość wyeliminowania takiego zachowania?

    Wiem że jest jakaś możliwość nie programowa czyli dodanie jakiegoś opornika i kondensatora ale nie wiem jak podłączyć te elementy do przycisku. Po takich modyfikacjach nie trzeba by było robić opóźnień programowo aby wyeliminować drgania styków.

    pozdrawiam Szymon

    0