-
        

Seite 1 von 4 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 31

Thema: PWM Erzeugung 18* Simultan

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150

    PWM Erzeugung 18* Simultan

    Anzeige

    Hallo Leute, ich hab mal wieder das Thema PWM aufgegriffen und habe eine Idee, wie man 18 oder mehr Servo PWMs mit nur einem 16-Bit-Timer mit einer Auflösung von 15 Bit erreichen kann.
    Angenommen der µC arbeitet bei 16MHz, dann kann der 16Bit Timer taksynchron maximal 4.096ms darstellen. Also kann man auch einen ganzen Puls (max. 2.5ms) vorladen, starten und beim Überlauf beenden.
    wenn man jedoch 18 signale gleichzeitig erzeugen will, so startet man alle PWM gleichzeitig, lädt den timer mit der gerigsten PWM dauer vor und wenn der überläuft,dann wird der kürzeste PWMbeendet, der Timer mit einer differenzzeit bis zum nächsten zu beendenden Impuls vorgeladen und so weiter.
    also wenn in einem Array x[18] die pulsdauern liegen, so muss man diese zunächst sortieren in s[18] und die reihenfolge der indizes liegt in i[18]. also der kleinste wert von x[] steht in s[0] und in i[] steht der index des kleinsten Wertes aus x[]. nun werden in t[18] die benötigten Zeitdifferenzen berechnet. also t[0]=s[0], t[1]=s[1]-s[0], t[2]=s[2]-s[3]...
    jetzt werden alle ausgänge auf high gesetzt,k=0, der 16Bit-Timer mit 2^16-t[k] vorgeladen, und beim überlauf wird k erhöht, der timer neu vorgeladen und stop(i[k]) wird aufgerufen. stop[n] beendet mittels einer case(n) struktur den entsprechenden Ausgang.


    Was haltet ihr von der Idee? man könnte natürlich für sehr kleine zeitdifferenzen gleich den nächsten impuls beenden, da die berechnungen wahrscheinlich länger brauchen als die differenzzeit andauert. Außerdem muss natürlich noch eine minimale korrekturzeit für die unterbrechung des ISR von den Zeitdifferenzen abgezogen werden.
    Aber sonst sollte es so möglich sein die relevanten 1,5ms mit mehr als 14 Bit aufzulösen, was für mich eine erhebliche steigerung wäre. momentan habe ich eine auflösung von ungefähr 200 schritten

    Bin offen für Kritik und anregungen...

    mfg WarChild[/flash]
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    ___|"""""""""|_______________________t[0];stop(i[k]);k++
    ___|""""""""""""|_____________________+t[1];stop(i[k]);k++
    ___|"""""""""""""|____________________+t[2];stop(i[k]);k++
    ___|""""""""""""""""""|________________+t[3];stop(i[k]);k++
    ___|"""""""""""""""""""""|______________+t[4];stop(i[k]);k++
    ___|""""""""""""""""""""""""|____________+t[5];stop(i[k]);k++
    ___|""""""""""""""""""""""""|____________stop(i[k]);k++ //da t[k]zu klein
    ___|"""""""""""""""""""""""""""|__________+t[7]];stop(i[k]);k++
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    28
    Beiträge
    607
    Deine Idee wird so in Realität leider nicht funktionieren, es wäre viel zu ungenau.
    Überleg z.B. was passiert, wen 2 Servos gleichzeitig auf LOW gestellt werden müssten, oder gar noch mehr Servos. Das würde mit dieser Funktion nicht gehen, ohne Genauigkeit einzubüßen (d.h. keine 15bit-Genauigkeit mehr)
    Außerdem würde der Interrupt viel zu viel Zeit in Anspruch nehmen. Allein die case-Struktur (die die Werte jedes mal neu aus dem SRAM laden muss) und der Funktionsaufruf würden die Zeit sprengen.
    Solche Funktionen, die sehr zeitkritisch sind, kann man nicht in C schreiben, sondern muss das in ASM machen.
    Wozu brauchst du denn eine so große Auflösung? 15bit können Servos doch überhaupt nicht darstellen. Eine Auflösung von 200 sollte doch reichen, oder?
    Ich bin gerade dabei, so eine Funktion für 18 Servosin ASM zu schreiben, allerdings verwende ich eine Genauigkeit von "nur" 180 Schritten und einen 20MHz-AVR. Theoretisch sollte auch eine Auflösung von ca.270 Schritten möglich sein. Viel höher geht es aber nicht, wenn es die Möglichkeit gibt, dass mehrere Servos gleichzeitig auf LOW gesetzt werden müssen.
    Wenn dir das nicht so wichtig ist, und im restlichen Programm darauf achtest, dass Servos nie den gleichen Wert haben, dann kannst du mit ASM eine Genauigkeit von ca. 1500 Schritten erreichen (schätzungsweise). Mit C wirst du nie so hoch kommen.
    Mit einem sehr ausgeklügelten Programm und einigen Zeiteinbußen könntest du sogar erreichen, dass einige Servos Parallel auf LOW gesetzt werden könnten (allerdings nur die, die am selben PORT hängen).
    Insgesammt ist sowas immer sehr schwer abzuschätzen, denn bei solch Zeitkritischen Programmen zählt jeder Befehl. Man müsste halt anfangen so eine Funktion zu schreiben, sie dann zu optimieren und dann gucken, was dabei rauskommt.
    18Servos deuten sehr stark auf einen Hexapoden hin, was bedeutet, dass Servos sehr wohl öfters den Selben Winkel haben. Außerdem braucht man meißt keine riesenhohe Auflösung für sowas, da die Servos sowieso nicht so genau sind, wie man es gerne wollte. Einen Unterschied von 0,5° wird niemand Merken. Mit einer 8bit-Auflösung spart man sich außerdem eine Menge Rechenzeit.

    Ich hoffe, ich hab dir ein wenig weiterhelfen können,

    Gruß, Yaro

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    naja es kommt mir mehr auf die Auflösung an, nicht auf die Abweichung.
    Wenn mehrere Servos gleichzeitig beendet werden müssen, dann stehen die zu beendenden signale in einem array, wenn der timer wieder läuft hat eine andere Funktion kurz Zeit um die Signale tatsächlich zu beenden. dass dabei verzögerungen von bis zu 200 zyklen auftreten ist mir egal.
    diese konstante zeitverzögerung kann man ja beim vorladen des timers berücksichtigen. Die absolute Abweichung in grad kann man ehh nicht feststellen, denn das geht im Lagerspiel unter.
    Meine derzeitige Auflösung von 200 Schritten kann man deutlich sehen. Es kommt sprunghaft zu einem längeren PWM, der servo will handeln, beschleunigt, schießt über das Ziel hinaus und er muss zurück....
    Je dichter die möglichen PWM längen beieeinander liegen, desto geringer ist die beschleunigung des Servos und desto flüssiger wirkt seine bewegung.
    In manchen Stellungen gerät mein Hexapod nähmlich genau aus diesem Überagieren der Servos in eine art Eigenschwingung. Da sein 4Kg die schnell beschleunigt werden relativ träge sind.

    Aber trotzem Dange. mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    28
    Beiträge
    607
    Das mit der Schwingung ist ein gutes Argument. Wird nicht genaz einfach sein, so eine Funktion zu schreiben, weil man sehr viel berücksichtigen muss, aber interessant ist es allemal.
    Ich werde in nächster Zukunft vielleicht auch mal soeine schreiben, wird aber noch mindestens 1-2Monate dauern, habe im Moment sehr viel zutun.

    Gruß, Yaro

  6. #6
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Ich sehe keinen wirklichen Grund Wieso die Servosignale alle Syncron starten müssen. Wenn man die Pulse hintereinander hat, sollten eine Auflösung bis auf etwa 3 Zyklen relativ einfach sein. Selbst Zyklusgenau sollte in ASM gehen, wenn da keiner zu lange interruts sperrt. Ist aber doch recht viel Aufwandt die letzten paar Zyklen auch noch zu syncronisieren.

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    das problem ist dabei nur dass ein 16Bit Timer seriell maximal 9 Signale a 2.2ms mit 50Hz erzeugen kann. Es sind also mindestenz zwei 16-Bit-timer von nöten, oder man muss viel mit "überläufe von 8-Bit-Timer zählen und aufsummieren" herumhantieren.

    Meine ersten versuche laufen jetzt, aber was ich eingestehen muss:
    Die signale werden wirklich äußerst genau aufgelöst, aber wenn die signale der Servos zu dicht beieinander liegen, dann wird geht die genauigkeit flöten. mal sehen, ob ich das irgendwie korrigiert bekomme.
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    30
    Beiträge
    150
    Dem problem ist nicht beizukommen. Der ISR schlckt einfach 50 takte und wenn alle 18 verschiedenen signale inerhalb eines bereiches mit einem maximalen abstand von 50 takten liegen, dann pflanzt sich da eine unschärfe fort, die beim letzten servo gute 5 grad beträgt, also unannehmbar.
    mal sehen, vlt kann ich dem 16Bit timer ja beibringen zwei signale gleichzeitig zu generieren, eines mit dem compare match interrupt und das zweite mit dem überlauf, dann muss man die nur so sortieren, dass immer ein kleiner wert und ein größerer wert gleichzeitig generiert wird.

    mfg WarChild
    Code:
    SIGNAL (SIG_OVERFLOW2)								// 1ms Interrrupt
    {
    	TCNT2 = 256 - 250;								//Timer2 mit 6 neu vorladen
    	timer2++;
    	timer3++;
    	if(timer2 == 20)								//alle Impulse starten
    	{
    		timer2 = 0;									//timer2 endet bei 20ms und startet ALLE 18 Signale
    		signal= 0;
    			servo1on;
    			servo2on;
    			servo3on;
    			servo4on;
    			servo5on;
    			servo6on;
    			servo7on;
    			servo8on;
    			servo9on;
    			servo10on;
    			servo11on;
    			servo12on;
    			servo13on;
    			servo14on;
    			servo15on;
    			servo16on;
    			servo17on;
    			servo18on;
    		cli();
    		TCNT1 = 65536-dtime[signal];			//Timer1 neu vorladen
    		sei();
    		TIFR |= (1 << TOV1);						//alten Overflow löschen
    		TIMSK |= (1 << TOIE1);						//Timer1 Overflow Interrupt freigegeben
    	}
    }
    
    
    
    //**************************************************//
    //Wird von Timer1 freigegeben und beendet die durch Timer2 gestarteten Pulse
    
    SIGNAL (SIG_OVERFLOW1)								//
    {	
    	stoppulse(sortindex[signal]);					//letzten Impuls beenden
    	delay=ISRdelay;
    	missing=0;
    	signal++;										//nächstes Signal
    	while(dtime[signal]<delay && signal<18)		//für kleine Zeitintervalle direkt den nächsten beenden
    	{
    		stoppulse(sortindex[signal]);
    		delay+=88;									//neue korrekturzeit bestimmen
    		missing+=dtime[signal];						//ubersprungene Zeit merken
    		signal++;
    	}
    	if(signal<18)									//solange noch Impulse zu beenden sind
    	{
    		cli();
    		TCNT1 = 65536-dtime[signal]-missing+delay;	//Timer1 neu vorladen
    		sei();
    	}
    	else											//sonst Timer1 beenden
    	TIMSK &= ~(1 << TOIE1);
    }
    //**************************************************//
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  9. #9
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.782
    Blog-Einträge
    8
    Hallo

    Es gibt unzählige Möglichkeiten viele Servos anzusteuern, hier möchte ich euch nochmal meine letzte Version vorstellen. Sie ist sicher nicht die beste Möglichkeit und mit 18 Servos funktioniert sie auch noch nicht richtig. Sie zeigt aber einen möglichen Ansatz ;)

    Code:
     // Servos ansteuern mit 8MHz Mega32 und 8-Bit Timer2 Overflow-ISR 22.3.2009 mic
    
    // Die Servosimpulse werden nacheinander erzeugt. Die Impulsdauer jedes Servos
    // setzt sich aus einem Grundimpuls (der für alle Servos gleich ist) und seinem
    // Positionswert zwischen 0 und 255 zusammen.
    
    // In der ISR werden im Wechsel ein Grundimpuls und ein Positionswert erzeugt
    // und zum jeweiligen Servo gesendet. Nach den Servoimpulsen wird eine
    // Pause eingefügt um die 50Hz Wiederholfrequenz (20ms) zu erzeugen.
    
    // Diese auf acht Servos aufgebohrte Version scheint zu funktionieren,
    // ich habe es allerdings nur mit angeschlossenen Servos 1-4 ausprobiert.
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    // Servoausgänge 1-8
    #define servoinit {DDRB |= (1<<PB7); PORTB &= ~(1<<PB7); DDRC |= 0b01110000; PORTC &= ~0b01110000;}
    #define servo1on  PORTC |=  (1<<PC4)
    #define servo1off PORTC &= ~(1<<PC4)
    #define servo2on  PORTC |=  (1<<PC5)
    #define servo2off PORTC &= ~(1<<PC5)
    #define servo3on  PORTC |=  (1<<PC6)
    #define servo3off PORTC &= ~(1<<PC6)
    #define servo4on  PORTB |=  (1<<PB7)
    #define servo4off PORTB &= ~(1<<PB7)
    
    #define servo5on  PORTB |=  (1<<PB0) // Dummyservos 4-8 an SL6
    #define servo5off PORTB &= ~(1<<PB0)
    #define servo6on  PORTB |=  (1<<PB0)
    #define servo6off PORTB &= ~(1<<PB0)
    #define servo7on  PORTB |=  (1<<PB0)
    #define servo7off PORTB &= ~(1<<PB0)
    #define servo8on  PORTB |=  (1<<PB0)
    #define servo8off PORTB &= ~(1<<PB0)
    
    uint8_t servo1, servo2, servo3, servo4, servo5, servo6, servo7, servo8;
    
    int main(void)
    {
       servoinit; // Datenrichtung der Servopins einstellen
    
       //Timer2 Initialisierung
       // für 8MHz Takt:
       TCCR2 = (0 << WGM21) | (0 << COM20) | (1 << CS22); // Normal Mode, prescaler /64
       // für 16MHz Takt:
       //TCCR2 = (0 << WGM21) | (0 << COM20) | (1 << CS22) | (1 << CS20); // /128
       TIMSK |= (1 << TOIE2); // Timer2 Overflow-Interrupt erlauben -> Servos an
       //TIMSK &= ~(1 << TOIE2); // Timer2 Overflow-Interrupt verbieten -> Servos aus
       sei();
       
       servo1=125; // Mittelposition, Drehbereich ist von 0-255!
       servo2=125;
       servo3=125;
       servo4=125;
       servo5=125;
       servo6=125;
       servo7=125;
       servo8=125;
    
       while(1) // Hauptschleife
       {
       }
       return(0);
    }
    ISR (TIMER2_OVF_vect)
    {
       static uint8_t servo_nr=0, grundimpuls=0; // Gestartet wird am Ende der Pause
       static uint16_t impulspause;
       if(servo_nr)
       {
       // Endweder wird hier der Grundimpuls erzeugt (Länge 56 Einheiten)
          if(grundimpuls++ & 1) { TCNT2=200; impulspause-=256-200; } else
       // Oder der zur Servoposition gehörende Impuls (0-255, 0 ist der längste Impuls!)
          {
             if(servo_nr==1) {TCNT2=servo1; servo1on; impulspause-=servo1;}
             if(servo_nr==2) {TCNT2=servo2; servo1off; servo2on; impulspause-=servo2;}
             if(servo_nr==3) {TCNT2=servo3; servo2off; servo3on; impulspause-=servo3;}
             if(servo_nr==4) {TCNT2=servo4; servo3off; servo4on; impulspause-=servo4;}
    
             if(servo_nr==5) {TCNT2=servo5; servo4off; servo5on; impulspause-=servo5;}
             if(servo_nr==6) {TCNT2=servo6; servo5off; servo6on; impulspause-=servo6;}
             if(servo_nr==7) {TCNT2=servo7; servo6off; servo7on; impulspause-=servo7;}
             if(servo_nr==8) {TCNT2=servo8; servo7off; servo8on; impulspause-=servo8;}
             if(servo_nr==9) {servo8off; servo_nr=0;}
             if(servo_nr) servo_nr++;
          }
       }
       else
    // Anschliessend wird die Impulspuse erzeugt. Sie ergibt sich aus der Startlänge-
    // der Summe der einzelnen Impulslängen. Bei acht Servos errechnet sich der
    // kleinste benötigte Startwert für Impulspause etwa so:
       
    // 8*56 + 8*256 = 2496  (Summe der Grundimpulse + Summe der Positionsimpulse)
       {
          if(impulspause>256) impulspause-=256; // Gesamtpause in 256er-Schritten
             else {TCNT2=-impulspause; servo_nr++; impulspause=3000;} // die Restpause
       }
    }
    Davon habe ich nun noch eine Version mit 16Bit-Timer im CTC-Mode und zwei Kanälen (A/B) für 18 Servos:
    Code:
     // 18 Servos ansteuern mit 8MHz-Mega32 und 16-Bit Timer1          24.3.2009 mic
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    
    #define systemtakt 1 // 1 bei 8MHz, 2 bei 16MHz-Prozessortakt
    #define grundimpuls 47  // grundimpuls + 125 sollte Servomitte sein
    
    // Servoausgänge A 1-9
    #define servoainit {DDRB |= (1<<PB7); PORTB &= ~(1<<PB7);}
    #define servoa1on  PORTB |=  (1<<PB7)
    #define servoa1off PORTB &= ~(1<<PB7)
    #define servoa2on  PORTB |=  (1<<PB0)
    #define servoa2off PORTB &= ~(1<<PB0)
    #define servoa3on  PORTB |=  (1<<PB0)
    #define servoa3off PORTB &= ~(1<<PB0)
    #define servoa4on  PORTB |=  (1<<PB0)
    #define servoa4off PORTB &= ~(1<<PB0)
    
    #define servoa5on  PORTB |=  (1<<PB0) // Dummyservoas 4-9 an SL6
    #define servoa5off PORTB &= ~(1<<PB0)
    #define servoa6on  PORTB |=  (1<<PB0)
    #define servoa6off PORTB &= ~(1<<PB0)
    #define servoa7on  PORTB |=  (1<<PB0)
    #define servoa7off PORTB &= ~(1<<PB0)
    #define servoa8on  PORTB |=  (1<<PB0)
    #define servoa8off PORTB &= ~(1<<PB0)
    #define servoa9on  PORTB |=  (1<<PB0)
    #define servoa9off PORTB &= ~(1<<PB0)
    
    // Servoausgänge B 1-9
    #define servobinit {DDRC |= 0b01110000; PORTC &= ~0b01110000;}
    #define servob1on  PORTC |=  (1<<PC4)
    #define servob1off PORTC &= ~(1<<PC4)
    #define servob2on  PORTC |=  (1<<PC5)
    #define servob2off PORTC &= ~(1<<PC5)
    #define servob3on  PORTC |=  (1<<PC6)
    #define servob3off PORTC &= ~(1<<PC6)
    #define servob4on  PORTB |=  (1<<PB0)
    #define servob4off PORTB &= ~(1<<PB0)
    
    #define servob5on  PORTB |=  (1<<PB0) // Dummyservobs 4-9 an SL6
    #define servob5off PORTB &= ~(1<<PB0)
    #define servob6on  PORTB |=  (1<<PB0)
    #define servob6off PORTB &= ~(1<<PB0)
    #define servob7on  PORTB |=  (1<<PB0)
    #define servob7off PORTB &= ~(1<<PB0)
    #define servob8on  PORTB |=  (1<<PB0)
    #define servob8off PORTB &= ~(1<<PB0)
    #define servob9on  PORTB |=  (1<<PB0)
    #define servob9off PORTB &= ~(1<<PB0)
    
    volatile uint8_t p; // 20ms-Timer
    uint16_t servoa1, servoa2, servoa3, servoa4, servoa5, servoa6, servoa7, servoa8, servoa9;
    uint16_t servob1, servob2, servob3, servob4, servob5, servob6, servob7, servob8, servob9;
    
    /************************* Ausgabe an Terminal ********************************/
    void writeChar(char ch) {while (!(UCSRA & (1<<UDRE))); UDR = (uint8_t)ch;}
    void writeString(char *string) {while(*string) writeChar(*string++);}
    void writeInteger(int16_t number, uint8_t base)
       {char buffer[17]; itoa(number, &buffer[0], base); writeString(&buffer[0]);}
    /******************************************************************************/
    
    int main(void)
    {
       /************************ UART-Setup für RP6 *******************************/
       #define BAUD_LOW      38400  //Low speed - 38.4 kBaud
       #define UBRR_BAUD_LOW   ((F_CPU/(16*BAUD_LOW))-1)
    
       UBRRH = UBRR_BAUD_LOW >> 8;   // Baudrate is Low Speed
       UBRRL = (uint8_t) UBRR_BAUD_LOW;
       UCSRA = 0x00;
       UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
       UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
       /***************************************************************************/
    
       servoa1=125; // Drehbereich ist ca. 10-245!
       servoa2=125;
       servoa3=125;
       servoa4=125;
       servoa5=125;
       servoa6=125;
       servoa7=125;
       servoa8=125;
       servoa9=125;
       servob1=125;
       servob2=125;
       servob3=125;
       servob4=125;
       servob5=125;
       servob6=125;
       servob7=125;
       servob8=125;
       servob9=125;
       //servoa1=servoa2=servoa3=servoa4=servoa5=servoa6=servoa7=servoa8=servoa9=60; // Test
       //servob1=servob2=servob3=servob4=servob5=servob6=servob7=servob8=servob9=60; // Test
    
       servoainit; // Datenrichtung der Servopins A einstellen
       servobinit; // Datenrichtung der Servopins B einstellen
    
       //Timer1 Initialisierung
       TCCR1A = 0;
       TCCR1B = (0<<CS12) | (1<<CS11) | (1<<CS10); // Prescaler /64
       TCCR1B|= (1<<WGM12); // CTC-Mode
       OCR1A=100; // 100*64 Takte bis zum ersten Interrupt
       OCR1B=100;
       TIMSK |= (1 << OCIE1A);
       TIMSK |= (1 << OCIE1B);
    
       sei(); // ... und los!
    
       while(1) // Hauptschleife
       {
          writeChar('*');
          writeChar('\n');
          servoa1=115;
          servob1=115;
          p=50; while(p);    // Das sollte ungefähr 50*20ms=1 Sekunde verzögern
          servoa1=135;
          servob1=135;
          p=50; while(p);
       }
       return(0);
    }
    ISR (TIMER1_COMPA_vect)
    {
       uint16_t temp=grundimpuls;
       static uint8_t servob_nr=1;
       static uint16_t impulspause=3000;
    
         if(servob_nr==1) {temp+=servob1; servob1on;}
         if(servob_nr==2) {temp+=servob2; servob1off; servob2on;}
         if(servob_nr==3) {temp+=servob3; servob2off; servob3on;}
         if(servob_nr==4) {temp+=servob4; servob3off; servob4on;}
         if(servob_nr==5) {temp+=servob5; servob4off; servob5on;}
         if(servob_nr==6) {temp+=servob6; servob5off; servob6on;}
         if(servob_nr==7) {temp+=servob7; servob6off; servob7on;}
         if(servob_nr==8) {temp+=servob8; servob7off; servob8on;}
         if(servob_nr==9) {temp+=servob9; servob8off; servob9on;}
         if(servob_nr >9) {temp =impulspause; servob9off; servob_nr=0;}
    
       OCR1A=temp*systemtakt;
    
         if(servob_nr) impulspause-=temp; else impulspause=3000;
       servob_nr++;
    }
    
    ISR (TIMER1_COMPB_vect)
    {
       uint16_t temp=grundimpuls;
       static uint8_t servoa_nr=1;
       static uint16_t impulspause=3000;
    
       switch(servoa_nr)
       {
          case 1: temp+=servoa1; servoa1on; if(p) p--; break;
            case 2: temp+=servoa2; servoa1off; servoa2on; break;
            case 3: temp+=servoa3; servoa2off; servoa3on; break;
            case 4: temp+=servoa4; servoa3off; servoa4on; break;
          case 5: temp+=servoa5; servoa4off; servoa5on; break;
            case 6: temp+=servoa6; servoa5off; servoa6on; break;
            case 7: temp+=servoa7; servoa6off; servoa7on; break;
            case 8: temp+=servoa8; servoa7off; servoa8on; break;
            case 9: temp+=servoa9; servoa8off; servoa9on; break;
            default:temp =impulspause; servoa9off; servoa_nr=0; break;
       }
       OCR1B=temp*systemtakt;
    
       if(servoa_nr) impulspause-=temp; else impulspause=3000;
       servoa_nr++;
    }
    (Beide Quellcodes aus: http://www.roboternetz.de/phpBB2/zei...=436733#436733)

    Leider funktionieren in der 18er Version immer nur 9 Servos in einer ISR, die andere ISR wird scheinbar ignoriert. Warum das so ist habe ich noch nicht rausgefunden, vielleicht findet ihr den Fehler.

    Gruß

    mic

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  10. #10
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Für mehr als 8 oder 9 Servos gehen die Pulse nicht mehr alle hintereinander. Man könnte dann aber auf 2 Parallele Ketten von Pulsen ausweichen. Die 16 Bit Timer haben ja 2 Compare units. Man programmiert einfach jedesmal die Compare Werte um, auf den nächsten Wert. Da können dan schlimmstenfalls 2 Flanken zusammenfallen. Mit einigem auswand ließe sich das aber auch noch vermeiden indem man vorher gut plant und ggf. extra Pausen einfügt.

    Gerade für Interreupts ist ASM einiges schneller als GCC oder gar BASCOM. Man kommt oft mit weniger Registern aus und braucht entsprechend weniger zu sichern. Auch ist der C compiler nicht immer so gut wenn es um 8 Bit werte geht.

Seite 1 von 4 123 ... LetzteLetzte

Berechtigungen

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