Hi,
Ich habe mich nochmal daran gemacht mein Programm von Grundauf neu zu überdenken. Es ist sch**ße, wenn die Impulse von einer funktion erzeugt werden, die von der main Funktion aus aufgerufen wird. Die Gefahr, dass irgendeine andere funktion einmal zu lange braucht, ist zu groß.
Daher habe ich die impulserzeugung jetzt in den ISR verlegt.
Eine kleine Erläuterung steht im Header. Ein standardmäßiger Grundimpuls zur erhöhung der Auflösung, sowie weitere Calibrierungsfunktionen folgen.
Allerdings muss da noch irgendwo ein minimaler zufallskinken drin sein. gelegentlich muss ch mehrmals den Reset button drücken, bis das Programm Ordnungsgemäß läuft. Wenn ich den ISP entferne ist der Fehler weg.
Code:
// Servos ansteuern mit 16MHz Mega32 und 8-Bit Timer0 und Timer2 (als ms stopwatch verwendbar)
// Die Servosimpulse werden simultan erzeugt. Die Impulsdauer jedes Servos
// besteht nur aus einem Wert, der zwischen 0 und 255 liegen muss. Der Stellbereich liegt dann bei
// ungefähr zwischen 50 und 230. --> ~180 werte für 180 grad, also eine auflösung bis auf ein Grad.
// In der ISR wird ein 1 ms Timer2 verwendet, um einen Zähler alle 20ms zurückzusetzen und den impulsmessenden Timer0 zu starten.
// Während Timer0 läuft ist die maximale Auslastung: alle 160 Takte ein interupt, mit maximal 100 Befehlen 63% im Durchschnitt 30% nur für den ISR
// Daher wird der Timer0 auch diret nach der Pulserzeugung gestoppt und erst ~18ms später von Timer2 aufgerufen.
// Während der Pause läuft also nichts außer einem 1ms Timer. Viel Zeit um andere Dinge zu erldigen.
// 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
//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<<PC7)
#define servo1off PORTC &= ~(1<<PC7)
#define servo2on PORTC |= (1<<PC6)
#define servo2off PORTC &= ~(1<<PC6)
#define servo3on PORTC |= (1<<PC5)
#define servo3off PORTC &= ~(1<<PC5)
#define servo4on PORTC |= (1<<PC2)
#define servo4off PORTC &= ~(1<<PC2)
#define servo5on PORTC |= (1<<PC3)
#define servo5off PORTC &= ~(1<<PC3)
#define servo6on PORTC |= (1<<PC4)
#define servo6off PORTC &= ~(1<<PC4)
#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;
volatile unsigned char timer1 = 0;
volatile unsigned char timer2 = 0;
volatile unsigned char signals = 0;
int main(void)
{
DDRAinit; // Datenrichtung der Servopins einstellen
//Timer 0
TCCR0 |= (1 << CS00); //normal mode, prescaler 1
//TIMSK |= (1 << TOIE0); //Timer0 Interrupt freigegeben (wird von timer 1 freigegeben und vorgeladen)
//TCNT0 = 256 - 160; //Timer0 mit 96 vorladen, 1/16MHz*160 = 10µs
//Timer 2
TCCR2 |= (1 << CS22); //normal mode, prescaler 64
TCNT2 = 256-250; //Timer2 mit 6 vorladen, 64/16MHz*250=1ms
TIMSK |= (1 << TOIE2); //Timer2 Interrupt freigeben
sei(); //Interrupts freigegeben
servo1=210; // Mittelposition
servo2=210;
servo3=210;
servo4=210;
servo5=210;
servo6=210;
servo7=210;
servo8=210;
servo9=210;
servo10=210;
servo11=210;
servo12=210;
servo13=210;
servo14=210;
servo15=210;
servo16=210;
servo17=210;
servo18=210;
while(1) // Hauptschleife
{
}
return(0);
}
SIGNAL (SIG_OVERFLOW2) //frisst ~7% der ProzessorLeistung
{
TCNT2 = 256 - 250; //Timer2 mit 6 neu vorladen
timer2++;
if(timer2 == 20)
{
timer2 = 0; //timer2 endet bei 20ms
timer1 = 0;
TCNT0 = 256 - 160; //Timer0 mit 96 vorladen, 1/16MHz*160 = 10µs
//alle Impulse starten
servo1on;
servo2on;
servo3on;
servo4on;
servo5on;
servo6on;
servo7on;
servo8on;
servo9on;
servo10on;
servo11on;
servo12on;
servo13on;
servo14on;
servo15on;
servo16on;
servo17on;
servo18on;
TIMSK |= (1 << TOIE0); //Timer0 Interrupt freigegeben
signals = 18; //Anzahl der laufenden Signale
}
}
SIGNAL (SIG_OVERFLOW0) //frisst ~95% der ProzessorLeistung
{
TCNT0 = 256 - 160; //Timer0 mit 96 neu vorladen
timer1++; //timer1 Zähler misst die impulsdauer in 10µs Schritten
//Bei erreichen der Sollpulsdauer wird der jeweilige Impuls beendet
if(timer1 == servo1){servo1off;signals--;}
if(timer1 == servo2){servo2off;signals--;}
if(timer1 == servo3){servo3off;signals--;}
if(timer1 == servo4){servo4off;signals--;}
if(timer1 == servo5){servo5off;signals--;}
if(timer1 == servo6){servo6off;signals--;}
if(timer1 == servo7){servo7off;signals--;}
if(timer1 == servo8){servo8off;signals--;}
if(timer1 == servo9){servo9off;signals--;}
if(timer1 == servo10){servo10off;signals--;}
if(timer1 == servo11){servo11off;signals--;}
if(timer1 == servo12){servo12off;signals--;}
if(timer1 == servo13){servo13off;signals--;}
if(timer1 == servo14){servo14off;signals--;}
if(timer1 == servo15){servo15off;signals--;}
if(timer1 == servo16){servo16off;signals--;}
if(timer1 == servo17){servo17off;signals--;}
if(timer1 == servo18){servo18off;signals--;}
if(signals == 0){TIMSK &= ~(1 << TOIE0);} //Timer0 stoppen, sobald alle Impulse erzeugt sind
}
mfg WarChild
Lesezeichen