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

[Atmega16][C][WinAvr] Problem z obsługą dwóch przerwań zew.

melersan 25 Kwi 2009 17:36 2327 7
  • #1 6455783
    melersan
    Poziom 11  
    Witam,

    od pewnego czasu borykam się z pewną trudnością, a mianowicie obsługą dwóch przerwań zewnętrznych, z czego jedno ma byc wykorzystywane podczas obsługi drugiego.
    Projekt to odcięcie zapłonu z zamkiem szyfrowym. Po krótce:
    W momencie załaczenia stacyjki na on, ma wyśwoietlać się komenda podania pinu itd, po wpisaniu na tranzystor sterujący przekaźnikiem zostaje wysłany stan wysoki i pompa paliwa dostaje prąd. Jednakże przy wyłaczeniu stacyjki atmega ma przejść w stan power-down(tego jeszcze nie zaimplementowałem), w czasie jazdy ma wyświetlać czas i temp.
    O ile funkcje zawarte w mainie działały, o tyle w przerwaniu wszystko głupieje, ale najczęściej przerwanie się nie wykonuje...

    Czy ktos mógłby rzucić okiem, czy da się to tak jak to zrobilem wykonać? moj angielski nie jest najlepszy więc coś może przeoczyłem w datasheecie lub pomocy WinAvr.


    Przerwanie z klawiatury(kolumny sa podpięte pod bramke and) obsługiwane są przy opadającym zboczu, Przerwanie ze stacyjki przy dowolnej zmienie (z czego będzie zabezpieczenie 60 sekundowe przed przypadkowym zgaśnięciem silnika)

    Do oceny właściwie tylko te pliki się przydadza:

    main.c:
    #include "lcd.h"
    #include "keyboard.h"
    #include "globals.h"
    #include "pcf8583.h"
    #include "pin.h"
    
    
    void main(void)
    {
    	writePin();
    	LCD_ADD = 0xFF;	
    	LCD_PORT = 0xFF;
    	KEY_ADD = 0xF8;
    	KEY_PORT = 0x07;
    	
    	STER_CLR; //odcina zapłon
    	
    	lcdInit();
    	i2cSet();
    	INT_KEY;
    	INT_IGNIT;
    	
    	sei();
    	
    	//resetPcf();
    
    	while(1)
    	{
    		lcdString("lalala");//przerwanie go nie rusza i wykonuje sie cały czas
    	}
    
    	
    }
    
    ISR(INT1_vect, ISR_NOBLOCK)
    {
    	pinLoop(); //wprowadzanie pinu (składa się z kilku funkcji);
    	lcdCommand(CLEAR);
    	while(1)
    	{//wyswietlanie godziny i daty na wyświetlaczu
    		dispClock();
    		dispCalendar();
    		lcdCommand(0xCB);
    		lcdString("T=25C");
    		//_delay_ms(200);
    	}
    }
    ISR(INT0_vect)
    {
    	keyCheck();
    	KEY_PORT = 0x0F;
    }


    globals.h:
    #ifndef __GLOBALS_H__
    #define __GLOBALS_H__
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    #ifndef F_CPU
    #define F_CPU 16000000
    #endif
    
    
    /*********GLOBAL BEGIN**************/
    unsigned char sign; //variable for printing signs on LCD during operations
    unsigned char button; //variable for giving information about pushing buttons
    unsigned char error; //error=0 - wthout errors, error=1 - PIN error, error=2 - PIN change (if passed -> STER_SET)
    /*********GLOBAL END****************/
    
    
    /*********STER BEGIN****************/
    #define STER_SET DDRD |= _BV(7); PORTD |= _BV(7)
    #define STER_CLR DDRD |= _BV(7); PORTD &= ~_BV(7)
    /*********STER END******************/
    
    
    /*********INTERRUPTS BEGIN**********/
    #define INT_KEY MCUCR |= _BV(1);MCUCR &= ~_BV(0);GICR |= _BV(6) //fall
    #define INT_IGNIT MCUCR &= ~_BV(3);MCUCR |= _BV(2);GICR |= _BV(7) //changing
    /*********INTERRUPTS END************/
    
    #endif
  • #2 6455957
    dawid512
    Poziom 32  
    Przerwanie powinno być krótkie więc zapomnij w ogóle o wykonywaniu jakichkolwiek funkcji w nim zawartych. Ustawiaj sobie jakąś flagę która będzie informacją że przerwanie wystąpiło.
  • #3 6459428
    marenc
    Poziom 24  
    Dołączając moduł #include<avr/interrupt.h> możesz stosować deklarację SIGNAL i INTERRUPT. SIGNAL blokuje pozostałe przerwania na czas jego obsługi, a INTERRUPT nie.

    Osobiście nie stosowałem INTERRUPT, ale sam zastanawiałem się niedawno w jaki sposób będzie interpretowana komenda RETI(assembler) podczas jej wywołania z przerwania uruchomionego w innym przerwaniu.

    Teoretycznie wywołanie przerwania odkłada na stos adres PC(licznik kodu), więc nie powinno być problemu - daj znać o rezultatach, to nie będę musiał robić testów ;)
  • #4 6459480
    Freddie Chopin
    Specjalista - Mikrokontrolery
    marenc napisał:
    Dołączając moduł #include<avr/interrupt.h> możesz stosować deklarację SIGNAL i INTERRUPT. SIGNAL blokuje pozostałe przerwania na czas jego obsługi, a INTERRUPT nie.


    Po pierwsze nie INTERRUPT tylko ISR, po drugie obydwa te makra nic nie robią z flagą GIE, więc przerwania są ZABLOKOWANE. Jedynym sposobem ich odblokowania jest skorzystanie z makra ISR i podanie mu parametru ISR_NOBLOCK

    Dokumentacja do avr-libc, opis nagłówka interrupt.h

    4\/3!!
  • #5 6459516
    marenc
    Poziom 24  
    Kiedyś stosowałem INTERRUPT i działało, ale przejrzałem plik i faktycznie tam nie ma takiej deklaracji ...

    A jak będzie z wywoływaniem przerwania w przerwaniu(nie będzie problemu)? Zastanawiałem się nad priorytetem przerwań, bo chyba w '51 można jakoś to poustawiać...
  • #6 6459525
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Priorytet jest zafixowany - po numerze wektora, tak jak zwykle. Co do przerwań zagnieżdżonych, to ze strony kompilatora problemu nie będzie, procek też zrobi co mu każesz, niemniej jednak napisanie kodu który to przeżyje jest dosyć skomplikowane [;

    Co do INTERRUPT, to może w jakiejś starej wersji or sth - teraz w każdym razie zalecane jest ISR()

    4\/3!!
  • #7 6464958
    melersan
    Poziom 11  
    Dzięki za odpowiedzi:)

    Faktycznie głupota wykonywać funkcje trwające kilka minut w przerwaniu ;] (ahhh te początki ;d). Postaram się to zrealizować w mainie, a swoją drogą czy zawsze w miarę postępów nad projektem muszą powstawać kolejne trudności? :P

    Pozdrawiam:)
  • #8 6465038
    Dr.Vee
    VIP Zasłużony dla elektroda
    melersan napisał:
    Faktycznie głupota wykonywać funkcje trwające kilka minut w przerwaniu ;] (ahhh te początki ;d).

    Twoja procedura obsługi INT1 bije na głowe wszystkie inne, bo nigdy się nie kończy (while(1) ...)

    Zastosuj pętlę główną w main + automat stanów.

    Poza tym przy takiej zawartości pliku "globals.h" każdy moduł (plik .c) projektu będzie miał własną kopię zmiennych sign, button i error - o ile oczywiście linker na to pozwoli. Prawidłowo powinieneś mieć:
    /* w jednym pliku .c */
    unsigned char jakas_zmienna;
    
    /* w pliku globals.h */
    extern unsigned char jakas_zmienna;
    
    /* w innych plikach .c */
    #include "globals.h"


    Pozdrawiam,
    Dr.Vee
REKLAMA