- LiTime Speicher und Akkus         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 22

Thema: Ständig Interrupt Probleme

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.11.2006
    Ort
    Hamburg
    Alter
    38
    Beiträge
    199

    Ständig Interrupt Probleme

    Anzeige

    Powerstation Test
    Moin!
    Ich hab mein Programm mal ein bisschen weiter endwickelt.
    Ich hab einen Servo, der sich hin und her bewegt. Auf den ist ein GP2D12 montiert. Dann hab ich einen LDR, der über ADC "ausgelesen" wird. Und 2 H-Brücken (mit Relais) bei denen 2 Antriebsmotoren über PWM gesteuert werden und über 2 Ausgänge werden die Drehrichtungen geändert. Das alles auf einem Modellpanzer.
    Mein Problem war erst das meine Scheinwerfer, die ja über den kontroller eingeschaltet werden wenn´s dunkel ist, geflakert haben, weil die Interruptroutine zu lang war. Das hab ich jetzt hinbekommen. Nur jetzt wo ich die Motorsteuerung programmiert habe, fängt plözlich mein Servo an zu rucken, oder bleibt einfach stehen und zuckt dann rum, läuft dann aber nach ner zeit wieder weiter. Dachte zuerst Hardware-Problem. Hab also ein bisschen rumgemessen und so, aber nichts gefunden. Dann hab ich meinen ganzen Motorkram aus meinem Programm genommen und das Programm wieder auf meinen Mega32 geladen. So funktioniert wieder alles ohne Problem. Mein Servo bewegt sich ganz normal und meine Helligkeitsmessung macht auch kein Problem.

    Hier mal mein Programm MIT Motorkram.
    Code:
    #include <avr/io.h>
    #include <stdint.h>
    #include <avr/interrupt.h>
    
    #ifndef F_CPU
    #define F_CPU 16000000
    #endif
    
    #define Scheinwerfer PD0
    #define Rueckleuchten PD1
    #define PWM_ServoPort PD5
    #define IR_Servo OCR1A
    #define Motor_Links PB3
    #define Motor_Rechts PD7
    #define Motor_Links_Rueck PC0
    #define Motor_Rechts_Rueck PC1
    
    //---------------------------------Globale Variablen----------------------------------
    uint8_t a=0, posi=25, count=0;
    
    //---------------------------------Interruptroutinen----------------------------------
    ISR(TIMER1_COMPB_vect)
      {
      count++;
      }
    
    //---------------------------------Helligkeitsmessung---------------------------------
    void helligkeitsmessung(void)
    {
    uint16_t LDR;
    
    ADCSRA |= (1<<ADSC);
      while (ADCSRA & (1<<ADSC))
        {
    	;
    	}
      LDR = ADCL;
      LDR += (ADCH<<8);
      
      if (LDR<150)
        {
        PORTD |= (1<<Scheinwerfer);
        PORTD |= (1<<Rueckleuchten);
        }
      if (LDR>190)
        {
    	PORTD &= ~(1<<Scheinwerfer);
    	PORTD &= ~(1<<Rueckleuchten);
    	}
    }
    
    //-------------------------------------IR_Servosteuerung---------------------------------------
    int IR_Servoposition(void)
    {
    if ((count==2)&&(a==0))
      {
      count=0;
      posi++;
      if (posi==50)
        {
        a=1;
        }
      }
    
    if ((count==2)&&(a==1))
      {
      count=0;
      posi--;
      if (posi==0)
        {
    	a=0;
    	} 
      }
    return ((posi)+440);   //440=min, 490=max
    }
    
    //--------------------------------------Motorsteuerung-----------------------------------------
    void Motorsteuerung(void)
    {
    OCR0=50; //255=Max (Links)
    OCR2=50; //255=Max (Rechts)
    }
    
    //-------------------------------------initialisierungen---------------------------------------
    void Initial_ADC0(void)
    {
    ADMUX |= 0x00;	//AREF, resultat rechtsbündig, ADC-Eingang ADC0
    ADCSRA |= ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));  //ADC eingeschaltet, Teilungsfaktor..
    DDRD |= ((1<<Scheinwerfer) | (1<<Rueckleuchten));
    }
    
    void Initial_IR_Servo(void)
    {
    TCCR1A |= ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode OC1A
    TCCR1A |= ((1<<COM1B1)|(1<<COM1B0)); //Inverted Mode OC1B
    TCCR1B |= (1<<CS12); 	//Prescaler 256
    TIMSK |= (1<<OCIE1B);
    DDRD |= (1<<PWM_ServoPort); 
    PORTD |= (1<<PWM_ServoPort);
    OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
    }
    
    void Initial_Motoren(void)
    {
    //Ausgang Initialisieren (OC0)
    DDRB |= (1<<Motor_Links); //Setzen als Ausgang
    PORTB |= (1<<Motor_Links); //Pull-Up
    
    //Ausgang Initialisieren (OC2)
    DDRD |= (1<<Motor_Rechts); //Setzen als Ausgang
    PORTD |= (1<<Motor_Rechts); //Pull-Up
    
    //Initialisierung der Ausgänge für Rückwärtsfahren
    DDRC |= ((1<<Motor_Links_Rueck)|(1<<Motor_Rechts_Rueck));
    
    //Initialisierung PWM für OC0
    TCCR0 |= ((1<<WGM01)|(1<<WGM00)); //Fast PWM
    TCCR0 |= (1<<COM01); //Clear Output on Compare, Set on Top
    TCCR0 |= ((1<<CS02)|(1<<CS00)); //CLK/1024 (15,625kHz, 64µs/periode)
    //Compare Register ist OCR0
    
    //Initialisierung PWM für OC2
    TCCR2 |= ((1<<WGM21)|(1<<WGM20)); //Fast PWM
    TCCR2 |= (1<<COM21); //Clear Output on Compare, Set on Top
    TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20)); //CLK/1024 (15,625kHz, 64µs/periode)
    //Compare Register ist OCR2
    }
    
    //---------------------------------------Hauptprogramm---------------------------------
    int main(void)
    {
    Initial_ADC0();
    Initial_IR_Servo();
    Initial_Motoren();
    
    while(1)
      {
      helligkeitsmessung();
      sei(); 
      IR_Servo = IR_Servoposition();
      Motorsteuerung();
      cli();
      }
    }
    Ich weiß echt nicht mehr weiter. Wurde mich freuen wenn mal jemand ein Auge drauf wirft, der sich auskennt. Is auch das erste mal das ich was mit Interrupt mache. Hab also nicht wirklich erfahrung, aber denke der is schuld an meinem spinnenden Roboter.

    MfG Jan
    Habe Mut, dich deines eigenen Verstandes zu bedienen.

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    05.09.2006
    Beiträge
    17

    Warum sperrst Du die Interrupts

    Hi Spongebob,

    gleich mal vorneweg, ich habe mir das Programm nicht im Detail angeschaut und weiß auch nicht, ob alle Register richtig initialisiert werden.
    Aber eines ist mir aufgefallen: Du sperrst als letztes in Deiner while(1) alle Interrupts. Dann rufst Du die Funktion helligkeitsmessung(), die auf ein Wandlerergebnis(?) wartet. Das heißt aber auch, dass wenn der Timer überläuft, während Du auf das Ergebnis wartest die ISR nicht angesprungen wird. Das passiert erst, wenn die Funktion helligkeitsmessung() beendet wurde. Je nachdem, wie schnell Dein Timer überläuft kann es passieren, dass Du einen Interrupt nicht mitbekommst (nämlich genau dann, wenn Dein Timer zweimal überläuft, während Du auf den AD-Wandler wartest).
    Würde Dir folgendes empfehlen:
    1. Nach der Interruptfreigabe (vor while(1)) sperre den Interrupt nicht mehr!
    2. Überprüfe in der TimerISR, ob Dein Counter schon 2 ist, wenn ja, setzte ein globales Flag, das Du in der while(1) abfrägst, und nur wenn dieses gesetzt ist rufst Du die Funktion IR_Servoposition().

    Hoffe mal, das hilft etwas, ansonsten schreib halt nochmal. Wie gesagt, ob Deine Initialisierungen stimmen kann ich nicht beurteilen, dafür kenne ich die AVRs zu wenig...

    Viele Grüße

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.11.2006
    Ort
    Hamburg
    Alter
    38
    Beiträge
    199
    Überprüfe in der TimerISR, ob Dein Counter schon 2 ist, wenn ja, setzte ein globales Flag
    Heißt das ich soll eine Globale Variable deklarieren, die in der ISR immer bis 2 hochzählen und jedes mal wenn die 2 ist in der main funktion was auslösen?
    Das würde doch aber heißen das mein Interrupt wieder länger braucht. Ein "count++" braucht 16ms das heißt doch ich hätte eine verzögerung von 32ms, oder?
    Die Register sind meiner meinung nach richtig gesetzt. Einzelnd klappt ja alles. Nur nicht im zusammenspiel.

    MfG Jan
    Habe Mut, dich deines eigenen Verstandes zu bedienen.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    05.09.2006
    Beiträge
    17
    Hi,

    wie kommst Du darauf, dass ein count++ schon 16 ms braucht? Das wäre nämlich ne ganze Menge für einen Befehl!
    Wie schnell taktest Du Deinen Controller denn?

    Du brauchst halt ne Möglichkeit zu merken, wann Du den Wert 2 von count erreicht hast (außerhalb der ISR).
    Andere Möglichkeit die mir gerade noch einfällt: Wenn Du statt auf den Wandler zu warten einfach abfrägst, ob er fertig ist (also ein if statt dem while) blockierst Du den Controller auch nicht so lange.

    Viele Grüße

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.11.2006
    Ort
    Hamburg
    Alter
    38
    Beiträge
    199
    Also:
    Ich takte mit 16MHz. dann hab ich einen prescaler von 256 eingestellt und einen 9Bit PWM gewählt.
    das macht eine Periodendauer von 1/(16MHz/256/512)=0,008192s
    da der Zähler ein mal hoch und einmal runter zählt sind das dann 16,384ms.
    Ich löse ja den interrupt jedes mal bei Compare von OCR1B aus. der ja immer nur einmal in diesen 16ms kommt.
    Aber ich brauche ja auch eine so verhältnissmäßig lange Zeit, da mein Servo ja auch ne gewisse Zeit braucht um sich zu bewegen.
    Wenn dir ne bessere möglichkeit einfallen würde, würde ich mich aber auch freuen.

    Das mit dem "if" wäre auch noch ne möglichkeit. Aber das braucht je im gegensatz zu dem Interrupt gar nicht so lange.

    MfG Jan
    Habe Mut, dich deines eigenen Verstandes zu bedienen.

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    05.09.2006
    Beiträge
    17
    Hi,

    okay, jetzt weiß ich, was Du mit den 16 ms meintest. Dein Interrupt wird alle 16 ms ausgelöst, das hat aber nix mit der Dauer der ISR zu tun! Wenn Du mit 16 MHz taktest braucht Dein count++ definitiv keine 16 ms (weiß nicht, wie viele Maschinenzyklen ein ADD braucht, aber wenn wir mal von 4 ausgehen wären das 250 ns für den ADD, dann kommt noch a bisserl was für das PUSH und POP dazu, also wenn ganz schlimm kommt sagen wir mal 5 µs)!

    Deine Motorsteuerung alleine klappt auch, oder hast Du das noch nicht versucht?
    Wie lange braucht denn Dein AD-Wandler, bis seine Wandlung durchgeführt ist?

    Noch was: Wenn Du in mehr als einer Funktion auf Variablen zugreifst solltest Du diese als volatile anlegen. Das bewirkt, dass der Compiler nicht mit irgendwelchen lokal gespeicherten Werte arbeiten darf, sondern jedesmal auf die Speicheradresse, an der die Variable liegt, zugreift. Das wäre bei Dir z.B. bei count der Fall. (Konkret heißt das also dann "volatile uint8_t count = 0")

    Und wie gesagt, lass mal das cli() in der while(1) weg, das gehört da nicht hin (stört ja nicht weiter, wenn das Warten auf die Wandlung durch den Timer Interrupt unterbrochen werden sollte).
    Dann würde ich auch in der Funktion IR_Servoposition auf count >= 2 abfragen und nicht auf count == 2.

    Viele Grüße

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    die aktualisierung des motors wird durch die hellmessung blockiert. ist das ik?

    evtl posi auf >= 50 und <= 0 testen (muss signed sein)

    schreib LDR = ADC anstatt mit teilregs rumzufummeln
    Disclaimer: none. Sue me.

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.11.2006
    Ort
    Hamburg
    Alter
    38
    Beiträge
    199
    Ich bin jetzt wieder zu Hause.
    Hab eben eure ganzen Vorschläge mal in mein Prog eingearbeitet
    das sieht jetzt so aus:
    Code:
    #include <avr/io.h>
    #include <stdint.h>
    #include <avr/interrupt.h>
    
    #ifndef F_CPU
    #define F_CPU 16000000
    #endif
    
    #define Scheinwerfer PD0
    #define Rueckleuchten PD1
    #define PWM_ServoPort PD5
    #define IR_Servo OCR1A
    #define Motor_Links PB3
    #define Motor_Rechts PD7
    #define Motor_Links_Rueck PC0
    #define Motor_Rechts_Rueck PC1
    
    //---------------------------------Globale Variablen----------------------------------
    volatile uint8_t a=1, count=0, x=0;
    volatile int8_t posi=25; 
    
    //---------------------------------Interruptroutinen----------------------------------
    ISR(TIMER1_COMPB_vect)
    {
    count++;
    if (count>=2)
      {
      x=1;  //Globales Flag???
      }
    }
    
    //---------------------------------Helligkeitsmessung---------------------------------
    void helligkeitsmessung(void)
    {
    uint16_t LDR;
    
    ADCSRA |= (1<<ADSC);
      while (ADCSRA & (1<<ADSC))
        {
        ;
        }
    	LDR = ADC;
      
      if (LDR<150)
        {
        PORTD |= (1<<Scheinwerfer);
        PORTD |= (1<<Rueckleuchten);
        }
      if (LDR>190)
        {
    	PORTD &= ~(1<<Scheinwerfer);
    	PORTD &= ~(1<<Rueckleuchten);
    	}
    }
    
    //-------------------------------------IR_Servosteuerung---------------------------------------
    int IR_Servoposition(void)
    {
    if (a>=1)
      {
      posi++;
      if (posi>=50)
        {
        a=0;
        } 
      }
    else
      {
      posi--;
      if (posi<=0)
        {
        a=1;
        }
      }
    return ((posi)+440);   //440=min, 490=max
    }
    
    //--------------------------------------Motorsteuerung-----------------------------------------
    void Motorsteuerung(void)
    {
    OCR0=0; //255=Max (Links)
    OCR2=0; //255=Max (Rechts)
    }
    
    //-------------------------------------initialisierungen---------------------------------------
    void Initial_ADC0(void)
    {
    ADMUX |= 0x00;	//AREF, resultat rechtsbündig, ADC-Eingang ADC0
    ADCSRA |= ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));  //ADC eingeschaltet, Teilungsfaktor..
    DDRD |= ((1<<Scheinwerfer) | (1<<Rueckleuchten));
    }
    
    void Initial_IR_Servo(void)
    {
    TCCR1A |= ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode OC1A
    TCCR1A |= ((1<<COM1B1)|(1<<COM1B0)); //Inverted Mode OC1B
    TCCR1B |= (1<<CS12); 	//Prescaler 256
    TIMSK |= (1<<OCIE1B);
    DDRD |= (1<<PWM_ServoPort); 
    PORTD |= (1<<PWM_ServoPort);
    OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
    }
    
    void Initial_Motoren(void)
    {
    //Ausgang Initialisieren (OC0)
    DDRB |= (1<<Motor_Links); //Setzen als Ausgang
    PORTB |= (1<<Motor_Links); //Pull-Up
    
    //Ausgang Initialisieren (OC2)
    DDRD |= (1<<Motor_Rechts); //Setzen als Ausgang
    PORTD |= (1<<Motor_Rechts); //Pull-Up
    
    //Initialisierung der Ausgänge für Rückwärtsfahren
    DDRC |= ((1<<Motor_Links_Rueck)|(1<<Motor_Rechts_Rueck));
    
    //Initialisierung PWM für OC0
    TCCR0 |= ((1<<WGM01)|(1<<WGM00)); //Fast PWM
    TCCR0 |= (1<<COM01); //Clear Output on Compare, Set on Top
    TCCR0 |= ((1<<CS02)|(1<<CS00)); //CLK/1024 (15,625kHz, 64µs/periode)
    //Compare Register ist OCR0
    
    //Initialisierung PWM für OC2
    TCCR2 |= ((1<<WGM21)|(1<<WGM20)); //Fast PWM
    TCCR2 |= (1<<COM21); //Clear Output on Compare, Set on Top
    TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20)); //CLK/1024 (15,625kHz, 64µs/periode)
    //Compare Register ist OCR2
    }
    
    //---------------------------------------Hauptprogramm---------------------------------
    int main(void)
    {
    Initial_ADC0();
    Initial_IR_Servo();
    Initial_Motoren();
    sei(); //Globales Interrupt gesetzt
    
    while(1)
      {
      helligkeitsmessung();
      if (x>=1)
        {
        IR_Servo = IR_Servoposition();
    	x=0;
    	count=0;
    	}
      Motorsteuerung();
      }
    }
    Das problem ist, das der Servo immer noch solche macken macht, aber glaub nicht mehr so doll. Mal fährt er bis links dann in die mitte und wieder nach links, mal zuckt der etc.
    Hab eben mal den ganzen Motorkram mal kommentiert, so das das programm ohne den kram abläuft. Da hat der Servo gar nicht gesponnen. Müsste also denke ich was mit dem Motorkram nicht richtig sein. Ich Finde aber nichts. Das mit dem "if statt weil" beim ADC weiß ich auch nicht richtig wie ich das machen soll. Müsste ja dann so sein if (ADCSRA !& (1<<ADSC))
    {
    LDR = ADC;
    }
    aber dann bekomme ich fehlermeldungen.
    Das mit dem Globalen Flag weiß ich auch nicht was das bringt, außer ne zusätzliche Variable. Hab die x genannt.
    Hoffe ihr habt noch tipps.

    MfG Jan
    Habe Mut, dich deines eigenen Verstandes zu bedienen.

  9. #9
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.220
    Warum machst du den ADC nicht auch mit Interrupt, die Helligkeitsabfrage ist doch nicht wichtig. Starten würde ich sie mit dem Timer, wenn der ADC-Interrupt kommt nur ein Flag setzen, die Auswertung dann im main. So wie es jetzt ist startest du den ADC bei jedem while-Durchlauf und wartest bis die Convertion fertig ist. Du verlierst viel Zeit und wenn du noch so etwas machst ist es leicht möglich das du Timing-Probleme bekommst.

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.11.2006
    Ort
    Hamburg
    Alter
    38
    Beiträge
    199
    Ich verstehe das echt nicht.
    Meine Interrupt-Routine sieht so aus:
    Code:
    ISR(ADC_vect)
    {
    conv=1;
    }
    Conv ist global deklariert:
    Code:
    volatile uint8_t count=0, conv=0;
    und meine Helligkeitsmessung sieht jetzt so aus:
    Code:
    //---------------------------------Helligkeitsmessung---------------------------------
    void helligkeitsmessung(void)
    {
    uint16_t LDR;
    
    ADCSRA |= (1<<ADSC);
    //while (ADCSRA & (1<<ADSC))
      //{
      //;
      //}
    if (conv >= 1)
      {
      LDR = ADC;
      conv=0;
      }
      
    if (LDR<=150)
      {
      PORTD |= (1<<Scheinwerfer);
      PORTD |= (1<<Rueckleuchten);
      }
    if (LDR>=190)
      {
      PORTD &= ~(1<<Scheinwerfer);
      PORTD &= ~(1<<Rueckleuchten);
      }
    }
    das licht bleibt jetzt dauerhaft an
    viel euch das alles beim ersten Roboter auch alles so schwer?

    MfG Jan
    Habe Mut, dich deines eigenen Verstandes zu bedienen.

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

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

LiTime Speicher und Akkus