Problem z przerwaniem zewnetrznym ATmega 32

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Problem z przerwaniem zewnetrznym ATmega 32

Post autor: reticool » 07 cze 2008, 18:53

hmm, to moze zaczne od poczatku... programuje ATmege32 w zestawie ZL3AVR. przerwanie zewnetrzne INT0 ma wystepowac po wcisnieciu przycisku. podpialem jedno wyjscie do +VCC a drugie do nozki procesora INT0.
fragmenty kodu dotyczace timera wygladaja tak:

Kod: Zaznacz cały

GICR |= _BV(INT0);  

// co do ustawien rejestru MCUCR
//probowalem juz ustawiac ISC01, ISC00 
//na wszystkie 4 sposoby

sei(); 
i funkcja obslugi przerwania:

Kod: Zaznacz cały

SIGNAL (SIG_INTERRUPT0) 
{
	piszilcd(0x01);    //czysc lcd
	pisz_string((char*)"jakis tekst"); 
}
i efekt jaki otrzymuje jest taki ze napis "jakis tekst" pojawia sie caly czas jakby to przerwanie ciagle wystepowalo. dopiero jak wcisne guzik to nic sie nie dzieje jakby go nie bylo. jak zamiast INT0 podpialem diode to jak naciskam to swieci a jak puszcze to nie. dodam ze to moja pierwsza samodzielna przygoda z mikroprocesorem wiec prosze o pomoc dosc lopatologiczna. z gory dziekuje

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 07 cze 2008, 19:28

reticool pisze:podpialem jedno wyjscie do +VCC a drugie do nozki procesora INT0.
Wyjście czego? bo jakoś niejasno napisane.
reticool pisze:Jak zamiast INT0 podpialem diode to jak naciskam to swieci a jak puszcze to nie. dodam ze to moja pierwsza samodzielna przygoda z mikroprocesorem wiec prosze o pomoc dosc lopatologiczna. z gory dziekuje
Zamiast INT0 diode? tzn? Trochę nie jasno to wszystko. Zrób tak:

Podepnij przycisk do masy jednym końcem a drugim do INT0, ustaw w programie INT0 jako wejście z podciągnięciem. Rejestry ustaw:

Kod: Zaznacz cały

MCUCR|=(1<<ISC01);
GICR|=(1<<INT0);
a w obsłudze przerwania zrób żeby ci zapalał leda na jakimś porcie albo wystawiał zmienną jakąś na port którą w przerwaniu będziesz inkrementował. Do portu na który będziesz wysyłał tą zmienną podłącz ledy i sprawdź czy zadziała.

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 07 cze 2008, 20:06

snow pisze: ustaw w programie INT0 jako wejście z podciągnięciem
w programie w ktorym pisze kod? uzywam avr studio, gdzie to sie ustawia? bo szczerze mowiac nie mam zielonego pojecia...

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 07 cze 2008, 20:24

piszilcd(0x01); //czysc lcd
pisz_string((char*)"jakis tekst");
Osobiście pisze w asemblerze , i nie znam podprogramów napisanych w C i te etykiety nic mi nie mówią, ale z tego co widzę to program zachowuje się jak najbardziej poprawnie. Zauważ , że wyświetlacz LCD , nie wymaga odświeżania i raz wpisany tekst będzie tam tkwił aż do , kolejnego czyszczenia / nadpisania ( to obraz zawartości komórek ). W twoim przypadku , czyszczenie LCD zajmie krótką chwilkę i nawet tego nie zauważysz , więc dla sprawdzenia wrzuć jakieś krótkie opóźnienie pomiędzy te dwie instrukcje. ( Pisząc opóźnienie , mam na myśli chociażby dwie pętle zagnieżdżone w sobie )

[EDIT] Aj , spojrzałem na sterownik i bazowo występuje inkrementacja komórki po zapisaniu.
Rozumiem , ze ten tekst wyświetla się ciągiem cały czas ?
Jeśli tak , to spróbuj do obsługi przerwania dopisać :

GIFR |= 1<<INTF0 - Chodzi o ustawienie bitu INTF0 w rejestrze GIFR ( wyzerowanie flagi zgłoszenia przerwania ).

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 07 cze 2008, 20:44

moze troche niejasno sie wyrazilem, on sie caly czas na nowo pojawia na lcd, tak jakby ciagle wykonywal funkcje przerwania, raz za razem. dodalem i nic, dalej to samo

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 07 cze 2008, 20:48

W sensie , ekran wyświetlacza wypełnia się cały tymi frazami ? Bo tak by się zachował gdyby przerwania występowały cały czas ( z pominięciem pierwszej instrukcji po skończeniu podprogramu przerwania która jest zawsze wykonywana , przed ewentualnie kolejnym ) .

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 07 cze 2008, 20:49

w sensie napis pojawia sie, niknie na ulamek sekundy, pojawia sie, niknie, pojawia sie itd itd

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 07 cze 2008, 20:56

No to rzeczywiście się zgadza . Właśnie doczytałem , że sterownik Twojego wyświetlacza bo wyczyszczeniu ustawia się na pierwszej pozycji - więc wszystko pasuje.

A gdzie on wraca , po wykonaniu przerwania ? wklej całego maina najlepiej . Pamiętaj o tym , że po wywołaniu przerwania zewnętrznego czy jakiegokolwiek innego , adres powrotu zostaje zapisany na stosie ( w asemblerze ustawia się to ręcznie , nie wiem jak w Twoim przypadku ), i po zakończeniu przerwania wracasz do wcześniej wykonywanego programu.

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 07 cze 2008, 21:01

main oprocz konfiguracji lcd i przerwan sklada sie z pustej nieskonczonej petli while:

Kod: Zaznacz cały

while(1);
wiec powinien tam siedziec...

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 07 cze 2008, 21:22

To powoli tracę , pomysły . To może spróbuj zakomunikować przerwanie , jeszcze innym sposobem . Podczas wywołania przerwania ustaw w przykładowo zmiennej a , drugi bit ( koniecznie na początku wyzeruj , bo flash kontrolera ma przypadkowe wartości ) czyli dziesiętnie będzie to liczba 2, a w pętli while daj warunek coś via :
IF( a &= 2 ) { GICR=0; } bądź po prostu if ( a== 2 ) { GICR=0; }

Chociaż to raczej nie pomoże , bo po powrocie procesor ma możliwość wykonania tylko jednej
operacji przed ewentualną obsługą następnego przerwania.
Cholera , warunkiem rozpoczęcia wykonywania przerwania jest ustawiona flaga INTF0 , więc zerowanie ręczne na szarym końcu powinno dać jakiś rezultat a ,że przerwanie jest wykonywane znów to ta flaga musi ponownie się ustawiać.
Ostatnio zmieniony 08 cze 2008, 8:31 przez atmega, łącznie zmieniany 1 raz.

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 07 cze 2008, 21:41

wiec tak sie dzialo.. w obsludze przerwania mialem wyswietlanie na lcd i potem zmiana zmiennej. w mainie byla petla ktora zalezala od tej zmiennej. program kilkakrotnie wyswietlil napis (wiec obsluge przerwania przerywalo nastepne przerwanie) az wkoncu wyskoczyl z tej petli po wylaczeniu przerwan

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 07 cze 2008, 21:47

Małe sprostowanie : Nie można domyślnie przerwać przerwania innym ze względu na fakt , ze po przejściu do wykonywania procedury przerwaniowej , wyłączone jest globalne pozwolenie.

ZbeeGin

Post autor: ZbeeGin » 08 cze 2008, 7:48

Co do pierwotnej wersji to podłącz sygnał do INT0 po bożemu. Czyli przycisk z INT0 do plusa (jeśli już tak chcesz) i jeszcze rezystor 1k ściągający INT0 do masy. Przecież nie wysterowane wejście pływa i procesor zinterpretuje go jako stan wysoki.

Lepiej jednak podłączyć przycisk jedną końcówką do masy, a drugą do INT0, a dodatkowo dołączyć rezystor 4,7k do plusa który wymuszał będzie stan wysoki na wejściu przerywającym. Oczywiście trzeba skonfigurować sposób reakcji na "opadające zbocze (falling edge)" lub "niski poziom logiczny (low level)". Z tym, że przy niskim poziomie przerwanie będzie zgłaszane stale jak przycisk będzie naciśnięty.

Skoro piszesz w AVR Studio z wykorzystaniem AVRGCC to zrób symulację programu. Zdarzyło Mi się, że optymalizacja programu z GCC zepsuła cały efekt.
Na potrzeby symulacji napisałem taki programik:

Kod: Zaznacz cały

#include <avr/io.h>
#include <avr/interrupt.h>

//--------------------------------------------------------------
//--------------------------------------------------------------
SIGNAL(SIG_INTERRUPT0) 
{ 
  PORTB = ~PORTB;                 // zamieniaj stan portu
}

//##############################################################
int main(void)
{
  DDRB = 0xFF;                    // portd jako wyjście
    
  MCUCR = (1<<ISC01)|(1<<ISC00);  // zbocze narastające  
  //MCUCR = (1<<ISC01);             //zbocze opadjaące
  
  GICR = (1<<INT0);               // włącz przerwania z INT0
  sei();                          // przerwania globalne włączone

  while(1)
    {
       asm("nop");                // na potrzeby symulacji
    }
  return(0);
}
Zmiany na PIND.2 powodują wywoływania przerwania.

reticool
-
Posty: 9
Rejestracja: 07 cze 2008, 18:37
Lokalizacja: woj. Małopolskie

Post autor: reticool » 08 cze 2008, 15:23

no ale jest taki problem maly... nie dysponuje zadnymi rezystorami, mam tylko ten zestaw ZL3AVR i kilka kabelkow, i w dodatku to wszystko pozyczone

atmega
-
Posty: 26
Rejestracja: 07 cze 2008, 20:17
Lokalizacja: Gdańsk

Post autor: atmega » 08 cze 2008, 15:32

Tutaj koledze chodzi o PULL-UP , czyli wewnętrzne podciągniecie do VCC a Twoja ATMEGA32 dostarcza taką możliwość.

Ustaw wyprowadzenie DDRD , odpowiadające przerwaniu INT0 , jako wejście a na PORTD ustaw na tej linii 1.

DDRD |= 0<<2;
PORTD |= 1<<2;

Na tym wyprowadzeniu od tego momentu będzie widniał stan wysoki . Teraz poprzez np. przycisk będziesz zwierał to wyprowadzenie do masy , co będzie równoznaczne z wywołaniem przerwania na zbocze opadające.
Ostatnio zmieniony 08 cze 2008, 17:58 przez atmega, łącznie zmieniany 1 raz.

ODPOWIEDZ