- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 12

Thema: Servosignal von Timer1 KanalA und ~B zeigt Ausfälle

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.693

    Servosignal von Timer1 KanalA und ~B zeigt Ausfälle

    Hallo C-Spezialisten,

    heute kommt wieder (m)ein C-Spezialproblem, das ich seit vier Tagen nicht lösen kann. Tests auf zwei verschiedenen Targets und Controllern (Steckbrett mit mega328/20MHz und RNControl mit m1284/20MHz) bringen gleiche Ergebnisse - soweit ein eher zufällig aussehender Fehler dieses Urteil zulässt. Recherchen zum Stackpointer bei AVR-GCC sagten mir, dass ich den SP nicht anfassen muss/müsste. Die Dokumentationen der Controller zu den Timern brachten mir auch keinen Fortschritt. Nun bleibt mir nur noch diese Anfrage.

    Aufgabenstellung (Fernziel):
    i) Ein Controller soll sechs bis sieben Servos treiben, maximal 8
    ii) Normale Servos (bzw. die billigen Analogmodelle)
    iii) Die Verstellgeschwindigkeit MUSS variabel sein
    iv) Die Servos müssen unabhängig voneinander fahren
    v) Mein Standardtimer 20kHz toggelt eine "Herzschlag"-LED

    Lösungsweg:
    v) Timer1 (16 bit) erzeugt mit Kanal-A/OCR1A ein Achtel (1/ 8 der Servoperiode
    OCR1A ist üblicherweise 800 - ergibt insgesamt dann ca. 20 ms Periode
    vi) Timer1 erzeugt mit Kanal-B/OCR1B die Servorampe (=Verstellwinkel)
    OCR1B wird zwischen 300 und 600 schwanken - ca. 1 bis 2 ms,
    getestet wurde erfolgreich Werte zwischen 280 und 620
    vii) Ein Feld mit 8 int16-Werten enthält die gewünschten Rampenlängen
    viii) Die Rampenlänge OCR1B ist deutlich kürzer als OCR1A - s.o.
    ix) AVR-STudio4

    Realisierung (derzeit vorwiegend mit konstantem Schaltpin = Kontroll-LED)
    x) Timer1_A startet im ersten Durchlauf den Servo-Pin/LED und
    startet Timer1_B = enable CompareB Match : TIMSK1 |= (1<<OCIE1B)
    xi) Timer1_B löscht in seinem ersten Interrupt den Servopin
    und disabled den eigenen Interrupt : TIMSK1 &= ~(1<<OCIE1B)
    xii) Testweise wird OCR1B in den Grenzen rauf- und runtergefahren.
    xiii) Ein Test mit OCR1A = 6400 <=> der Timer1_A erzeugt die 20-ms-Periode in einem Durchlauf und startet NUR einmal den Timer1_B für eine auf-und-ab-gehenden OCR1B-Rampe - läuft bisher störungsfrei. Der zugehörige Servo lässt sich mit Stellgeschwindigkeit von "normal" bis ca. 1/4 der üblichen Geschwindigkeit praktisch ruckelfrei fahren. Langsamere Schwenkgeschwindigkeiten erzeugen mehr oder weniger deutliches Ruckeln. Dabei dreht der angeschlossene Servo mustergültig. Es scheinen nach längerer Laufzeit - mehreren Minuten - auch Fehler aufzutreten.
    xiv) Das "Servosignal" wird im Oszilloskop beobachtet und durch das Leuchten der LED angezeigt.
    xv) Controller und Servo werden getrennt versorgt, GND´s sind verbunden.

    Später soll ein umlaufender Pointer die verschiedenen Werte der Rampenlänge als OCR1B nehmen und damit die zugehörigen Pinne schalten. Derzeit wird NUR die Kontroll-LED geschaltet.

    Beobachteter Fehler:
    xxi) Beim Betrieb des Timer1_A mit 20ms und nur einer Rampe - also das Servo-Standardsignal läufts problemlos.
    xxii) Der Betrieb mit dem Timer1_A mit 2ms und der darin erzeugten Rampe von 1 bis <2 ms läuft teilweise minutenlang.
    xxiii) Die erzeugte Rampe läuft programmgemäß rauf und runter.
    xxiv) Meist fällt die erzeugte Rampe nach (dem ersten) Auf-Ab-Zyklus praktisch aus, es ist nur ein mikrosekundenlanger Peak im 2ms-Takt zu sehen.
    xxv) Seltsameweise kommt die Rampe programmgerecht nach einiger Zeit wieder . . .
    xxvi) Wiederholen der Initialisierung des Timer1 - am Ende eines Auf-Ab-Zyklus brachte weniger Störungen - aber keine Störungsfreiheit.

    Wer es bisher gelesen hat - danke für die Aufmerksamkeit.

    Frage: Wo könnte der Fehler (noch) liegen?

    Danke für Eure Geduld, Aufmerksamkeit und Hilfe.

    Zur Erläuterung noch der Code (einige Kommentarzeilen, Portinitialisierungen etc. rausgekürzt)

    Auszug Hauptprogramm
    Code:
    // ============================================================================== =
    // ===  HAUPTProgramm =========================================================== =
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     int main(void)
    //      ......
    // - - - - - - - - - - - - - - -
    // Ports+Pins als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
    //      A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
      DDRB  = 0b11111111;   // siehe aktuell oben
      PORTB = 0b00000000;   //    und Port/Pull Ups (1)  aktivieren
                            //
      DDRC  = 0b11111111;   // PC0 .. 6 , kein PC7-Pin bei m168/328 in THT
      PORTC = 0b00000000;   // PC0 und ~1 sind ADC-Eingänge ##>> OHNE Pullup !!
                            // 
      DDRD  = 0b11111110;   // -> siehe unter DDRB
      PORTD = 0b00001001;   //    Pull Ups aktivieren, NICHT bei extINT0/~1
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      ......
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      TC1TMR_init();        // Init Tmr/Cntr1 für PWMs/Servo                      ~tmr~
    // - - - - - - - - - - - - - - -
      Izeit_1       = 20000;    // Der ZeitHorizont für ISR(TIMER2_COMPA_vect)
      Izthrznt      = 20000;    // Der ZeitHorizont für ISR(TIMER2_COMPA_vect)
      Isecundn      = 1;    // Sekundenzähler, max 9 Stunden - NUR hier nullen
      TC2TMR_init();        // Init Timer/Cntr2-Interrupt 20 kHz/50 µsec          ~tmr~
                            //   ISR gibt auf PC3 ein Taktsignal aus
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      sei();        //Globalen Interrupt freigeben
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      init_USART0(MYUBRR);  // USART0 initialisieren m wählbarer Baudrate (s.o.)  ~inf~
    //      ......
    // ============================================================================== =
    //  Testabschnitt(e).     
    // ============================================================================== =
    //      ......
      uart_puts("\tEs folgt Aufruf I2CTST01()\r\n");
      I2CTST01();           //
    //      ......
    // =====  Ende main
    // ================================================================================
    /*  Es folgt der aktuelle Übersetzungskommentar:
    Build started 19.10.2012 at 09:51:33
    avr-gcc  -mmcu=atmega328p -Wall -gdwarf-2 -std=gnu99       
            -DF_CPU=20000000UL -Os -funsigned-char -funsigned-bitfields 
            -fpack-struct -fshort-enums -MD -MP -MT R5Sv1.o 
            -MF dep/R5Sv1.o.d  -c  ../R5Sv1.c
    avr-gcc -mmcu=atmega328p -Wl,-Map=R5Sv1.map R5Sv1.o     -o R5Sv1.elf
    avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  
            R5Sv1.elf R5Sv1.hex
    avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
            --change-section-lma .eeprom=0 --no-change-warnings 
            -O ihex R5Sv1.elf R5Sv1.eep || exit 0
    avr-objdump -h -S R5Sv1.elf > R5Sv1.lss
    
    AVR Memory Usage
    ----------------
    Device: atmega328p
    
    Program:    1566 bytes (4.8% Full)
    (.text + .data + .bootloader)
    
    Data:        408 bytes (19.9% Full)
    (.data + .bss + .noinit)
    
    Build succeeded with 0 Warnings...
    
     ============================================================ */
    Auszug header
    Code:
    // ============================================================================== =
    // ============================================================================== =
    //      ##### Variablenliste, global #####
    // ============================================================================== =
    // ============================================================================== =
                                    //
      #define SetBit(ADDR,BIT)       ((ADDR)  |=  (1<<(BIT)))       // Setzt Bit
      #define ClrBit(ADDR,BIT)       ((ADDR)  &= ~(1<<(BIT)))       // Löscht Bit
      #define ToggleBit(ADDR,BIT)    ((ADDR)  ^=  (1<<(BIT)))       // Toogelt Bit
    // - - - - - - - - - - - - - - - -
    //      ......
     volatile int16_t Izeit_1;      //  Timer mit 20 kHz  Wertbereich int16: 32.767
     volatile int16_t Izthrznt;     // Der zeitliche Horizont, z.B. 20000 für 1 sec
     volatile int16_t Isecundn;     // Sekunden Programmlaufzeit, 32.767 sec sind ...
    // ============================================================================== =
    // ============================================================================== =
    Auszug Testroutine:
    Code:
    // ============================================================================== =
    // ==  Routine zum "Normalbetrieb"
    // ============================================================================== =
     void SrvTST_03(void)           // Servo Testbetrieb, übernommen aus :
                                    //      war SrvTST_01 in ~r1n01d
     {                              //
      uint16_t   ilng;              // Siehe for-Loops in RCBB == 25 und RCBB == 6
      uint16_t nochnl;              // for-Loop "nochnloop"
      uint16_t PWMmin, PWMmax;      // PWM-Grenzen
      uint16_t  srvwt;              // wait-Millisekunden für Servoloop
    // - - - - - - - - - - - - - - -
      PWMmin        = 300;          //
      PWMmax        = 640;          //
      srvwt         =  25;          //
    // - - - - - - - - - - - - - - -
      uart_puts ("\tStart Servo-Test03 ~r1n01\r");   //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      while (1)                     //
      {                             //
        for (ilng = PWMmin; ilng <= PWMmax; ilng++)
        {                           //
          cli();                    // ###
          OCR1B       = ilng;       //
          sei();                    // ###
          waitms (  srvwt);         //
        }           // ### Ende for (ilng = ...
    // - - - - - - - - - - - - - - -
        for (ilng = PWMmax; ilng >= PWMmin; ilng--)
        {                           //
          cli();                    // ###
          OCR1B       = ilng;       //
          sei();                    // ###
          waitms (  srvwt);         //
        }           // ### Ende for (ilng = ...
      }             // ### Ende while (1)
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      uart_puts ("\tEnde Servo-Test03 ~r1n01\r");   //
      return;       // ### Ende von void SrvTST_03(void)
     }                              //
    // ============================================================================== =
    Auszug Timer, Initialisierung-en und ISR
    Code:
    // ============================================================================== =
    // ==   Timer  Aufgabe: Servo mit Soft-PWM ansteuern auf wählbarem Port
    // - - - - - - - - - - - - - - - -
      void TC1TMR_init(void)        // Init Timer/Counter 1 für 2 ms Servoperiode
      {                             //
        TCCR1B  |= (1<<WGM12);      // WGM12 => CTC, TOP = OCR1A                   S133
        TCCR1B  |= (1<<CS11)|(1<<CS10); // CS11/10 <=> clk/64 => 312 500 Hz        S134
        OCR1A    =  800;            // Mit OCR1A = 6250 => alle 20 ms ein Interrupt
        TIMSK1  |=  (1<<OCIE1A);    // Tmr/Cntr1 Oput CompA Mtch intrrpt enabled
      }                                
    // ============================================================================== =
    
    
    // ============================================================================== =
    // ===  Nicht unterbrechbare ISR für TIMER1_COMPA_vect     ====================== =
     ISR(TIMER1_COMPA_vect)         // VECTOR 8                                    S 65
      {                             //
        SetBit (PORTB, 2);          // LED/PB2 high, wird von Timer1_COMPB gelöscht
        TIMSK1 |=  (1<<OCIE1B);     // Tmr/Cntr1 CompB Match interrupt enabled
      }                             //
    // ============================================================================== =
    
    
    // ============================================================================== =
    // ===  Nicht unterbrechbare ISR für TIMER1_COMPB_vect     ====================== =
     ISR(TIMER1_COMPB_vect)         // VECTOR 9                                    S 65
      {                             //
        ClrBit (PORTB, 2);          // LED/PB2 gelöscht
        TIMSK1 &= ~(1<<OCIE1B);     // Tmr/Cntr1 CompB Match interrupt disabled
      }                             //
    // ============================================================================== =
    
    
    // ============================================================================== =
    // ===  Initialisierung fuer Timer2 mega168 ===================================== =
     void TC2TMR_init(void)         // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
     {                            //
      TCCR2A |= (1<<WGM21);         // Timer im CTC-Mode, Top=OCR2A   doc S 157
      TCCR2B |= (1<<CS21);          // Prescaler 1/8 / Clock <- CPU      doc S 158
      OCR2A = 124;                  // Preset 124 für 50µs bei 20Mhz  
      TIMSK2 |= (1<<OCIE2A);        // Tmr/Cntr2 CompareA interrupt enabled
     }                              //
    // ============================================================================== =
    
    
    // ============================================================================== =
    // ===  Nicht unterbrechbare ISR für timer2 ===================================== =
    // Routine zählt hoch im Takt 20 kHz = 50 µs.  Der Zählerwert wird von den ISR für
    //      EXT_INT0 und -INT1 ausgelesen und den Werten Iz_yseci zugewiesen
     ISR(TIMER2_COMPA_vect)         // Vektor 7
     {                              //
      if (Izeit_1)                  //Interrupt-Timer = 1 ... 20 000 ... (1 sec blink)
      {                             //
        Izeit_1 --;                 //  ###>>> Izeit_1 ist aktuell int16_t ==>>
                           //  Izeit_1 bleibt bis 32000 in der int16-Grenze
      }                             //
      else                          // Eine Sekunde ist voll =>
      {                             //
        Izeit_1 = 20000;            // Rückstellen auf 20000
        Isecundn ++;                // Sekundenzähler hochtackern, max 9 Std
        ToggleBit (PORTC, L1g);          // LED/PB2 gelöscht
      }                     // Ende if (Izeit_1 < Izthrznt)
      return;                       //
     }                              //
    // ============================================================================== =
    
    
    // ============================================================================== =
    // ============================================================================== =
    //### Programm pausieren lassen  !! Der Pausenwert ist nur experimentell !
    
    void waitms(uint16_t ms) 
    { 
       for(; ms>0; ms--) 
       { 
          uint16_t __c = 4000; 
          __asm__ volatile ( 
             "1: sbiw %0,1" "\n\t" 
             "brne 1b" 
             : "=w" (__c) 
             : "0" (__c) 
          ); 
       } 
    } 
    // ============================================================================== =
    
    
    // ============================================================================== =
    // =====  ENDE    Subroutinen  ================================================== =
    // ============================================================================== =
    Geändert von oberallgeier (19.10.2012 um 10:18 Uhr) Grund: Durch autoedit des Forumprogramms entstandene Smileys entfernt
    Ciao sagt der JoeamBerg

Ähnliche Themen

  1. Pulsgenerator für servosignal
    Von Horstel im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 10.06.2007, 12:58
  2. Servosignal erzeugen
    Von Sukilin im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 30.05.2007, 16:04
  3. Servosignal schaltet nicht ab
    Von Andree-HB im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 6
    Letzter Beitrag: 28.01.2005, 21:38
  4. PCM-Servosignal-Erkennung
    Von odlanir im Forum Controller- und Roboterboards von Conrad.de
    Antworten: 4
    Letzter Beitrag: 27.04.2004, 18:47

Berechtigungen

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

Solar Speicher und Akkus Tests