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
Lesezeichen