-         

Ergebnis 1 bis 9 von 9

Thema: Externe Interrupts an ATMega 32 auf RN-Control... *help*

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.10.2005
    Beiträge
    165

    Externe Interrupts an ATMega 32 auf RN-Control... *help*

    Anzeige

    Hallo ale miteinander. Seit gestern nachmittag versuche ich verzweifelt auf meinem RN-Control ein kleines Programm zum Laufen zu bringen. Es soll in der Hauptschleife die LED am PortC.4 blinken lassen (tut es auch) und wenn ich den Interrupt 0 auslöse die LED am PortC.0 blinken lassen (tut es nicht).

    Ich habe jetzt viele Stunden dieses und etliche andere Foren gewälzt, Tutorials, Datenblätter und Google gequält, aber ich finde die Lösung einfach nicht... Könnt ihr bitte mal kurz in meinen Code schauen und mir sagen, wo der Fehler liegt?



    Quellcode:
    Code:
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    
    
    int main(void)
    {
    
    	/*###Initialisierungsphase###*/
    
    	//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
    	DDRC |= 0x11;	//10001000 -> PORTC.4 ist blinkende LED im Hauptprogramm, PORTC.0 ist Anzeige des Interrupts
    	DDRD |= 0x00;	//00000000 -> PORTD.2 ist Interrupt0 (Der ausgelöst werden soll)
    	
    	//Variablen
    	uint8_t counter;
    
    	//Interrupts initialisieren - ist der Kram hier richtig?
    	MCUCR = ~(1<<ISC01);
    	MCUCR = (1<<ISC00);
    	GICR = (1<<INT0);
    	sei();
    
    	//Interruptroutine, die ausgelöst werden soll - aber nicht wird
    	ISR(INT0_vect)
    	{
    		for(uint8_t i=0; i<5; i++)
    		{
    		PORTC |= (1<<0);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    
    		PORTC &= ~(1<<0);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    		}
    	}
    
    	while(1)
    	{
    		PORTC |= (1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    
    		PORTC &= ~(1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    	{
    
    	}
    	}
    	
    	
    	return 1;
    }


    Compilerausgabe:
    Code:
    > "make.exe" all
    
    -------- begin --------
    avr-gcc (GCC) 3.4.6
    Copyright (C) 2006 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    
    Size before:
    interrupts.elf  :
    section    size      addr
    .text       228         0
    .data         0   8388704
    .bss          0   8388704
    .noinit       0   8388704
    .eeprom       0   8454144
    .stab      1980         0
    .stabstr   1866         0
    Total      4074
    
    
    
    
    Converting to AVR Extended COFF: interrupts.cof
    avr-objcopy --debugging --change-section-address .data-0x800000 --change-section-address .bss-0x800000 --change-section-address .noinit-0x800000 --change-section-address .eeprom-0x810000  -O coff-ext-avr interrupts.elf interrupts.cof
    Warning: file C:/DOCUME~1/EWEDDI~1/LOCALS~1/Temp/cc0Eeaaa.s not found in symbol table, ignoring
    Warning: ignoring function __vectors() outside any compilation unit
    Warning: ignoring function __bad_interrupt() outside any compilation unit
    
    Size after:
    interrupts.elf  :
    section    size      addr
    .text       228         0
    .data         0   8388704
    .bss          0   8388704
    .noinit       0   8388704
    .eeprom       0   8454144
    .stab      1980         0
    .stabstr   1866         0
    Total      4074
    
    
    
    Errors: none
    -------- end --------
    
    
    > Process Exit Code: 0
    > Time Taken: 00:01


    Ich weiß, dass sich dieser Effekt über Timer oder sonstwas viel einfacher erreichen ließe, aber ich will verstehen, wie ich externe Interrupts auslöse. Bin für jede Hilfe sehr dankbar!


    Gruß
    Corone

  2. #2
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.186
    Im Simulator funktioniert es so:
    Code:
    #include <avr/interrupt.h>
    #define F_CPU 10000000UL
    #include <util/delay.h>
    uint8_t i;
    uint8_t counter;
    
    
       //Interruptroutine, die ausgelöst werden soll - aber nicht wird
    ISR(INT0_vect){
    	
     //     for( i=0; i<5; i++)
          {
          PORTC |= (1<<0);
          
          //wait 16*65536
          counter = 0;
          while(counter < 16)
          {
             counter++;
             _delay_loop_2(65535);
          }
    
          PORTC &= ~(1<<0);
          
          //wait 16*65536
          counter = 0;
          while(counter < 16)
          {
             counter++;
             _delay_loop_2(65535);
          }
        }  
       }
    int main(void)
    {
    
       /*###Initialisierungsphase###*/
    
       //Pins bzw. Ports als Ein-/Ausgänge konfigurieren
       DDRC |= 0x11;   //10001000 -> PORTC.4 ist blinkende LED im Hauptprogramm, PORTC.0 ist Anzeige des Interrupts
       DDRD |= 0x00;   //00000000 -> PORTD.2 ist Interrupt0 (Der ausgelöst werden soll)
       
       //Variablen
       
    	
       //Interrupts initialisieren - ist der Kram hier richtig?
       MCUCR = ~(1<<ISC01);
       MCUCR = (1<<ISC00);
       GICR = (1<<INT0);
       sei();
    
    for(;;){
       
          PORTC |= (1<<4);
          
          //wait 16*65536
          counter = 0;
          while(counter < 16)
          {
             counter++;
             _delay_loop_2(65535);
          }
    
          PORTC &= ~(1<<4);
          
          //wait 16*65536
          counter = 0;
          while(counter < 16)
          {
             counter++;
             _delay_loop_2(65535);
          }
       
    }
    }
    Einige kleine Änderungen, Taktfrequenz noch richtig eintragen.

    Hubert

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.10.2005
    Beiträge
    165
    Mhhh.... vielen Dank für deine Hilfe. Supi, dass sich so schnell jemand gemeldet hat! Leider bekomm ich's trotzdem noch nicht hin...

    Klar... ich Ochse hab irgendwie die Interruptroutine in der main-Schleife gehabt... warum auch immer *Kopp auf Tisch hau*. Aber das war nicht der alleinige Fehler... Leider funktionierte auch dein Programm nicht besser als meines - LED4 blinkt, die 0 rührt sich nicht

    Habe da gleich mal noch ein paar Fragen: Warum enthält dein Programm in der Main keine Return-Anweisung? Sicher, die wird nie erreicht... aber bei mir meckert der Compiler, wenn ich keine habe.

    Warum hast du in meiner Interruptroutine die For-Schleife auskommentiert?

    Ach ja... das Setzen dieser Register (MCUCR und GICR) habe ich mir nach Datenblättern und Tuts frei zusammengeschustert - stimmt das überhaupt, was ich da geschrieben habe?

    Zum Auslösen des Interrupts verbinde ich immer +5V kurzzeitig mit dem Pin D.2... ist das überhaupt so möglich, oder kann ich damit gar keinen Interrupt auslösen?

    So... zu guter letzt noch mal die aktuelle Version meines Quelltextes. Da nach Programmstart die LED0 immer mit rumfunzelt (Ausgang is eben high) will ich sie per Interrupt nur noch auf Low schalten -> Programm verkürzt sich weiter. Könnt ihr bitte noch mal schauen, was ich falsch mache?


    Code:
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    
    
    //Interruptroutine, die ausgelöst werden soll - aber nicht wird
    ISR(INT0_vect)
    {
    	PORTC &= ~(1<<0);
    }
    
    
    
    int main(void)
    {
    
    	/*###Initialisierungsphase###*/
    
    	//Variablen
    	uint8_t counter;
    
    	//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
    	DDRC |= 0x11;	//10001000 -> PORTC.4 ist blinkende LED im Hauptprogramm, PORTC.0 ist Anzeige des Interrupts
    	DDRD |= 0x00;	//00000000 -> PORTD.2 ist Interrupt0 (Der ausgelöst werden soll)
    	
    
    	//Interrupts initialisieren - ist der Kram hier richtig?
    	MCUCR = ~(1<<ISC01);
    	MCUCR = (1<<ISC00);
    	GICR = (1<<INT0);
    	sei();
    
    
    	while(1)
    	{
    		PORTC |= (1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    
    		PORTC &= ~(1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    	}
    	
    	
    	return 1;
    }

    Vielen Dank für deine Hilfe und alle, die sich hoffentlich noch melden!!

    Viele Grüße
    Corone

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Hallo,
    MCUCR = ~(1<<ISC01);
    MCUCR = (1<<ISC00);
    Erste Zeile hat hier wohl nicht viel zu sagen, weil Du in der zweiten Zeile den ganzen Register sowieso überschreibst...
    Lass die erste Zeile für das Beispielprogramm ganz weg.
    Du stellst Interrupt bei logischem Weschsel an Int 0 ein, ist es denn Hardwaremäßig so gegeben ?
    Welchen Level hat der INT0 ?
    Ist da ein Pulldown dran ?
    selbst wenn ja, machst Du hier 2 Interrupts schnell hintereinander, also:
    Du gehst mit Deinen +5V Draht an den Pin dran -> interrupt, machst den Draht weg -> interrupt
    Mach es z.B so:
    Code:
     //Pins bzw. Ports als Ein-/Ausgänge konfigurieren 
       DDRC |= 0x11;   //10001000 -> PORTC.4 ist blinkende LED im Hauptprogramm, PORTC.0 ist Anzeige des Interrupts 
       DDRD |= 0x00;   //00000000 -> PORTD.2 ist Interrupt0 (Der ausgelöst werden soll)
     PORTD = (1<<PD2); /*internen Pullup einschalten*/
     MCUCR = (1<<ISC01); /*Interrupt bei fallender Flanke*/ 
       GICR = (1<<INT0); 
       sei();
    Jetzt kannst Du Deinen Draht zwischen GND und PD2 halten,
    so müßte es funktionieren

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.186
    Hallo
    Das mit dem Interrupt auslösen hat dir "izaseba" schon geschrieben. Die for-schleife habe ich nur zum testen auskommentiert. In der Simulation blinkt bei mir auch die Led 0. Ich weis nicht ob du das AVR-Studio benutzt, aber da kann man zumindest so einfache Sachen sehr leicht simulieren.
    Hubert

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.10.2005
    Beiträge
    165
    Ah, vielen Dank für eure Hilfe. Hab's gerad eben auch hinbekommen... nur eine Frage zu dem MCUCR hab ich noch: Warum überschreibt der Zweite das Erste? Laut Datenblatt sind ISC01 und ISC00 unabhängig voneinander - je nachdem, welche der insgesamt 4 Kombinationsmöglichkeiten ich wähle, habe ich die 4 Modi: (vorne: ISC01 / hinten: ISC00) "00 - Interrupt bei Low-Level auslösen" "01 - bei irgend einer Pegeländerung" "10 - bei fallender Flanke" "11 - bei steigender Flanke"


    Ist dem nicht so? Wenn nein - wie kann ich dann die 4 verschiedenen Modi aussuchen?




    Hier mal noch mein kompletter Code... hilft vielleicht mal irgend einem Anfänger weiter, der vor dem selben Rätsel wie ich steht:



    Code:
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    
    //Variablen
    uint8_t counter;
    uint8_t i;
    
    //Interruptroutine, die ausgelöst werden soll
    ISR(INT0_vect)
    {
    	for(i=0; i<2; i++)
    	{
    		PORTC |= (1<<0);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    
    		PORTC &= ~(1<<0);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    	}
    }
    
    
    
    int main(void) 
    {
    
    	/*###Initialisierungsphase###*/
    
    	//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
    	DDRC |= 0x11;	//10001000 -> PORTC.4 ist blinkende LED im Hauptprogramm, PORTC.0 ist Anzeige des Interrupts
    	DDRD |= 0x03;	//00000011 -> PORTD.2 ist Interrupt0 (Der ausgelöst werden soll)
    
    
    	//Interrupts initialisieren
    	MCUCR &= ~(1<<ISC01);	//stellen den Modus ein, wie der Interrupt auslöst - je nach Art des Sensorsignals muss ein anderer Modus gewählt werden
    	MCUCR |= (1<<ISC00);	//00 bei Low-Level //01 bei Änderung des Pegels (egal, welche) //10 bei fallender Flanke (high zu low) //11 bei steigender Flanke (low zu high)
    	GICR |= (1<<INT0);		//aktiviert den Interrupt an sich
    	sei();					//aktiviert das globale Interrupt Enable-Flag (I im SREG-Register)
    
    
    	while(1)
    	{
    		PORTC |= (1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    
    		PORTC &= ~(1<<4);
    		
    		//wait 16*65536
    		counter = 0;
    		while(counter < 16)
    		{
    			counter++;
    			_delay_loop_2(65535);
    		}
    	}
    	
    	
    	return 1;
    }


    Vielen Dank für eure Hilfe!! Schaut mal bitte noch wegen dem MCUCR-Register, das verwirrt mich noch. Ansonsten - alles gelernt, was auf dem Plan stand. Danke!!!


    Grüßle
    Corone

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Warum überschreibt der Zweite das Erste?

    MCUCR = ~(1<<ISC01);
    löscht ISC01 bit und läßt den rest unverändert...

    MCUCR = (1<<ISC00);

    interessieren die restlichen Bits nicht, es wird nur ISC00 gesetzt, der Rest wird mit 0 beschrieben.
    Solltest Du z.B im MCUCr irgendwas gesetzt haben, wird nach der zweiten Operation alles gelöscht sein, alles klar?
    Deswegen hab ich geschrieben , daß die erste Zeile in diesem Zusammenhang unnötig ist.

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    21.10.2005
    Beiträge
    165
    ahhh... gut, danke. aber wenn ich beide auf 1 setzen will, muss ich

    MCUCR = (1<<ISC01);
    MCUCR = (1<<ISC00);


    nehmen, oder?

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    nein, Entweder
    Code:
    MCUCR = (1<<ISC01); 
    MCUCR |= (1<<ISC00);
    oder
    Code:
    MCUCR = (1<<ISC01)|(1<<ISC00);
    was bei eingeschalteter Optimierung den gleichen Code geben dürfte.
    Code:
    MCUCR |= (1<<ISC01)|(1<<ISC00);
    setzt die Bits, ohne den alten Zustand von MCUCR zu verändern
    Code:
    MCUCR &= ~(1<<ISC01)|(1<<ISC00);
    Schaltet sie ab, der Rest bleibt unberührt, das sind aber C Grundlagen
    Ich hoffe Licht ins dunkle gebracht zu haben

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •