- 3D-Druck Einstieg und Tipps         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 17

Thema: Kein Interrupt nach Reset/Neustart

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    29.07.2013
    Beiträge
    11

    Kein Interrupt nach Reset/Neustart

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Guten Tag,

    ich habe mit meinem mini-Programm ein Problem.

    Jedes mal nach dem Neustarten oder Reseten des Kontrollers wird die Interrupt-Funktion ausgeführt und erst dann das Hauptprogramm.

    Nun habe ich schon gelesen ,dass man in Assembler die erste Speicheradresse überspringen muss, um das zu unterbinden.
    Aber ich finde nichts ,wie ich sowas in "C" machen kann.

    Kann mir vlt. jemand helfen?

    Vielen Dank!
    Code:
    /*
     * Ampel.c
     *
     * Created: 07.08.2013 10:36:06
     *  Author: en
     */ 
    
    #define F_CPU 1600000UL
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    // eigene Bezeichnungen
    #define		rot		PC0
    #define		gelb	PC1
    #define		gruen	PC2
    #define		ein		1
    #define		aus		0
    
    //volatile unsigned char _taster=1;
    
    
    ISR (INT1_vect)
    {
    	_delay_ms(80);
    	PORTC	 |= (1 << PC4);
    	_delay_ms(1000);
    	PORTC &=~(1<<PC4);
    	
    	
    }
    
    void rot_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << rot);}   // Setzen
    	else {PORTC &= ~(1 << rot);}  // Rücksetzen
    	//_delay_ms(1000);
    	
    	
    	};
    
    void gelb_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << gelb);}   // Setzen
    	else {PORTC &= ~(1 << gelb);}  // Rücksetzen
    	//_delay_ms(1000);
    	
    	
    };
    
    
    void gruen_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << gruen);}   // Setzen
    	else {PORTC &= ~(1 << gruen);}  // Rücksetzen
    	//_delay_ms(1000);
    	
    	
    };
    
    
    int main(void)
    {  cli();
    	
    	 GICR |= (1 << INT1);               
    	 MCUCR |= (1 << ISC11);
    	//PORT A als Ausgang
    	PORTC	=	0x00;
    	DDRA	=	0xFF;
    	
    	//PORT C als Ausgang
    	PORTC	=	0x00;
    	DDRC	=	0xFF;
    	
    	//PORT D als Eingang
    	
    	DDRD	=	1<<PD3;
    	PORTD	=	1<<PD3;
    	SREG |= (1<<7);
    	
        while(1)
        {
    		
    		
    		rot_schalten(ein); 
    		_delay_ms(1000);
    		gelb_schalten(ein);
    		_delay_ms(600);
    		rot_schalten(aus);
    		gelb_schalten(aus);
    		gruen_schalten(ein);
    		_delay_ms(1000);
    		gruen_schalten(aus);
    		gelb_schalten(ein);
    		_delay_ms(600);
    		gelb_schalten(aus);
    		
        }
    }

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Hi,

    die Speicherorganisation übernimmt der Linker beim Compilieren automatisch, Du musst also nicht wie in Assembler selber den Interrupt-Adressbereich überspringen.
    Bist Du sicher, dass der Interrupt wirklich vor main() aufgerufen wird und nicht erst vor dem Sprung in Deine Hauptschleife (while(1){...})?
    Denn mit
    Code:
    DDRD    =    1<<PD3;
    PORTD    =    1<<PD3;
    löst Du den Interrupt vor der Hauptschleife manuell aus.

    Gruß,
    askazo

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    29.07.2013
    Beiträge
    11
    Habe mich falsch ausgedrückt.Natürlich wird es in "main()" ,aber noch vor der schleife ausgeführt.

    Nur verstehe ich nicht wie ich mit
    Code:
    DDRD    =    1<<PD3;
    PORTD    =    1<<PD3;
    Interrupt auslöse?
    Der ist doch auf abfallende Flanke eingestellt.Sprich gegen Masse.
    Und wenn das doch der Fall ist und ich löse ihn tatsächlich selber aus.Wie mache ich das denn korrekt?
    Könntest die Programmzeilen richtig stellen?!

    Riesen Dank!

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Du wechselst mit
    Code:
    DDRD = 1<<PD3;
    von einem offenen Eingang (floating) zu einem definierten Low-Pegel, was schon als fallende Flanke erkannt wird. Das Interrupt-Flag wird auch gesetzt, wenn das I-Bit nicht aktiviert ist. Sobald dieses dann aktiviert wird, wird der Interrupt ausgeführt.
    Am besten konfigurierst Du zuerst den Port und aktivierst dann den externen Interrupt. Also
    Code:
    DDRD    =    1<<PD3;
    PORTD    =    1<<PD3;
    MCUCR |= 1<<ISC11;
    GICR |= 1<<INT1;
    
    GIFR |= 1<<INTF1;
    sei();
    Somit wird der Interrupt erst scharf geschaltet, wenn der PD3 schon einen definierten High-Pegel hat.
    Sicherheitshalber habe ich mit der vorletzten Zeile das Interrupt-Flag ausdrücklich gelöscht.

    Gruß,
    askazo

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    29.07.2013
    Beiträge
    11
    Was soll ich sagen..
    Das war die Lösung!Einfach die Plätze tauschen...

    Erst Eingänge setzten ,dann interrups definieren.

    Vielen Dank!!
    -----------------------------------------

    Ganz andere frage:
    Macht es Sinn die "Delay`s" aus dem Programm rauszunehmen und stattdessen Timer zu verwenden?
    Und wenn ja, könnte mir jemand ein "Stoß" bzw Tipp geben wie ich das am besten mache?
    Also kein Code,sondern so ein kleines Flussdiagramm.
    Nach meinem derzeitigen Plan, brächte ich mindestens drei Timer...für rot ,gelb,grün..

  6. #6
    Erfahrener Benutzer Roboter-Spezialist Avatar von robo_tom_24
    Registriert seit
    04.02.2012
    Ort
    Burgenland, Österreich
    Beiträge
    485
    Wieso machst du ds eigentlich mit einer Interrupt routine?

    Klar, Timer sind besser, bei delays rechnet die CPU andauernd, bei Timern nicht da dies ein externes Modul am die ist und unabhängig von der cpu läuft. Am besten eine Timer machen, der alle 100ms einen Interrupt auslöst, diese Interrupts mit einer static variable mitzählen und je nach Zählerstand handeln (nach 10x100ms => 1s Rot aus, Gelb ein; nach 16x100ms => 1.6s Gelb aus, usw), wenn man dann einmal durch ist mit dem Ampelprogramm Variable zurücksetzten und das Spiel beginnt von neuem

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    29.07.2013
    Beiträge
    11
    Hallo geehrte Freunde der "C"-Sprache!

    Nun habe ich etwas weiter gemacht.Ich bin auf Timer umgestiegen!
    Soweit funktioniert es auch grundsätzlich!Ein Problem habe ich aber...
    Ich schaffe es nicht zuverlässig den Taster abzufragen..
    Nun habe ich schon in fast jede zweite Code-Zeile die Abfrage reingepackt...kein erfolg..Es funktioniert einfach unzuverlässig.
    Prinzip ist schnell erklärt:Es wird immer die Funktion schalten_ohne(); ausgeführt.bis der Taster PB3 gedrückt wird!dann soll in der nächsten Rot-Phase für Autos, grün für Fußgänger angehen.

    Was mache ich falsch?muss ich tatsächlich auf interrupt für Taster ausweichen(wie in der ersten Version vom Code)?Gibt es vlt doch eine andere Lösung?

    Code:
    /*
     * Ampel_mit_Timer.c
     *
     * Created: 10.08.2013 10:05:38
     *  Author: Gerrus
     */ 
    
    #define F_CPU 4000000UL //Takt auf 4Mhz festlegen
    
    
    
    
    
    #include <avr/io.h>
    #include <avr/interrupt.h> //Include fürs INterrupt
    
    // eigene Bezeichnungen
    #define		rot		PC0
    #define		gelb	PC1
    #define		gruen	PC2
    #define		rotf	PC4
    #define		gruenf	PC5
    #define		ein		1
    #define		aus		0
    
    volatile  int sec,igr;
    void rotf_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << rotf);}   // Setzen
    	else {PORTC &= ~(1 << rotf);}  // Rücksetzen
    	
    	
    	
    };
    void gruenf_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << gruenf);}   // Setzen
    	else {PORTC &= ~(1 << gruenf);}  // Rücksetzen
    	
    	
    	
    };
    void rot_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << rot);}   // Setzen
    	else {PORTC &= ~(1 << rot);}  // Rücksetzen
    	
    	
    	
    };
    void gelb_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << gelb);}   // Setzen
    	else {PORTC &= ~(1 << gelb);}  // Rücksetzen
    	
    	
    	
    };
    void gruen_schalten(unsigned int i)
    {
    	if (i==ein){PORTC	 |= (1 << gruen);}   // Setzen
    	else {PORTC &= ~(1 << gruen);}  // Rücksetzen
    	//_delay_ms(1000);
    	
    	
    };
    void schalten_ohne (void)
    {
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    	if (igr==0)
    	{
    		rot_schalten(ein);
    		
    	}
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    	if (igr==76)
    	{
    		gelb_schalten(ein);
    	}
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    	if (igr==107)
    	{
    		rot_schalten(aus);
    		gelb_schalten(aus);
    		gruen_schalten(ein);
    	}
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    	if (igr==183)
    	{
    		gruen_schalten(aus);
    		gelb_schalten(ein);
    	}
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    	if (igr==213)
    	{
    		gelb_schalten(aus);
    		igr=0;
    	}
    	
    }
    void schalten_mit (void)
    {
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    		
    	}
    	
    	if (igr==0)
    	{
    		rot_schalten(ein);
    		rotf_schalten(ein);
    	}
    	if (igr==15)
    	{
    		rotf_schalten(aus);
    		gruenf_schalten(ein);
    	}
    	if (igr==61)
    	{
    		gruenf_schalten(aus);
    		rotf_schalten(ein);
    	}
    	if (igr==76)
    	{
    		gelb_schalten(ein);
    	}
    	if (igr==107)
    	{
    		rot_schalten(aus);
    		gelb_schalten(aus);
    		gruen_schalten(ein);
    	}
    	if (igr==183)
    	{
    		gruen_schalten(aus);
    		gelb_schalten(ein);
    	}
    	if (igr==213)
    	{
    		rotf_schalten(aus);
    		gelb_schalten(aus);
    		igr=0;
    		sec=0;
    	}
    
    	
    }
    
    
    
    
    ISR (TIMER0_OVF_vect)					// Die Funktion die beim Overflow aufgerufen wird
    {
    	
    	 igr ++;
    	if (!(PIND &(1<<PD3)))
    	{
    		sec=1;
    	}
    }
    
    
    
    
    
    
    int main(void)
    {
    	//PORT C als Ausgang
    	PORTC	=	0x00;
    	DDRC	=	0xFF;
    	
    	//PORT D als Eingang
    	
    	DDRD	=	0<<PD3;
    	PORTD	=	1<<PD3;
    	
    	
    	
    	TCCR0 |= (1<<CS02)|(1<<CS00);	//Einstellen Von Preteiler 1/1024. Datasheet Seite 85
    	TIMSK |= (1<<TOIE0);			//Interrupt auslösen beim Overflow Datasheet Seite 85
    	TCNT0 = 0;						//den timer selber reseten.Eine Null reinschreiben
    	sei();							//Interruos aktivieren
    	
    	
    	while(1)
        {	
    		if (!(PIND &(1<<PD3)))
    	    {
    		    sec=1;
    	    }
    		if (sec==0)
    		{
    			schalten_ohne();		//Ampelschaltung ohne fussgaenger
    			
    		}
    		if (!(PIND &(1<<PD3)))
    		{
    			sec=1;
    		}
    		if (sec==1)
    		{
    			schalten_mit();			//Ampelschaltung mit fussgaenger
    		}
    		
    		
    
    	}
    }
    P.S: Bin über jede Art von Tips dankbar!!Vlt verfolge ich komplett verkehrten weg?vlt geht es einfacher,stabiler,besser?

    Vielen Dank!

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    05.11.2007
    Beiträge
    1.076
    Hallo,
    ich lange über deinen Code gesessen und möchte dazu folgendes beitragen
    Viel Text mit hoffentlikch einer Lösung ganz am Ende.

    Deine Tastenabfrage kannst Du so schreiben, da brauchst Du keine Klammern, weil nur eine Anweisung folgt

    if (!(PIND &(1<<PD3))) sec=1;

    Diese Abfrage kommt eigentlich nur einmal in deine Interrupt Funktion, alle abderen identischen Abfragen kannst Du rausnehmen, die geben dann keinen Sinn.
    Wenn die Taste betätigt wird, setzt Du ja im Interrupt dann die Variable "sec" auf 1. Diese bleibt nun solange auf 1 bis sie vom Hauptprogramm wieder auf 0 gesetzt wird.
    Dies passiert bei Dir NUR in der Funktion schalten_mit bei dem Zählerstand 213 also nach einem kompletten Durchlauf mit Fussgänger. Das sieht soweit okay aus.

    Ich weis jetzt nicht wie oft dein Interrupt ausgelöst wird, anhand deiner Zahlenwerte anscheinend nicht sonderlich häufig. Da könnte es mit der eben genannten Methode "nur im Interrupt" problematisch werden, also lass das vorerst mal so, das tut keinem ja weh, obwohl nicht schön.
    Du könntest noch den Int Aufruf schneller machen, z.B. 10 mal schneller und deine Zeitwertabfragen auch entsprechend mit 10 multiplizieren.
    Dann reicht die Tastenabfrage nur im Interrupt sicherlich aus.

    Idee, aber wieder verworfen....
    Könnte es sein, das an deinem Pin wo die Taste dran ist kein Widerstand nach Plus dran ist, dann bekommt er zwar eine schöne Null wenn Du die Taste drückst, aber wenn Du sie losläst hängt der Pin irgendwie inder Luft.
    Gibt aber auch keinen Sinn, da der High Pegel bei Dir nie ausgewertet wird.


    etwas übersichtliche ist folgende Vorgehensweise:
    Code:
      while(1)
      {
    
        if (sec==0) schalten_ohne();  //Ampelschaltung ohne fussgaenger
               else schalten_mit();   //Ampelschaltung mit  fussgaenger
    
        switch(igr)   /* den Zeitwert auswerten */
        {
    
          case   0 : rot_schalten(ein);
                     break;                /* fertig, sprige hinter die switsch Anweisung */
    
          case  76 : gelb_schalten(ein);
                     break;
    
          case 107 : rot_schalten(aus);
                     gelb_schalten(aus);
                     gruen_schalten(ein);
                     break;  
    
          case 183 : gruen_schalten(aus);
                     gelb_schalten(ein);
                     break;
    
          case 213 : gelb_schalten(aus);
                     igr=0;
                     break;
    
        } /* ende switch */
      } /* ende while */
    Was fällt mir noch ein:
    Ist dein Taster defekt und gibt schlechten Kontakt ?
    ich davon tonnenweise rumliegen.....


    dann hab ich ein ein Read Modify Write Problem gedacht, kenne ich von den PICs von Microchip her.
    Port lesen Bit ändern und zurück schreiben. Dein Taster ist aber auf einem anderen Port als deine LEDs, also eher unwahrscheinlich.


    Letzte Idee:
    Die Variable sec wird im Interrupt gesetzt,
    du hast sie als int definiert, könnte also sein, dass sie 2 Bytes belegt
    Wenn nun im Hauptprogramm der Wert gesetzt wird und ein Interrupt während der Verarbeitung
    der beiden Bytes auftritt, könnte das schief gehen.
    Um das zu verhindern versuche mal folgendes:
    Sperre die Interrupts während Du den Wert sec auf Null setzt.

    Atomaren Code erzeugen nennt man das wohl, also so:

    cli(); // sperre alle Interrupts
    sec = 0; // setzen den Wert
    sei(); //Interrupts aktivieren


    vielleicht konnte ich Dir irgendwie weiterhelfen
    viel Spass noch wünscht Dir
    Siro
    Geändert von Siro (14.08.2013 um 01:06 Uhr)

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    29.07.2013
    Beiträge
    11
    Hallo Siro!
    Vielen Dank für deine Tips!
    Ich bin mi meinem Programm immer noch nicht erfolgreich.
    Wie ich inzwischen raus gefunden habe,reicht die Abfrage in dem Timer-Interupt komplett aus.Denn,ich lasse jetzt ein Port setzen und damit eine extra LED (zur Kontrolle) aufleuchten.Das blöde ist,schein bar wird die Variable "sec" entwider nicht gesetzt (obwohl im gleich "IF"-Strang) oder wird wieder zurückgesetzt ,wie auch immer...
    Leider kriege ich das auch nicht mit dem Debuggen in Atmel Studio raus..
    bin so bischen schon am lust zuverlieren weiter zumachen...

    zB : wenn ich Rücksetzten von "sec" rausnehme aus dem Code ,dann wird "sec" richtig gesetzt(also wenn ich den Taster drücke) und danach läuft wirklich immer die Funktion "schalten_mit"..aber wenn ich die "sec" am ende der Funktion "schalten_mit" wieder auf null setze ,dann funktioniert nichts mehr..
    ich will jetzt nochmals die "IF"`s auf switch umschreiben,aber viel hoffnung, dass es was bringt,ausser übersicht, habe ich nicht.
    es müssen doch zu hauf programme sein ,die ständig auf tasteneingabe warten und trotzdem etwas machen?!Sind die alle über INT0 (1) gemacht?Kann doch nicht sein.

    Ich habe wirklich das Gefühl ,dass die "sec" aus versehen immer überschrieben wird.

  10. #10
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    05.11.2007
    Beiträge
    1.076
    Das ist wirklich merkwürdig was da anscheined passiert.
    Kann es eine Überlappung von Stack und Variablen geben ?
    Ich habe mit den AVR's noch nicht gearbeitet aber man kann sicher so einiges in der Entwicklungsumgebeung umstellen, oder es gibt einen Linker FIle....
    Wenn Du der Meinung bist, dass sich ein Speicher überschreibt:
    Mach doch mal ein paar unnütze Variablen vor den momentanen, um Speicher zu verschwenden....
    Das Problem ist, dass die Compiler unbenutzen meist wegoptimieren, meist reicht das volatile davor.

    volatile char dummy[20]; /* reserviere 20 Bytes für Muell */

    dann deine wirklicehn Variablen

    volatile int sec,igr;

    dadurch verschieben sich die Speicherstellen deiner Variablen
    Dann schaust Du wie sich das Programm dadurch verhält.

    und ganz wichtig: NIE aufgeben jeder Fehler ist zu finden

Seite 1 von 2 12 LetzteLetzte

Ähnliche Themen

  1. Kein Reset mit angeschlossenem ISP Programmer
    Von Markus87 im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 5
    Letzter Beitrag: 23.08.2011, 14:22
  2. kein RXD Empfang nach "Reset"
    Von neo3000 im Forum Controller- und Roboterboards von Conrad.de
    Antworten: 0
    Letzter Beitrag: 10.10.2010, 14:39
  3. Motorport wird nach Neustart angesteuert am ATMEGA 32 ?
    Von M.Huhnke im Forum AVR Hardwarethemen
    Antworten: 2
    Letzter Beitrag: 20.01.2010, 16:00
  4. Problem nach RESET
    Von bombatz im Forum Assembler-Programmierung
    Antworten: 7
    Letzter Beitrag: 12.08.2006, 12:10
  5. Timer1 reset nach Compare1A
    Von Theo16505 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 11.02.2006, 23:33

Stichworte

Berechtigungen

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

12V Akku bauen