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

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

25 Kwi 2009 17:36 2219 7
  • 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:
    Code:
    #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:
    Code:
    #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
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Relpol przekaźniki nadzorczeRelpol przekaźniki nadzorcze
  • 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.
  • Relpol przekaźniki nadzorczeRelpol przekaźniki nadzorcze
  • 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 ;)
  • 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!!
  • 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ć...
  • 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!!
  • 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:)
  • 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ć:
    Code:
    /* 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