- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

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

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

    Servosignal von Timer1 KanalA und ~B zeigt Ausfälle

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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

  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,
    könnte das Problem auftauchen, weil das Setzen von OCR1B nicht mit dem Timerstand (TCNT1) abgestimmt ist?

    Die while Schleife, in der das Setzen von OCR1B stattfindet läuft unabhängig vom Timer1 bzw umgekehrt. Die beiden sind nicht synchronisiert.

    Nun könnte es passieren, daß gerade ein CompB Interrupt aufgetreten ist, OCRB erhöht wird und aufgrund des TCNT1 Standes und Weiterlaufen des Timers das Interrupt Flag sofort neu gesetzt wird. (Interrupt tritt nicht auf, da disabled)

    Im folgenden Compare1A Interrupt wird Compare1B enabled und aufgrund des stehenden Compare1B Flags tritt sofort der Compare1B Interrupt auf und löscht das gerade von Compare1A gesetzte PB2 wieder. (Der Peak?)

    Das könnte solange gehen bis die while Schleife und Timer auseinandergedriftet sind, daß das Compare1B Flag nicht mehr zum falschen Zeitpunkt gesetzt wird.

    Versuch: In der Compare1A ISR vorsorglich das Compare1B Interruptflag löschen.

    (Fals ich Müll erzählt habe, schiebe ich es der Einfachheit halber auf fehlende C-Kenntnisse )

    Gruß
    Searcher
    Geändert von Searcher (19.10.2012 um 15:23 Uhr)
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Hallo,

    ich verwende keine AVRs, kann also die Einstellungen der Timerregister nicht überprüfen. Ich will mich trotzdem mal an eine Fehlersuche wagen.

    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.

    Dieses gibt mir zu denken. Wenn deine Pulszeit ganz dicht an den 2ms ist, könnte folgendes Problem auftreten: ein Heartbeat wird bearbeitet, während der Zeit tritt sowohl ein COMPA als auch ein COMPB Ereignis ein, und nach dem Heartbeat werden die Interrupte in der falschen Reihenfolge bearbeitet.

    Ich würde die Aufgabe anders lösen:

    Du programmierst einen Timer auf die gewünschte Pulslänge und setzt den Ausgang. Kommt jetzt der Interrupt, setzt du den Ausgang zurück, holst dir den Wert für den nächsten Kanal aus einer Tabelle programmierst den Timer und setzt den nächsten Ausgang usw. Wenn du durch alle durch bist, machst du einfach einen längeren Puls ohne einen Ausgang zu setzen, um auf die ungefähr 20ms zu kommen. Wenn die 20ms genau sein sollen, kann man alle Pulse aufaddieren und von 20ms abziehen. Damit bekommt man für kleines Geld 10 Servos gesteuert.

    Ich sehe gerade, Searcher denkt in eine ähnliche Richtung.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Hi Searcher, hi Klebwax,

    danke für die prompte Antwort, danke für die Lesearbeit.

    Zitat Zitat von Searcher Beitrag anzeigen
    ... Nun könnte es passieren, daß gerade ein CompB Interrupt aufgetreten ist...
    (Fals ich Müll erzählt habe, schiebe ich es der Einfachheit halber auf fehlende C-Kenntnisse ) ...
    Und was ist, wenn Du nun gerade keinen Müll erzählt hast? Dein Tip mit den Interruptflags in den Registern scheint jedenfalls zu stimmen, der Oskar zeigt gerade seit rund zwölf Minuten ein gleichmässiges Bild des Testlaufs. Ich hatte lediglich in der T1CmpA-Routine vor dem T1CmpA-Match enabled das OCF1B gesetzt - und schön läufts. Die Gegenprobe mit Löschen des OCF1B lieferte ähnliche geht-gehtnicht-Erscheinungen (nur viel schneller) als die Ausgangsversion.

    Zitat Zitat von Klebwax Beitrag anzeigen
    ... Aufgabe anders lösen ... und setzt den nächsten Ausgang usw.
    Danke für den Tip. Klar, das geht - und ist vermutlich schneller programmiert und am Laufen. ABER - eine sequentielle Pulsausgabe kann eben je nach Pulslänge der verschiedenen Servos die Nachfolger mit wechselnden Periodenlängen versorgen - dann stimmt im Prinzip der Puls nicht mehr zur Periode. Daher mein Bemühen die verschiedenen Pulse in einem tmerfixierten Raster loszuwerden und die gewünschte Periodenlänge stabil zu halten.

    Und es scheint ja zu gehen (mittlerweile seit zwanzig Minuten störungsfrei). Und wenn ich den Vorteiler für den Timer von 64 auf 8 runtersetze, dann könnte ich sogar eine Feinheit der Rampen von knappen fünftausend Strichen schaffen - aber dass meine Servos so eine Genauigkeit schaffen glaub ich nicht.

    Danke Euch beiden.
    Ciao sagt der JoeamBerg

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Zitat Zitat von oberallgeier Beitrag anzeigen
    ...Und was ist, wenn Du nun gerade keinen Müll erzählt hast? Dein Tip mit den Interruptflags in den Registern scheint jedenfalls zu stimmen, ...
    Dann freut mich das und Danke für die Rückmeldung. Es soll aber auf gar keinen Fall heißen, daß ich nicht doch fehlende C-Kenntnisse hätte und ich hab mich in das Abenteuer auch nur reinbegeben weil es um Timer ging

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

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Danke für den Tip. Klar, das geht - und ist vermutlich schneller programmiert und am Laufen. ABER - eine sequentielle Pulsausgabe kann eben je nach Pulslänge der verschiedenen Servos die Nachfolger mit wechselnden Periodenlängen versorgen - dann stimmt im Prinzip der Puls nicht mehr zur Periode. Daher mein Bemühen die verschiedenen Pulse in einem tmerfixierten Raster loszuwerden und die gewünschte Periodenlänge stabil zu halten.
    Ich denke, du gibst dir da an der falschen Stelle Mühe. Bei einem Servo ist, in Grenzen natürlich, das Puls/Pause Verhältnis unerheblich. Ich kenne (aus der Zeit vor den µC) Schaltungen von Fernsteuersendern, die einfach eine Kette von Monos waren. Alle Kanalpulse wurden nacheinander erzeugt, und dann kam noch eine feste Pause. Die Periodenlänge ist dabei grundsätzlich nicht konstant.

    Aber mit meinem Vorschlag kannst du auch eine konstante Periode haben, wenn du die Pausenzeit aus der Summe der Pulse ausrechnest.

    Und es scheint ja zu gehen (mittlerweile seit zwanzig Minuten störungsfrei). Und wenn ich den Vorteiler für den Timer von 64 auf 8 runtersetze, dann könnte ich sogar eine Feinheit der Rampen von knappen fünftausend Strichen schaffen - aber dass meine Servos so eine Genauigkeit schaffen glaub ich nicht.
    Je feiner du steuern willst, desto schneller sollten die Servos reagieren. Wenn du also, mal unabhängig von der Genauigkeit der Servos, 5000 Positionen ansteuern willst, brauchst du 100 sec (1 neuer Positionswert alle 20ms).

    Ich würde sogar versuchen, die Periodendauer soweit als möglich zu reduzieren. So etwas machen auch die Kopterbauer. Also mal dein einkanaliges Testprogramm auf eines deiner Servos arbeiten lassen und die Periodendauer verkürzen, bis es gerade noch geht. Das dann mal mit allen Servos testen, und um eine Reserve erhöhen.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  7. #7
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Ich denke, du gibst dir da an der falschen Stelle Mühe ...
    Hallo Klebwax,

    Du hast Recht und ich hoffe, dass Du nicht denkst, dass ich gute und freundliche Ratschläge ablehne oder einfach nicht befolge. Das mit der falschen Stelle klingt nicht nur so, aber ... Ich wollte dieses Vorhaben schon vor vielen Monaten bei meinem Servotester durchgehen, hatte mir aber nicht die Zeit dazu genommen - und auch die Sache mit den Timern völlig ungenügend verstanden. Nun brauche ich eine Baugruppe "sechs bis sieben Servos" und will dabei auch gleich meine Kenntnisse im Umgang mit den Timern verbessern. Auch die Kenntnisse in C. Und in dieser alte Absicht steckt sicher auch noch mein damaliges Unwissen über Servos (und das Unwissen gabs noch immer - hattest Du ja auch sauber aus meinem Posting rausgelesen).

    ... Bei einem Servo ist, in Grenzen natürlich, das Puls/Pause Verhältnis unerheblich ...
    Ja, da gabs z.B. mal eine hübsche Untersuchung von lokirobotiks, nach der ich auch im RNWissen im Servoartikel auf diese Toleranz der Servos und lokirobotiks Arbeit hingewiesen hatte. Aber danke, dass Du mir das durch eigene Erfahrungen bestätigst.

    ... 5000 Positionen ... 100 sec (1 neuer Positionswert alle 20ms) ... Periodendauer soweit als möglich zu reduzieren ...
    Genau. Da habe ich auch ein Auge drauf. Derzeit habe ich in meinem Aufbau billige 5Euro-Teile und war überrascht, wie weit runter die noch sauber laufen . . . Insgesamt bin ich auch verblüfft darüber, wie weich man sogar die billigen Servos selbst bei langsamen Schwenks fahren kann (satte 20 ms für 1 Pulsincrement das theoretisch einem Drittel Winkelgrad entspricht). Natürlich freut mich auch, dass das ursprüngliche Vorhaben mit Eurer Hilfe so funktioniert wie ich es mir vorgestellt hatte.

    Nochmal danke für Deine Mühe und bitte nicht krumm nehmen, dass ich manchmal nicht alle Ratschläge befolge (aber meistens trotzdem einsehe - früher oder später).
    Ciao sagt der JoeamBerg

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Nochmal danke für Deine Mühe und bitte nicht krumm nehmen, dass ich manchmal nicht alle Ratschläge befolge (aber meistens trotzdem einsehe - früher oder später).
    Kein Problem. Hauptsache die Idee ist rübergekommen. Vielleicht kannst du noch mal woanders einsetzen, Ideen kann man nie genug auf Vorrat haben.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo zusammen.

    Hier nur eine Haarspalterei am Rande, die auch nichts mit der grundsätzlichen Funktionalität zu tun hat. (oberallgeier bitte verzeih mir!)

    In deiner Test-Funktion benutzt du folgenden Code:
    Code:
        for (ilng = PWMmin; ilng <= PWMmax; ilng++)
         {                           //
           cli();                    // ###
           OCR1B       = ilng;       //
           sei();                    // ###
           waitms (  srvwt);         //
         }           // ### Ende for (ilng = ...
    Hier beim Schreiben in das OCRnx-Register kannst du getrost auf das cli() und sei() verzichten. Diese Register sind gepuffert und vertragen eine Unterbrechung durch Interrupts. (Mit der Ausnahme, wenn du in einer beliebigen INT-FNC auf das Register schreibst! Was du in deinen Code-Ausschnitten aber nicht machst.)
    Klar, es bleibt, dass beim Lesen leider doch mit INT-sei(n)-oder-nicht-sei(n) gewerkelt werden muss.

    Im dicken PDF zu den AVRs (angefangen beim atmega8 bis zum atmega644) ist das so beschrieben:
    When the High byte I/O location is written by the CPU, the TEMP Register will be updated by the value written. Then when the Low byte (OCR1xL) is written to the lower eight bits, the High byte will be copied into the upper 8-bits of either the OCR1x buffer or OCR1x Compare Register in the same system clock cycle.


    Aber wie gesagt: Hat nichts mit der eigentlichen Funktion zu tun. (Soll nur Bytes sparen)

    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  10. #10
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Zitat Zitat von Sternthaler Beitrag anzeigen
    ... Haarspalterei ... (Soll nur Bytes sparen) ...
    Ich liebe Haarspaltereien - ich meine Codezeileneinsparungen.

    Zuerst hatte ich diese cli();/sei();-Geschichte nicht verwendet. Hatte mich dabei schon gewundert, dass es sozusagen trotzdem funktionierte . . . und die Zeilen nachgetragen. Nun weiß ich, warum es funktionierte, denn ich habs im Datenblatt gesucht und gefunden. Habe aber noch nicht in der *.lls nachgesehen, ob der Compiler das richtig macht(e) *ggg*. In der aktuellen Version wird nämlich OCR1B sowieso erst in der ISR (TIMER1_COMPA_vect) mit Daten aus dem Feld für die maximal möglichen zehn Servos beschrieben/geladen. Und da ich keine nested Interrupts verwende . . habe ich aktuell auch die cli();/sei();-Geschichte eingespart. Trotzdem

    Danke.
    Ciao sagt der JoeamBerg

Seite 1 von 2 12 LetzteLetzte

Ä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
  •  

Labornetzteil AliExpress