- LiTime Speicher und Akkus         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 11

Thema: Timer0 beim Atmega32 will nicht

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

    Timer0 beim Atmega32 will nicht

    Anzeige

    Praxistest und DIY Projekte
    Hallo zusammen,

    Ich habe ein erstes Testprogramm für meinen Hexapod geschrieben und das funktioniert wunderbar.
    SexCrora

    Code:
    #include <avr/io.h>
    //#include <avr/interrupt.h>
    #include <util/delay.h>
    
    int main (void)
    {
    	DDRA = 0b00000001;		//PA0 	Servo 12
    	DDRB = 0b00011111;		//PB0-4	Servo 11/10/7/8/9
    	DDRC = 0b11111100;		//PC2-7	Servo 4/5/6/3/2/1
    	DDRD = 0b11111100;		//PD2-7	Servo 15/14/13/16/17/18
    	
    	while (1)
    	{
    		PORTA |= (1 << PA0);
    		PORTB |= (1 << PB0);
    		PORTB |= (1 << PB1);
    		PORTB |= (1 << PB2);
    		PORTB |= (1 << PB3);
    		PORTB |= (1 << PB4);
    		PORTC |= (1 << PC2);
    		PORTC |= (1 << PC3);
    		PORTC |= (1 << PC4);
    		PORTC |= (1 << PC5);
    		PORTC |= (1 << PC6);
    		PORTC |= (1 << PC7);
    		PORTD |= (1 << PD2);
    		PORTD |= (1 << PD3);
    		PORTD |= (1 << PD4);
    		PORTD |= (1 << PD5);
    		PORTD |= (1 << PD6);
    		PORTD |= (1 << PD7);
    		_delay_us(1500);		//480=0°/1250=90°/2160=180°
    		PORTA &= ~(1 << PA0);
    		PORTB &= ~(1 << PB0);
    		PORTB &= ~(1 << PB1);
    		PORTB &= ~(1 << PB2);
    		PORTB &= ~(1 << PB3);
    		PORTB &= ~(1 << PB4);
    		PORTC &= ~(1 << PC2);
    		PORTC &= ~(1 << PC3);
    		PORTC &= ~(1 << PC4);
    		PORTC &= ~(1 << PC5);
    		PORTC &= ~(1 << PC6);
    		PORTC &= ~(1 << PC7);
    		PORTD &= ~(1 << PD2);
    		PORTD &= ~(1 << PD3);
    		PORTD &= ~(1 << PD4);
    		PORTD &= ~(1 << PD5);
    		PORTD &= ~(1 << PD6);
    		PORTD &= ~(1 << PD7);
    		_delay_ms(18);
    	}
    	return 1;
    }
    Nun wollte ich das aber nicht unbedingt mit der delay funktion sondern mit einem Timer realisieren.
    Timer0 ist synchron zum 16MHz takt geschaltet. und wird auf 256-160=96 vorgealden. Das ergibt einen Überlauf alle 10µs.
    Bei jedem überlauf soll mein timer1 erhöht werden. wenn dieser 250 erreicht hat wird er zurückgesetzt und timer2 (auf 8 vorgeladen) wird um eins vermindert.
    timer1 ist ein timer der 0-2,5ms läuft und timer2 ist alle 20ms gleich null.

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    //#include <util/delay.h>
    
    unsigned char timer1=0;
    unsigned char timer2=8;
    unsigned char pulse=0;
    
    SIGNAL (SIG_OVERFLOW0)
    {
    	timer1++;
    	if(timer1==250)
    	{
    		timer1=0;
    		timer2--;
    	}
    	TCNT0 = 256 - 160;		//Timer0 neu vorladen
     }
    
    int main (void)
    {
    	DDRA = 0b00000001;		//PA0 	Servo 12
    	DDRB = 0b00011111;		//PB0-4	Servo 11/10/7/8/9
    	DDRC = 0b11111100;		//PC2-7	Servo 4/5/6/3/2/1
    	DDRD = 0b11111100;		//PD2-7	Servo 15/14/13/16/17/18
    	TCNT0 = 256 - 160;		//Timer0 vorladen  (10us)
    	TCCR0 |= (1 << CS00);	//CS02/01/00 mit 001 belegen: Teiler 1
    	TIMSK |= (1 << TOIE0);	//Timer0 Interrupt freigegeben
    	sei();					//Interrupts freigegeben
    	
    	while(1)
    	{
    		if(timer2 == 0)
    		{
    			timer2 = 8;
    			pulse = 1;
    			PORTA |= (1 << PA0);
    			PORTB |= (1 << PB0);
    			PORTB |= (1 << PB1);
    			PORTB |= (1 << PB2);
    			PORTB |= (1 << PB3);
    			PORTB |= (1 << PB4);
    			PORTC |= (1 << PC2);
    			PORTC |= (1 << PC3);
    			PORTC |= (1 << PC4);
    			PORTC |= (1 << PC5);
    			PORTC |= (1 << PC6);
    			PORTC |= (1 << PC7);
    			PORTD |= (1 << PD2);
    			PORTD |= (1 << PD3);
    			PORTD |= (1 << PD4);
    			PORTD |= (1 << PD5);
    			PORTD |= (1 << PD6);
    			PORTD |= (1 << PD7);
    		}
    		if(pulse == 1 && timer1 >= 150)
    		{
    			pulse = 0;
    			PORTA &= ~(1 << PA0);
    			PORTB &= ~(1 << PB0);
    			PORTB &= ~(1 << PB1);
    			PORTB &= ~(1 << PB2);
    			PORTB &= ~(1 << PB3);
    			PORTB &= ~(1 << PB4);
    			PORTC &= ~(1 << PC2);
    			PORTC &= ~(1 << PC3);
    			PORTC &= ~(1 << PC4);
    			PORTC &= ~(1 << PC5);
    			PORTC &= ~(1 << PC6);
    			PORTC &= ~(1 << PC7);
    			PORTD &= ~(1 << PD2);
    			PORTD &= ~(1 << PD3);
    			PORTD &= ~(1 << PD4);
    			PORTD &= ~(1 << PD5);
    			PORTD &= ~(1 << PD6);
    			PORTD &= ~(1 << PD7);
    		}
    	}
    return 1;
    }
    Vielleicht sieht ja jemand einen fehler bei den Steuerbits, eine einfachen Tippfehler oder einen grundsätzlichen Fehler in der logik.
    Vielleicht habe ich mich auch bei der Berechnung der Steuergrößen vertan.
    Es ist mein erster µC den ich komplett selbst programmiere. ( habe nur RP6 Erfahrung)

    vielen Dank für eure Hilfe

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  2. #2
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Es wäre hilfreich wenn du näher beschreiben würdest was nicht richtig funktioniert. Nicht jeder hat gleich einen passenden Testaufbau bereit stehen.

    Auf den ersten Blick:

    volatile unsigned char timer1=0;
    volatile unsigned char timer2=8;

    volatile immer wenn eine Variable in einer ISR geändert wird. Ich glaube, das hat irgendwas mit der Art der Speicherung der Variablen zu tun (Register/Ram).

    Genauer betrachtet könnte die Ausführungszeit der ISR zu lange sein (muss ich erst nachrechen) was zu einem Überlauf mit Abstutz führen würde. Erste Massnahme wäre den 10µs-Interrupt zu verlängern. Dann würde sich zwar die Auflöung deiner Servopositionen verkleinern, aber bei 4% Grundfehler dürfte das auch noch zu verschmerzen sein. Gewinnen würdest du dadurch aber generell mehr Leerlaufzeit weil die Kontroller nicht mehr so häufig mit der ISR beschäftigt wäre.

    Die -160 beim Timersetup bei 16MHz ohne Vorteilung sind richtig weil der Timer ja nach oben zählt bis er wieder 0/256 ist, vorsichthalber würde ich aber die übrigen Bits im TCCR0-Register nicht einfach so übernehmen. Da du den normalen Mode verwendest kannst du die restlichen Bits mit TCCR0 = (1 << CS00); einfach mitlöschen.

    btw: Ein nettes Krabbeltierchen hast du dir da zusammengezaubert. Gefällt mir gut :)

    Gruß

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

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    36
    Beiträge
    150
    nun ja keiner der Servos reagiert

    das is meine einzige Kontrolle des timers, ob an den ausgängen ein PWM signal entsteht

    danke für das Lob und den ersten Tipp!

    Ich bin am überlegen das grundprinzip zu verändern.
    wie du schon sagtest, frisst der ISR grob geschätzt 8% meiner Rechenleistung (alle 100 Takte ein interrupt mit ca 8 Assembler befehlen) uns zusätzlich die permanente Überprüfung der Timer mit den Vergleichswerten.
    Daher wäre eine andere Lösung um 18 PWMs zu erzeugen ratsam.
    Ich überlege meinen 16MHz quartz durch ein 6,4MHz Quartz zu tauschen.
    Dadurch bin ich in der Lage die Timer 0 und 2 bei einem Prescaler von 64 zu 10µs timern zu nutzen (alternativ ginge auch 25,6MHz bei einem Prescaler von 256, aber das unterstützt der µC nicht ). Ein Pin wird auf High gesetzt, die Pulsdauer wird einfach vorgeladen und wenn der Überlauf erreicht wird, wird der entsprechende Pin zurück gesetzt. dann folgt der nächste kanal. da es 18 Servos sind und maximal 18*2,5ms=45ms vestreichen können müssen zwei Timer gleichzeitig impulse erzeugen, dann kann es höchstens 22,5ms dauern alle Signale zu erzeugen und dann können sie auch gleich schon wieder mit den nächsten Signalen loslegen. Im Falle, dass die Impulssumme kleiner als 20ms war muss entsprechend gewartet werden. Hier besteht die auslastung des µC nur darin in alle 20ms 18mal in den ISR zu springen, die Ports zu schalten und die timer neu vorzuladen. Also kaum arbeit.
    Das einzige was mich an dieser Idee stört ist, die Tatsache dass ich 60% meiner Geschwindigkeit verliere, weil ich nurnoch mit 6,4MHz arbeite. Aber ansonsten bekommt man mit den prescalern und den 8 Bit-Timern nicht auf einen Timer der 0-2,55ms abdeckt.
    Diese Signale hätten jedoch gegenüber der ersten Lösung den vorteil, dass sie aufgrund der tastsache, dass jedes signal durch einen ISR direkt ausgelöst wird sehr präzise ist.

    Was haltet ihr von der alternativen Idee?

    mfg Sirvivor
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  4. #4
    Erfahrener Benutzer Roboter Genie Avatar von Willa
    Registriert seit
    26.10.2006
    Ort
    Bremen
    Alter
    43
    Beiträge
    1.273
    Ich verstehe leider kein C, vielleicht ist aber der Beitrag im Wiki zur Servoansteuerung hilfreich für dich? Das entspricht der von dir beschriebenen Idee. Damit gehen bestimmt auch noch 18 Servos. Ist halt in Bascom beschrieben, aber das ist ja ziemlich leicht verständlich:
    https://www.roboternetz.de/wissen/in...rvoansteuerung

    Du musst unbedingt bis 2.55ms gehen? bei 1-2ms Pulslänge komme ich auf max 36ms, im Mittel jedoch auf 27 ms (oder sind deine Servos alle gleichzeitig am oberen Anschlag?) 36-27ms sollte eigentlich noch gehen als frametime.
    Viele Grüße, William
    -> http://william.thielicke.org/

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    36
    Beiträge
    150
    @ Radbruch
    Du hattest recht: es ware der falsche datentyp für meine Zähler

    VIELEN DANK!!!

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  6. #6
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Obwohl hier im RN-Forum schon einige Möglichkeiten gezeigt werden wie man viele Servos mit wenig Microkontroller ansteuert möchte ich hier noch meinen Weg vorstellen und testen lassen. Ich verwende das aber erst seit ein paar Tagen mit nur 4 Servos und kann deshalb nicht sagen ob es mit 8 (oder mehr) Servos auch so gut funktioniert.

    Ohne viele Worte hier der Code:
    Code:
    // Servos ansteuern mit 8MHz Mega32 und 8-Bit Timer2 Overflow-ISR  22.3.2008 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 Impulspause 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
    	}
    }
    (Das wird bei mir mit genau 500 Bytes übersetzt, ist das ein Ohmen?)

    Es wäre nett wenn das mal jemand testen würde, bei Interesse kann ich auch noch ein bisschen mehr über die Funktion plaudern.

    Gruß

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

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    36
    Beiträge
    150
    Ich hatte mir das ja auch schon überlegt, die impulse seriell zu produzieren, aber dafür wären mindestens zwei timer nötig um widerum immer zwei signale gleichzeitg zu erzeugen, da 18*2,5ms=54ms zu lange für eine serielle ausführung ist.
    Jetzt läuft aber auch die parallele Erzeugung von 18 Servoimpulsen.
    Das einzige kleine problem ist:
    den Stellbereich kann man ja als lineare funktion interpretieren:
    0°=tmin //minimale Impulsdauer
    180°=tmax //maximale Impulsdauer
    wenn man nun den stellwinkel in grad vorgibt berechnet sich die Impulsdauer wie folgt:
    tmin+(tmax-tmin)/180*x //standard Geradengleichung, zwei Punkte Form.
    der konstante kalirierungsfaktor vor dem x um die umrechnug von ° in 10µsekunden der Impulsdauer ist ein wert, der bei meinen Servos besipielweise (220-58 )/180=0.9 beträgt.

    wenn ich diese rechnung mit 0.9 ausführen lasse, dann stimmen die stellwinkel absolut nicht mehr.
    selbst wenn ich nur bei einem winkel diesen faktor zu korrektur eingebe, verändern sich alle anderen winkel auch. Je mehr Faktoren ich hinzufüge, desto schlimmer wird es.

    Ist die multiplikation mit feskommazahlen so kompliziert für den prozessor,dass dadurch mein gesammtes Timing durcheinander gerät?

    Aber abgesehen von dieser Problematik, kann ich jetzt hervorragend 18 verschiedene Impulse simultan erzeugen, und dass mit nur einem Timer.
    Der Code ist noch stark optimierungsbedürftig, er ist so im Verlauf des Experimentierens entstanden, was schonmal sehr schlecht ist.

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    	//minimale Impulsdauer
    #define	tmin1			50
    #define	tmin2			50
    #define	tmin3			50
    #define	tmin4			50
    #define	tmin5			50
    #define	tmin6			50
    #define	tmin7			50
    #define	tmin8			50
    #define	tmin9			50
    #define	tmin10			50
    #define	tmin11			50
    #define	tmin12			50
    #define	tmin13			50
    #define	tmin14			50
    #define	tmin15			50
    #define	tmin16			50
    #define	tmin17			50
    #define	tmin18			50
    	//maximale Impulsdauer
    #define tmax1			220
    #define tmax2			220
    #define tmax3			220
    #define tmax4			220
    #define tmax5			220
    #define tmax6			220
    #define tmax7			220
    #define tmax8			220
    #define tmax9			220
    #define tmax10			220
    #define tmax11			220
    #define tmax12			220
    #define tmax13			220
    #define tmax14			220
    #define tmax15			220
    #define tmax16			220
    #define tmax17			220
    #define tmax18			220
    	//Skalierungsfaktor von Grad auf Impulssekunden (tmax_i-tmin_i)/180	funktionier nicht, daher zunächst korrektur durch addition von impulsdauer
    #define pulsfaktor1	0.9	//... läuft nicht
    
    
    
    //Wert zur korrektur der schief sitzenden Servohörner --> Überflüssig, wenn die skalierung läuft
    signed int 	calibrate[19] = {0,1,1,0,8,-8,-4,-6,2,-8,1,0,-6,-6,6,4,-1,-4,-7};
    
    
    
    volatile unsigned char	timer1 = 0;
    volatile unsigned char 	timer2 = 8;
    
    #define		ready		0
    #define		nextpulse 		1
    #define		pulsestarted	2
    #define		pulseready		3
    volatile unsigned char	state = ready;
    
    	//Das Element [0] ist leer, damit die Indizes zu den servobezeichnern passen
    // später sind die arrays mit richtigen winkeln gefüllt, jetzt habe dich die winkel vorab mit meinem skalierungsfaktor multipliziert.
    //unsigned char			angle[19] = {0,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60};
    unsigned char			angle[19] = {0,45,140,95,32,135,85,45,140,95,32,135,85,45,140,95,36,135,85};//stehen tief
    //unsigned char			angle[19] = {0,95,80,95,85,70,85,95,80,95,85,70,85,95,80,95,85,70,85};//stehen hoch
    
    //eigentlich waren die pulse auch ein Array, aber der compiler hat gemeckert, weil ich die Einträge als Vergleichswert in einer if Bedingung benutzen wollte.
    unsigned char			pulse1 = 135; //Mittelstellung
    unsigned char			pulse2 = 135;
    unsigned char			pulse3 = 135;
    unsigned char			pulse4 = 135;
    unsigned char			pulse5 = 135;
    unsigned char			pulse6 = 135;
    unsigned char			pulse7 = 135;
    unsigned char			pulse8 = 135;
    unsigned char			pulse9 = 135;
    unsigned char			pulse10= 135;
    unsigned char			pulse11= 135;
    unsigned char			pulse12= 135;
    unsigned char			pulse13= 135;
    unsigned char			pulse14= 135;
    unsigned char			pulse15= 135;
    unsigned char			pulse16= 135;
    unsigned char			pulse17= 135;
    unsigned char			pulse18= 135;
    
    
    SIGNAL (SIG_OVERFLOW0)		//frisst ~7% der ProzessorLeistung
    {
    	TCNT0 = 256 - 160;		//Timer0 mit 96 neu vorladen
    	timer1++;
    	if(timer1 == 250)
    	{
    		timer1=0;			//timer1 endet bei 2,5ms
    		timer2--;			//timer2 wird im 2,5ms Intervall herabgezählt
    	}
    	if(timer2 == 0){
    		timer2 = 8;
    		state = nextpulse;}			// 
     }
    
    void pulsegenerator(void)
    {
    	if(state == nextpulse)			//alle 20ms alle Signalleitungen auf 1 setzen
    	{
    		PORTA |= (1 << PA0);
    		PORTB |= (1 << PB0);PORTB |= (1 << PB1);PORTB |= (1 << PB2);PORTB |= (1 << PB3);PORTB |= (1 << PB4);
    		PORTC |= (1 << PC2);PORTC |= (1 << PC3);PORTC |= (1 << PC4);PORTC |= (1 << PC5);PORTC |= (1 << PC6);PORTC |= (1 << PC7);
    		PORTD |= (1 << PD2);PORTD |= (1 << PD3);PORTD |= (1 << PD4);PORTD |= (1 << PD5);PORTD |= (1 << PD6);PORTD |= (1 << PD7);
    		state = pulsestarted;
    	}
    	if(state == pulsestarted)
    	{								//Signal des jeweiligen Servos beenden
    		if(timer1 >= pulse1){
    			PORTC &= ~(1 << PC7);}
    		if(timer1 >= pulse2){
    			PORTC &= ~(1 << PC6);}
    		if(timer1 >= pulse3){
    			PORTC &= ~(1 << PC5);}
    		if(timer1 >= pulse4){
    			PORTC &= ~(1 << PC2);}
    		if(timer1 >= pulse5){
    			PORTC &= ~(1 << PC3);}
    		if(timer1 >= pulse6){
    			PORTC &= ~(1 << PC4);}
    		if(timer1 >= pulse7){
    			PORTB &= ~(1 << PB2);}
    		if(timer1 >= pulse8){
    			PORTB &= ~(1 << PB3);}
    		if(timer1 >= pulse9){
    			PORTB &= ~(1 << PB4);}
    		if(timer1 >= pulse10){
    			PORTB &= ~(1 << PB1);}
    		if(timer1 >= pulse11){
    			PORTB &= ~(1 << PB0);}
    		if(timer1 >= pulse12){
    			PORTA &= ~(1 << PA0);}
    		if(timer1 >= pulse13){
    			PORTD &= ~(1 << PD4);}
    		if(timer1 >= pulse14){
    			PORTD &= ~(1 << PD3);}
    		if(timer1 >= pulse15){
    			PORTD &= ~(1 << PD2);}
    		if(timer1 >= pulse16){
    			PORTD &= ~(1 << PD5);}
    		if(timer1 >= pulse17){
    			PORTD &= ~(1 << PD6);}
    		if(timer1 >= pulse18){
    			PORTD &= ~(1 << PD7);}
    	}
    	if (timer2 <= 7){			// nach 2,5ms ist die pulsgenerierung beendet
    		state = pulseready;}	
    }
    
    
    void pulsecalculator(void)    //in dieser funktion bestehen die probleme mit dem skalierungsfaktor, daher zunächst die ungenaue berechnung mit konstanter anpassung angle ist jetzt kein winkel sondern eine impulsdauer, bei der 0-190 = 0-1,9ms = 0°-180° gilt. (unpraktisch)
    {
    	pulse1 = (tmin1  + calibrate[1]  + (180-angle[1]));			//bei andersherum montierten servos: (180-angle)
    	pulse2 = (tmin2  + calibrate[2]  + (180-angle[2]));			//*
    	pulse3 = (tmin3  + calibrate[3]  + (180-angle[3]));			//*
    	pulse4 = (tmin4  + calibrate[4]  + angle[4]);
    	pulse5 = (tmin5  + calibrate[5]  + angle[5]);
    	pulse6 = (tmin6  + calibrate[6]  + angle[6]);
    	pulse7 = (tmin7  + calibrate[7]  + (180-angle[7]));
    	pulse8 = (tmin8  + calibrate[8]  + (180-angle[8]));
    	pulse9 = (tmin9  + calibrate[9]  + (180-angle[9]));
    	pulse10= (tmin10 + calibrate[10] + angle[10]);
    	pulse11= (tmin11 + calibrate[11] + angle[11]);
    	pulse12= (tmin12 + calibrate[12] + angle[12]);
    	pulse13= (tmin13 + calibrate[13] + (180-angle[13]));
    	pulse14= (tmin14 + calibrate[14] + (180-angle[14]));
    	pulse15= (tmin15 + calibrate[15] + (180-angle[15]));
    	pulse16= (tmin16 + calibrate[16] + angle[16]);
    	pulse17= (tmin17 + calibrate[17] + angle[17]);
    	pulse18= (tmin18 + calibrate[18] + angle[18]);
    }
    int main (void)
    {
    	//Ausgänge definieren
    	DDRA = 0b00000001;		//PA0 	Servo 12
    	DDRB = 0b00011111;		//PB0-4	Servo 11/10/7/8/9
    	DDRC = 0b11111100;		//PC2-7	Servo 4/5/6/3/2/1
    	DDRD = 0b11111100;		//PD2-7	Servo 15/14/13/16/17/18
    	
    	//Timer0 Konfigurieren
    	TCNT0 = 256 - 160;		//Timer0 mit 96 vorladen  (10µs Timer)
    	TCCR0 |= (1 << CS00);	//CS02/01/00 mit 001 belegen: Teiler 1
    	TIMSK |= (1 << TOIE0);	//Timer0 Interrupt freigegeben
    	sei();					//Interrupts freigegeben
    	
    	
    	while(1)				//Arbeitsschleife
    	{
    		pulsegenerator();			// Funktion, die alle 20ms die Servo PWMs erzeugt
    		if (state == pulseready)     //hier können unterprogramme in der freizeit ausgeführt werden, aber nichts blockendes oder zu Zeitaufwendiges.
    		{
    			pulsecalculator();		// Wandelt Werte von Angle in Pulsweiten um.
    		}
    	}
    return 1;
    }
    Der code ist ein horror, aber vielleicht weiß ja jemand, weshalb die multiplikation mit gebrochenrationalen zahlen so ein problem ist.

    mfg sirvivor
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    36
    Beiträge
    150
    @radbruch
    ich habe dein Programm mal auf den Ports B0-B4 und C4-6 ausgeführt und hat einwandfrei funktioniert.

    glückwunsch!

    sehr schön überischtlicher code

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    36
    Beiträge
    150
    ich hatte vor dein programm mal testweise auf 18 Servos zu erweitern,
    allerdings brauche ich dafür timer0 oder timer1 und die kann ich nicht auf /128 einstellen.
    Du als Entwickler des programms: denkst du es ist möglich, dass ich durch Veränderung der Variablen (alles verdoppeln) mit timer1 prescaler /64 das gleiche wie mit timer2 erzeugen kann?

    Ich habe es soweit auf 9 Servos pro timer erweitert.
    wenn ich den timer0 (timer1 kann ich nicht) laufen lasse, dann funktionieren die servos, allerdings ist das Signal logischerweise wegen des falschen taktes verfälscht. (pause verdoppeln war kein problem, also stimmt zumindst die frequenz)
    Wenn nur ein timer läuft geht alles, wenn beide laufen, dann zuckt jeweils der servo, der das erste signal bekommt. (also 1 und 10)
    Da die zahlen wegen der verdopplung zu groß für den timer0 werden muss ich das noch auf time 1 modifizieren.

    Code:
    // Servos ansteuern mit 16MHz Mega32 und 8-Bit Timer2 Overflow-ISR  22.3.2008 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. 
    
    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    
    // Servoausgänge 1-18 
    						//PA0 Servo 12, PB0-4 Servo 11/10/7/8/9, PC2-7 Servo 4/5/6/3/2/1, PD2-7 Servo 15/14/13/16/17/18
    #define DDRAinit {	DDRA = 0b00000001;DDRB = 0b00011111;DDRC = 0b11111100;DDRD = 0b11111100;} 
    #define servo1on  PORTC |=  (1<<PC2) 
    #define servo1off PORTC &= ~(1<<PC2) 
    #define servo2on  PORTC |=  (1<<PC3) 
    #define servo2off PORTC &= ~(1<<PC3) 
    #define servo3on  PORTC |=  (1<<PC4) 
    #define servo3off PORTC &= ~(1<<PC4) 
    #define servo4on  PORTC |=  (1<<PC7) 
    #define servo4off PORTC &= ~(1<<PC7) 
    #define servo5on  PORTC |=  (1<<PC6)
    #define servo5off PORTC &= ~(1<<PC6) 
    #define servo6on  PORTC |=  (1<<PC5) 
    #define servo6off PORTC &= ~(1<<PC5) 
    #define servo7on  PORTB |=  (1<<PB2) 
    #define servo7off PORTB &= ~(1<<PB2) 
    #define servo8on  PORTB |=  (1<<PB1) 
    #define servo8off PORTB &= ~(1<<PB1) 
    #define servo9on  PORTB |=  (1<<PB0) 
    #define servo9off PORTB &= ~(1<<PB0) 
    #define servo10on  PORTB |=  (1<<PB3) 
    #define servo10off PORTB &= ~(1<<PB3) 
    #define servo11on  PORTB |=  (1<<PB4) 
    #define servo11off PORTB &= ~(1<<PB4) 
    #define servo12on  PORTA |=  (1<<PA0) 
    #define servo12off PORTA &= ~(1<<PA0) 
    #define servo13on  PORTD |=  (1<<PD5) 
    #define servo13off PORTD &= ~(1<<PD5) 
    #define servo14on  PORTD |=  (1<<PD6) 
    #define servo14off PORTD &= ~(1<<PD6) 
    #define servo15on  PORTD |=  (1<<PD7) 
    #define servo15off PORTD &= ~(1<<PD7) 
    #define servo16on  PORTD |=  (1<<PD4) 
    #define servo16off PORTD &= ~(1<<PD4) 
    #define servo17on  PORTD |=  (1<<PD3) 
    #define servo17off PORTD &= ~(1<<PD3) 
    #define servo18on  PORTD |=  (1<<PD2) 
    #define servo18off PORTD &= ~(1<<PD2) 
    
    
    uint8_t servo1, servo2, servo3, servo4, servo5, servo6, servo7, servo8, servo9, servo10, servo11, servo12, servo13, servo14, servo15, servo16, servo17, servo18; 
    // hilfswerte zur Anpassung an die geänderte timer frequenz 
    uint16_t servo10a, servo11a, servo12a, servo13a, servo14a, servo15a, servo16a, servo17a, servo18a; 
    
    int main(void) 
    { 
       DDRAinit; // Datenrichtung der Servopins einstellen 
       //Timer0 Initialisierung 
       TCCR0 = (0 << WGM01) | (0 << COM00) | (1 << CS01) | (1 << CS00); // /64 
       TIMSK |= (1 << TOIE0); // Timer0 Overflow-Interrupt erlauben -> Servos an 
       //TIMSK &= ~(1 << TOIE0); // Timer0 Overflow-Interrupt verbieten -> Servos aus
    
       //Timer2 Initialisierung 
       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; 
       servo9=125;
       servo10=125; 
       servo11=125; 
       servo12=125; 
       servo13=125; 
       servo14=125; 
       servo15=125; 
       servo16=125; 
       servo17=125;
       servo18=125;
       // hier wird der stellwert an die geänderte timer frequenz angepasst (zum schutz vor einem überlauf des timer0 zunächst durch 8 geteilt, später für timer 1 mit 2 multipliziert
       servo10a = servo10/8; 
       servo11a = servo11/8;
       servo12a = servo12/8;
       servo13a = servo13/8;
       servo14a = servo14/8;
       servo15a = servo15/8;
       servo16a = servo16/8;
       servo17a = servo17/8;
       servo18a = servo18/8;
    
       while(1) // Hauptschleife 
       { 
       } 
       return(0); 
    }
    
    ISR (TIMER0_OVF_vect) //variablen mit index a bzw. 1 versehen
    { 
       static uint8_t servo_nra=0, grundimpuls1=0; // Gestartet wird am Ende der Pause 
       static uint16_t impulspause1; 
       if(servo_nra) 
       { 
       // Entweder wird hier der Grundimpuls erzeugt (Länge 56 Einheiten) 
          if(grundimpuls1++ & 1) { TCNT0=200; impulspause1-=256-144; } else //2*pause
       // Oder der zur Servoposition gehörende Impuls (0-255, 0 ist der längste Impuls!) 
          { 
             if(servo_nra==1) {TCNT0=servo10a; servo10on; impulspause1-=servo10a; impulspause1-=servo10a}
             if(servo_nra==2) {TCNT0=servo11a; servo10off; servo11on; impulspause1-=servo11a;impulspause1-=servo11a;} 
             if(servo_nra==3) {TCNT0=servo12a; servo11off; servo12on; impulspause1-=servo12a;impulspause1-=servo12a;} 
             if(servo_nra==4) {TCNT0=servo13a; servo12off; servo13on; impulspause1-=servo13a;impulspause1-=servo13a;} 
    
             if(servo_nra==5) {TCNT0=servo14a; servo13off; servo14on; impulspause1-=servo14a;impulspause1-=servo14a;} 
             if(servo_nra==6) {TCNT0=servo15a; servo14off; servo15on; impulspause1-=servo15a;impulspause1-=servo15a;} 
             if(servo_nra==7) {TCNT0=servo16a; servo15off; servo16on; impulspause1-=servo16a;impulspause1-=servo16a;} 
             if(servo_nra==8) {TCNT0=servo17a; servo16off; servo17on; impulspause1-=servo17a;impulspause1-=servo17a;}
             if(servo_nra==9) {TCNT0=servo18a; servo17off; servo18on; impulspause1-=servo18a;impulspause1-=servo18a;}  
             if(servo_nra==10) {servo18off; servo_nra=0;} 
             if(servo_nra) servo_nra++; 
          } 
       } 
       else 
    // Anschliessend wird die Impulspause 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(impulspause1>256) impulspause1-=256; // Gesamtpause in 256er-Schritten 
             else {TCNT2=-impulspause1; servo_nra++; impulspause1=6000;} // die Restpause 
       } 
    }
    
    ISR (TIMER2_OVF_vect) //variablen mit index b bzw. 2 versehen
    { 
       static uint8_t servo_nrb=0, grundimpuls2=0; // Gestartet wird am Ende der Pause 
       static uint16_t impulspause2; 
       if(servo_nrb) 
       {
       // Endweder wird hier der Grundimpuls erzeugt (Länge 56 Einheiten) 
          if(grundimpuls2++ & 1) { TCNT2=200; impulspause2-=256-200; } else 
       // Oder der zur Servoposition gehörende Impuls (0-255, 0 ist der längste Impuls!) 
          { 
             if(servo_nrb==1) {TCNT2=servo1; servo1on; impulspause2-=servo1;} 
             if(servo_nrb==2) {TCNT2=servo2; servo1off; servo2on; impulspause2-=servo2;} 
             if(servo_nrb==3) {TCNT2=servo3; servo2off; servo3on; impulspause2-=servo3;} 
             if(servo_nrb==4) {TCNT2=servo4; servo3off; servo4on; impulspause2-=servo4;} 
    
             if(servo_nrb==5) {TCNT2=servo5; servo4off; servo5on; impulspause2-=servo5;} 
             if(servo_nrb==6) {TCNT2=servo6; servo5off; servo6on; impulspause2-=servo6;} 
             if(servo_nrb==7) {TCNT2=servo7; servo6off; servo7on; impulspause2-=servo7;} 
             if(servo_nrb==8) {TCNT2=servo8; servo7off; servo8on; impulspause2-=servo8;} 
             if(servo_nrb==9) {TCNT2=servo9; servo8off; servo9on; impulspause2-=servo9;} 
    		 if(servo_nrb==10) {servo9off; servo_nrb=0;} 
             if(servo_nrb) servo_nrb++; 
          } 
       } 
       else 
    // Anschliessend wird die Impulspause 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(impulspause2>256) impulspause2-=256; // Gesamtpause in 256er-Schritten 
             else {TCNT2=-impulspause2; servo_nrb++; impulspause2=2900;} // die Restpause 
       } 
    }
    Ich konnte schon herausfinden, dass das Zucken abhängig vom Verhältnis der Restpausen ist.
    Wahrscheinlich liegen die pararallel laufenden timer nicht ganz synchron und daher haken sie gelegentlich.
    Aber ich hoffe, dass das verschwindet, sobalt der timer 1 exakt läuft. (also beide timerdurchläufe gleich lange benötigen)

    kann mir jemand nen rat geben, wie ich:

    if(servo_nra==2) {TCNT0=servo11a; servo10off; servo11on; impulspause1-=servo11a}
    also speziell TCNT1A,B vorladen muss? mit 65536- das doppelte meiner eigentlichen impulsdauer oder einfach nur mit der doppelten impulsdauer.
    Oder mit (65536-512)+2*stellwert, also timermax-pulsmax+sollwert
    bei timer 0 funktioniert die formel 255-255+sollwert=sollwert
    das ist wegen der umgekehrten logik etwas verwirrend...

    Wie kann man das am schnellsten schreiben? man kann bestimmt kein 16bit int in TCNT1A schreiben und beschreibt B gleich mit oder?
    oder so: 16bitint/256->A 16bitint%256-->B?

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  10. #10
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Hier ein Versuch mit Timer1 und 18 Servos. Da steigt dann mein RP6 aus, vermutlich ein Zeitüberlauf in der ISR:
    Code:
    // 18 Servos ansteuern mit Mega32 und 16-Bit Timer1                24.3.2008 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 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-9 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)
    #define servo9on  PORTB |=  (1<<PB0)
    #define servo9off PORTB &= ~(1<<PB0)
    
    volatile uint8_t p; // 20ms-Timer
    uint16_t servo1, servo2, servo3, servo4, servo5, servo6, servo7, servo8, servo9;
    
    /************************* 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);
    	/***************************************************************************/
    
    	//Timer1 Initialisierung
    	TCCR1A = 0;
    	TCCR1B = (0<<CS12) | (1<<CS11) | (1<<CS10); // Prescaler /64
    	TCCR1B|= (1<<WGM12); // CTC-Mode
    	OCR1A=100; // 100 Takte bis zum ersten Interrupt
    	OCR1B=100;
    	TIMSK |= (1 << OCIE1A); // Das klappt so leider nur mit Timer1A?
    	//TIMSK |= (1 << OCIE1B);
    
    	servo1=60; // Drehbereich ist ca. 10-245!
    	servo2=125;
    	servo3=190;
    	servo4=245;
    	servo5=125;
    	servo6=125;
    	servo7=125;
    	servo8=125;
    	servo9=125;
    	//servo1=servo2=servo3=servo4=servo5=servo6=servo7=servo8=servo9=60; // Test
    
    	servoinit; // Datenrichtung der Servopins einstellen
    	sei(); // ... und los!
    
    	while(1) // Hauptschleife
    	{
    	   servo4=125; 		// ab hier funktioniert es mit meinen RP6 nicht mehr!
    	   p=50; while(p); 	// Das sollte ungefähr 50*20ms=1 Sekunde verzögern
    	   servo4=125;
    	   p=50; while(p);
    	}
    	return(0);
    }
    ISR (TIMER1_COMPB_vect)
    {
    	uint16_t temp=grundimpuls;
    	static uint8_t servo_nr=1;
    	static uint16_t impulspause=3000;
    
      	if(servo_nr==1) {temp+=servo1; servo1on; if(p) p--;}
      	if(servo_nr==2) {temp+=servo2; servo1off; servo2on;}
      	if(servo_nr==3) {temp+=servo3; servo2off; servo3on;}
      	if(servo_nr==4) {temp+=servo4; servo3off; servo4on;}
      	if(servo_nr==5) {temp+=servo5; servo4off; servo5on;}
      	if(servo_nr==6) {temp+=servo6; servo5off; servo6on;}
      	if(servo_nr==7) {temp+=servo7; servo6off; servo7on;}
      	if(servo_nr==8) {temp+=servo8; servo7off; servo8on;}
      	if(servo_nr==9) {temp+=servo9; servo8off; servo9on;}
      	if(servo_nr >9) {temp =impulspause; servo9off; servo_nr=0;}
    
    	OCR1B=temp*systemtakt;
    
      	if(servo_nr) impulspause-=temp; else impulspause=3000;
    	servo_nr++;
    }
    
    ISR (TIMER1_COMPA_vect)
    {
    	uint16_t temp=grundimpuls;
    	static uint8_t servo_nr=1;
    	static uint16_t impulspause=3000;
    
    	switch(servo_nr)
    	{
    		case 1: temp+=servo1; servo1on; if(p) p--; break;
      		case 2: temp+=servo2; servo1off; servo2on; break;
      		case 3: temp+=servo3; servo2off; servo3on; break;
      		case 4: temp+=servo4; servo3off; servo4on; break;
    
      		case 5: temp+=servo5; servo4off; servo5on; break;
      		case 6: temp+=servo6; servo5off; servo6on; break;
      		case 7: temp+=servo7; servo6off; servo7on; break;
      		case 8: temp+=servo8; servo7off; servo8on; break;
      		case 9: temp+=servo9; servo8off; servo9on; break;
      		default:temp =impulspause; servo9off; servo_nr=0; break;
    	}
    	OCR1A=temp*systemtakt;
    
    	if(servo_nr) impulspause-=temp; else impulspause=3000;
    	servo_nr++;
    }
    Mit systemtakt kann man zwischen 8 oder 16MHz wählen. Das ist einfach nur ein Multiplikator der im 16MHz-Modus alle Timerwerte mit 2 multipliziert. Ob das wie gedacht funktioniert kann ich nicht testen weil ich keinen 16MHz-Mega32 habe.

    Grundsätzlich funktionieren so immerhin 9 Servos an Timer1A. Allerdings wird bei mir dann die Hauptschleife nicht mehr ausgeführt. Eigentlich sollten die minimalen (64*grundimpuls)-Takte zur Ausführung der ISR ausreichen, ich weiß noch nicht, warum mein RP6 bockt.

    Wenn ich (nur) die ISR für COMPB aktiviere funktioniert nichts (nur der Impuls für das erste Servo wird gestartet aber nie beendet) An den unterschiedlichen Varianten der ISRs liegts anscheinend nicht denn wenn man die über kreuz umbenennt bleibt das Verhalten gleich. Scheinbar ist da ein Unterschied zwischen TIMER1A und TIMER1B dessen Beschreibung ich im Datenblatt noch nicht gefunden habe. Oder ich mache einen blöden Denk- oder Anfängerfehler den ich nicht erkenne :(

    Gruß

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

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

LiFePO4 Speicher Test