- Labornetzteil AliExpress         
Ergebnis 1 bis 4 von 4

Thema: INT0 an 328 - (M)Ein Problem

  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686

    INT0 an 328 - (M)Ein Problem

    Anzeige

    E-Bike
    Probleme mit dem externen Interrupt INT0.

    Aufgabenstellung: der externe Interrupt INT0 soll mit Flankenerkennung "any edge" Start und Ende des Servopulses zeitlich erfassen. Dies wird als Sollgröße in der Regelung weiter verarbeitet.

    Das Programm soll auf ATMega328p/8MHz_int-Osz. laufen und über den INT0 die Dauer von Servopuls und Periodenzeit laut dem Protokoll für Modellbauservos bestimmen (1 ms bis 2 ms Puls bei 20 ms Periodendauer). Ziel ist es, etliche defekte Mikroservos wieder zu beleben.

    Das ähnliche Projekt funktioniert bestens: im Roboter archie läuft ein Mikrogetriebemotor mit Encoder als Servo; Datenformat ist der übliche Modellbauservo-Puls. Das funktioniert auf einer Controllerplatine babyorangutan seit über einem Jahr gut. Der Motor hat einen Encoder der mit dem gleichen mega328p/20MHz-Resonator vom INT0 ausgelesen wird.

    Die neue Variante hat als Stellungsgeber keinen digitalen Eingang (Encoder) sondern einen anlogen Geber, den Servopoti. Daher musste das Programm neu geschrieben werden. Ausserdem ist mir das "alte" Programm (Encoderbasis) zu "heiß gestrickt".

    Es gibt Probleme über Probleme mit dem INT0.
    A Die Parametrierung des INT0 laut Datenblatt funktioniert nicht wie dort beschrieben (ATmega328-P_Atmel-42735B_Complete-11-2016, S 89).
    B Der weitgehend gleiche Code in der späteren Programmumgebung funktioniert nicht (allenfalls/selten wirres Schalten des Ausgangs).

    Nach den ersten Programmteilen einschließlich dem Auslesen des Poti (incl. Tests) wurde der INT0 implementiert zum Erfassen der jeweils erfassten Pulsdauer des Servos. Nun zeigte das Programm keine brauchbaren Ergebnisse. Zum Debuggen wurde schließlich ein Port (C0) gewählt, auf dem das mit INT0/PD2 dingelesene Servosignal von der INT0-ISR kopiert wurde. Es kam entweder nichts, oder Wirrwar, jedenfalls keine Kopie des Servopulses an (LED-Anzeige, Oszi-Kontrolle).

    Nach stundenlanger Fehlersuche wurde ein Code mit stark gekürzten Variante des Ursprungprogramms geschrieben und auf demselben Testboard für die Programm/Controllerentwicklung getestet (babyorangutan auf Lochraster mit Poti, RS232 und Tastern).

    In dieser Testvariante wurde nur der für INT0 relevante Code mit einer Debugfunktion (LED schaltet) geschrieben. Ziel: der am INT0/PD2 erfasste Pegel wird 1:1 an PC0 weitergegeben (siehe unter Tabelle).

    Die verlangte Funktion wird NUR erreicht, wenn ISC01 und ISC00 zu Null gesetzt sind, das heißt lt Datenblatt ".. The low level of INT0 generates an interrupt request .."

    Auszug aus dem Datenblatt zu mega328p (ATmega328-P_Atmel-42735B_Complete-11-2016, S 89):
    Code:
    ISC01 . ISC00 . . Description
     .0 . . . 0 . . . The low level of INT0 generates an interrupt request.
     .0 . . . 1 . . . Any logical change on INT0 generates an interrupt request.
     .1 . . . 0 . . . The falling edge of INT0 generates an interrupt request.
     .1 . . . 1 . . . The rising edge of INT0 generates an interrupt request.
    Der ganze Testcode
    Code:
    /* >> 
      Stand ...C1..\C_test1\C_test1.c
     =================================================================================
     Target MCU             : ATmega328p, Testplatine babyorangutan
     Target Hardware        : Babyorangutan
     Target Frequenz        : siehe unten
     =================================================================================
      *** Versionsgeschichte:
     ========================
     x10 28Okt17 1002 Test INT01-Signal=PD2 nach LED rtUserLED=UART-TxD=PD1 ausgeben
     =================================================================================
      *** Aufgabenstellung : LEDTest Blinken im Takt von INT0=Servopuls-Eingang
     ============================================================================== */
      #include <stdlib.h>           //
      #include <avr/io.h>           //
      #include <avr/interrupt.h>    //
      #define       F_CPU   8000000UL
                                    //
    // FP FP        Funktionsprototypen       FP FP FP FP FP FP FP FP FP FP FP ===== =
      void XTI0_int( void );        // Initialisiere Interrupt 0, PD2, auf ANY edge
      ISR(INT0_vect);               // INT0-PD2 triggert ANY edge => lesen 
      void wms(uint16_t ms);        // Wait für uint16_t Millisekunden
    // ============================================================================= =
    
    
    // ============================================================================= =
    // ============================================================================= =
      int main (void)       //
     {                      //
      DDRC |=  (1<<DDC0);   // PC0 => Ausgang rtLEDTest
      DDRC |=  (1<<DDC1);   // PC1 => GND für LEDs
      DDRC |=  (1<<DDC2);   // PC2 => Ausgang gnLEDHeart !Kein Timer für Heartbeat!
      DDRD |=  (1<<DDD1);   // PD1 => Ausgang für user defined LED on babyorangutan
      DDRD &= ~(1<<DDD2);   // PD2/INT0 => Eingang ohne Pullup für Servopuls
      DDRD &= ~(1<<DDD4);   // PD4 => paralleler Eingang ohne Pullup für Servopuls
      PORTC = 0b00000000;   // Keine Pullups, kein gesetzter Ausgang
      PORTD = 0b00010100;   // Pullup am INT0-Eingang und optionalem parallelem Port
    // - - - - - - - - - - - -
      XTI0_int ( );
      sei ( );
    // - - - - - - - - - - - -
      while ( 1 )
      {
        wms (  500);
        PORTD    |=  (1<<PD1);      //Z appelphilip auf user defined LED
        wms (  500);
        PORTD    &= ~(1<<PD1);
      }
      return 0;
     }                      //        
    // =====        Ende des main, der kann aus mehreren Abschnitten bestehen     == =
    // ============================================================================= =
    
    
    // ============================================================================= =
    // ===  Initialisierung externer Interrupts 0 bei m328
    //      INT0 auf PORTD2 empfaengt ServoPuls
    //      Dokumentation ATmega328-P_Atmel-42735B_Complete-11-2016_NEU-NEU..NEU.pdf
    // ============================================================================= =
      void XTI0_int( void )            // Initialisiere Interrupt 0, PD2, auf ANY edge
     {                              //
    // - - - - - - - - - - - - - - - -
      EIMSK   |=  (1<<INT0);        // erlaube INT0
      EICRA   |=  (1<<ISC00);       // low level of INT0 generates an interrupt request
                                    //  =>  im Test triggert   J E D E   Flanke
                                    //  Oskar zeigt korrektes Abbild von PD2/INT0
    //  EICRA   |=  (1<<ISC01);       // INT0 triggert "auf jede Flanke (any edge)"  S89
                                    // ".. Any logical change .."
                                    //  =>  im Test NUR   E I N E   Flanke 01? oder 10?
                                    //  => denn Oskar zeigt isochrone Pulse (je 20 ms + od -)
    //  EICRA   |=  (1<<ISC10);       // falling edge of INT1 generates an interrupt request
                                    //  =>  Oskar zeigt im Test sehr unregelmässig
                                    //      (mit ms-langen Pausen) inverse Servopulse
    //  EICRA   |=  (1<<ISC11);       // rising edge of INT1 generates an interrupt request
                                    //  =>  im Test wie eben mit ISC10
     }      // Ende von void XTI_0_init( void )
    // ============================================================================= =
    
    
    // ============================================================================= =
      ISR(INT0_vect)                // INT0-PD2 triggert ANY edge => lesen 
     {                              // => Bei Aufruf PORTD2/INT0 prüfen auf high/low
                                    // und high/low weitergeben an Ausgang PC2=LEDTest
      if (((PIND) & (1<<PD2))?1:0)
      { PORTC  |=  (1<<PC0); }
      else
      { PORTC  &= ~(1<<PC0); }
     }                      // Ende ISR(INT0_vect)
    // ============================================================================= =
    
    
    // ============================================================================= =
    //### Programm pausieren lassen  !! Der Pausenwert ist nur experimentell !
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      void wms(uint16_t ms)        //
      { 
        for(; ms>0; ms--) 
        { 
    //    uint16_t __c = 3000;      // Statt 4000 bei 20 MHz nur 3000 (3200) bei 16MHz
          uint16_t __c = 1600;      //     bzw. statt 4000/20 MHz nur 1600 bei 8MHz
          __asm__ volatile (        //
             "1: sbiw %0,1" "\n\t" 
             "brne 1b" 
             : "=w" (__c) 
             : "0" (__c) 
          ); 
        } 
      } 
    // ============================================================================= =
    //      E N D E         E N D E
    // ============================================================================= =
    Alle anderen Varianten zeigen (Oskar) entweder keine exakte Kopie der Pulsform, nur 20 ms - Pulse oder gar nichts.

    Derselbe Code in den komplex(er)en Projektquellen führt zu keiner Ausgabe der auf INT0 eingelesenen Daten.

    Die relevanten Teile des Originalen Codes:
    Code:
    ...
    // - - - - - - - - - - - - - - -
    // Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pins/Pull Ups (1) aktiv.
    //   A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp, Belegung siehe oben
      DDRB  = 0b00000111;   // Mot1/2: PB1 = OC1A-MotorPWM; PB2 = OC1B-MotorPWM
      PORTB = 0b11111000;   // 
                            //
      DDRC  = 0b01101111;   // PC6+7-Pin  NUR bei babyorangutan (TQFP+MLF)
      PORTC = 0b10100000;   // PC0=LHeart/~beat, PC1=GND, PC2=LEDTst
                            // PC3=GND, PC4-ADC/Srv-Poti ohne Pullup, PC5=VccPoti!!
                            // 
      DDRD  = 0b00000011;   // RX/TX-PD0/1, PD2 = INT0-Servopuls,
                            // PD5/PD6 = M1B/M1A, PD7 = Taste: PullUP !
      PORTD = 0b11110100;   //   Pull Ups aktivieren, mit pololuMot AUCH bei INT0/~1
                            //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ...
    ...
      XTI0_int ( );                 // Initialisiere Interrupt 0, PD2, auf ANY edge
    ...
                            //
    // ============================================================================= =
      sei();                // ###  Globalen Interrupt freigeben <<<<<#####
    // ============================================================================= =
    ...
    // ============================================================================= =
    // ===  Initialisierung externer Interrupts 0 bei m328, doc 8271I
    //      INT0 auf PORTD2  --  ServoPuls auf PIND2
    //      Dokumentation ATmega328-P_Atmel-42735B_Complete-11-2016_NEU-NEU..NEU.pdf
    // ============================================================================= =
      void XTI0_int( void )            // Initialisiere Interrupt 0, PD2, auf ANY edge
     {                              //  => EICRA ISC00 + ~10 auf 1                 S89
    // - - - - - - - - - - - - - - - -
      EIMSK        |=  (1<<INT0);   // erlaube INT0
      EICRA        |=  (1<<ISC00);  // INT0 triggert auf jede Flanke (any edge) ?? S89
    //EICRA        |=  (1<<ISC01);  // INT0 triggert auf jede Flanke (any edge)    S89
      IZTtmrA       =       555;    // Timer f Stoppen Servopuls; läuft wenn PD2 high
      tPLShi        =       555;    //
      tPLSlo        =       555;    //
                                    //
     }      // Ende von void XTI_0_init( void )
    // ============================================================================= =
    
    
    // ============================================================================= =
    // ===  Nicht unterbrechbare ISR für EXT_INT0{any edge} auf mega328      ======== =
    //      Aufruf bei Signalumschlag des Servo-Datenkanals.
    //      Prüfung Pulsanfang oder -ende ?
    //      Pulsanfang:     <=> PD2/INT0 ist high
    //                      setze IZTmrA zurück auf 0 (Null)
    //                      speichern TCNT1 (max 1023) nach s16 Pulsan
    //      PulsEnde:       <=> PD2/INT0 ist low
    //                       => speichern Diff TCNT1 - Pulsan nach Pulshi
    //                       => speichern IZTmrA
    //              #############################################
    //  cli(); A3ist = TCNT1; sei();  // Nicht-atomarer Wert TCNT1 ! ! !, max 1023 !!!
    //      ##>     Richtungskonform prüfen ! ! ! ? ? ?
    // ============================================================================= =
    // ============================================================================= =
      ISR(INT0_vect)                // INT0-PD2 triggert ANY edge => lesen 
     {                              //   => Bei Aufruf PORTD2 prüfen auf high/low 
      if (((PIND) & (1<<PD2))?1:0)
      { PORTC  |=  (1<<PC0); }
      else
      { PORTC  &= ~(1<<PC0); }
     }      // Ende ISR(INT0_vect)
    // ============================================================================= =
    Die vorgestellten Probleme laufen mit 20MHz/Resonator ebenso wie mit 8 MHz/int-Oszillator.

    Fragen
    Hat bitte jemand eine Idee was da falsch läuft?
    Kann mir bitte jemand einen Rat geben wo ich noch nach Fehlern suchen kann?

    Nachtrag:
    Bitte um Nachsicht, dass ich sooo viel schreiben muss - müsste ja alles gelesen werden.
    Ciao sagt der JoeamBerg

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Hallo oberallgeier,

    Zitat Zitat von oberallgeier Beitrag anzeigen
    Die verlangte Funktion wird NUR erreicht, wenn ISC01 und ISC00 zu Null gesetzt sind, das heißt lt Datenblatt ".. The low level of INT0 generates an interrupt request .."

    Auszug aus dem Datenblatt zu mega328p (ATmega328-P_Atmel-42735B_Complete-11-2016, S 89):
    Code:
    ISC01 . ISC00 . . Description
     .0 . . . 0 . . . The low level of INT0 generates an interrupt request.
     .0 . . . 1 . . . Any logical change on INT0 generates an interrupt request.
     .1 . . . 0 . . . The falling edge of INT0 generates an interrupt request.
     .1 . . . 1 . . . The rising edge of INT0 generates an interrupt request.
    In Deinem geposteten Testcode wird ISC00 aber auf 1 gesetzt und damit entgegen dem Kommentar in der gleichen Zeile richtig auf "Any logical change on INT0 generates an interrupt request." gesetzt.

    Der ganze Testcode
    Code:
      void XTI0_int( void )            // Initialisiere Interrupt 0, PD2, auf ANY edge
     {                              //
    // - - - - - - - - - - - - - - - -
      EIMSK   |=  (1<<INT0);        // erlaube INT0
      EICRA   |=  (1<<ISC00);       // low level of INT0 generates an interrupt request
                                    //  =>  im Test triggert   J E D E   Flanke
                                    //  Oskar zeigt korrektes Abbild von PD2/INT0
    Alle anderen Varianten zeigen (Oskar) entweder keine exakte Kopie der Pulsform, nur 20 ms - Pulse oder gar nichts.
    Find ich in Ordnung. Der Testcode tut das was er soll.

    Derselbe Code in den komplex(er)en Projektquellen führt zu keiner Ausgabe der auf INT0 eingelesenen Daten.

    Fragen
    Hat bitte jemand eine Idee was da falsch läuft?
    Kann mir bitte jemand einen Rat geben wo ich noch nach Fehlern suchen kann?
    Möglicherweise ist der Bug in den anderen Projektquellen. Der Testcodeprogrammteil im komplexen Code scheint mir in Ordnung.

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686

    Problem Erledigt

    Grüß Dich Searcher!

    .. In Deinem geposteten Testcode wird ISC00 aber auf 1 gesetzt .. richtig auf "Any logical change on INT0 generates an interrupt request." ..
    Hmmmm. Auaaa. Du hast ja Recht und ich war blind - wohl von der mentalen Art (Leseschwäche hab ich nicht, dachte ich) :-// So ein Mist!

    .. Möglicherweise ist der Bug in den anderen Projektquellen ..
    Noch mehr eigene Blö...Blindheit. Jetzt habe ich statt des (älteren) Files #include "Sbbo2_mot14.c" den aktuellen File #include "Sbbo2_mot16.c" in der Hauptquelle eingetragen, den ich immer fleissig editiert, aber nicht includiert hatte. Nu läufts auch in diesem, eigentlichen Programm. Ich fürchte ich muss mir da über meine Geisteskräfte Gedanken machen.

    Ohhh mannnohmannn, danke! War ne Riesenhilfe.
    Ciao sagt der JoeamBerg

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Freut mich, daß ich helfen konnte Wer kennt das nicht, daß man den Wald vor Bäumen nicht mehr sieht, wenn man schon mitten drin steht?

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

Ähnliche Themen

  1. [ERLEDIGT] Atmega32: Frequenzabhängiges Problem mit INT0 und Timer0
    Von Kokomoking im Forum C - Programmierung (GCC u.a.)
    Antworten: 8
    Letzter Beitrag: 22.04.2012, 14:13
  2. Int0 wird bei direkt bei 'Enable Int0' ausgelöst - Warum?
    Von malthy im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 30.08.2010, 19:10
  3. Int0 / Int1 Problem ( Prellen )
    Von BlaueLed im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 28.01.2010, 12:38
  4. Unverständliches Problem mit INT0 / INT1
    Von popi im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 7
    Letzter Beitrag: 04.09.2008, 15:34
  5. Problem aus Powerdown mit int0 bei mega8 ...
    Von Charly_cs im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 08.07.2007, 13:43

Stichworte

Berechtigungen

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

12V Akku bauen