PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM mit AVR: Rätselhafte Pulssprünge



Minifriese
01.06.2009, 19:30
Moin moin!

Ich erzeuge mit einem ATmega48 vier PWM-Signale, mit denen ich jeweils einen Brushless-Regler mit entsprechendem Motor ansteuere. Im Prinzip funktioniert das auch super. Bloß, wenn ich die Drehzahl der Motoren ändere, zum Beispiel mit einer steigenden Rampe für die PWM-Pulse von 1 ms bis 2 ms, dann ändert sie sich nicht gleichmäßig, sondern springt gelegentlich zurück und läuft von dem kleineren Wert weiter.

Mit dem Testprogramm unten wollte ich der Sache auf den Grund gehen. Die Werte im Testarray werden der Reihe nach an den Regler gegeben. Den ersten Wert (2000, entspricht 1 ms) braucht der Regler zum Anspringen; der Motor läuft erst beim zweiten Wert los. Dann werden die weiteren Werte für jeweils etwa 5 sec gehalten. Von 2350 auf 2360 springt die Drehzahl aber nicht hoch, sondern deutlich hörbar auf einen viel kleineren Wert. Von diesem kleineren Wert geht es dann in 5-sec-Schritten weiter aufwärts, bis nach dem letzten Wert im Array wieder die 2000 kommen und der Motor stehenbleibt.

Während einer 20-sec-Rampe von 1 ms bis 2 ms (mit einem anderen Programm) kommen mehrere solcher Sprünge vor und es scheint auch so zu sein, daß die Drehzahl zwischendurch manchmal wieder auf die ursprünglichen Rampenverlauf hochspringt. Sorry, weiß nicht, wie ich das besser ausdrücken soll... Genau messen kann ich die Drehzahl leider nicht, habe keinen Drehzahlmesser (abgesehen vom Gehör ;-) ).

Kann sich irgendjemand erklären, woher diese Sprünge in der Drehzahl kommen??

Alle vier BL-Regler/Motoren verhalten sich gleich, also vermute ich den Fehler eher in der Pulslänge. Die läßt sich leider nicht genau messen. Ich habe zwar ein Oszi, aber das triggert die Pulse nicht richtig. Wenn ich die Auflösung so stelle, daß ich einen Puls genau messen kann, erscheinen nur noch sporadisch Pulse auf dem Bildschirm. Zoome ich soweit raus, daß z.B. 5 Pulse auf dem Schirm sind, kann ich erkennen, daß die Pulse zwischen 1 ms und 2 ms lang sind und sich alle 20 ms wiederholen, aber dann läßt sich die Pulslänge schlecht genauer messen... Das Oszi-Bild springt immer etwas hin und her, also hat entweder der Trigger ne Macke, oder meine Funktion zur PWM-Erzeugung. Vermutlich eher letzteres, aber ich find den Fehler einfach nicht.

Ach so: der Motor pfeift immer ein bißchen. Das macht er nicht, wenn ich statt meines AVRs einen RC-Empfänger benutze. Ich denke, das spricht auch für einen Fehler in meinem Programm.

Hier ist der Code:


// Code for ATmega48/16MHz

#include <avr/io.h>
#include <avr/interrupt.h>

#define MIN 2000 // Clock cycles for a PWM pulse of 1 ms (Timer0, prescaler=8)
#define MAX 4000 // Clock cycles for a PWM pulse of 2 ms (Timer0, prescaler=8)
#define PERIOD 40000 // Clock cycles for whole PWM period of 20 ms (Timer 0, prescaler=8)

volatile long sig_3,sig_4,sig_5,sig_6,sigcount_3,sigcount_4,sigc ount_5,sigcount_6,percounter=PERIOD;
volatile long auxcounter=0;
volatile int i=0;
volatile long testarray[]={2000,2330,2340,2350,2360,2370,2380,2390,2400,241 0,2420,2430,2440,2450,2460};

long min(long a, long b, long c, long d, long e, long f) {
long h=a;
if((b<h)&&(b>0)) h=b;
if((c<h)&&(c>0)) h=c;
if((d<h)&&(d>0)) h=d;
if((e<h)&&(e>0)) h=e;
if((f<h)&&(f>0)) h=f;
return h;
}

ISR(SIG_OUTPUT_COMPARE0A) {
if(sigcount_3>0) sigcount_3-=OCR0A;
if(sigcount_4>0) sigcount_4-=OCR0A;
if(sigcount_5>0) sigcount_5-=OCR0A;
if(sigcount_6>0) sigcount_6-=OCR0A;
if(percounter>0) percounter-=OCR0A;

if(sigcount_3==0) { PORTB&=~(0x02); } //Reset Pin OC1A (=PB1)
if(sigcount_4==0) { PORTB&=~(0x04); } //Reset Pin OC2B (=PB2)
if(sigcount_5==0) { PORTB&=~(0x08); } //Reset Pin OC2A (=PB3)
if(sigcount_6==0) { PORTD&=~(0x08); } //Reset Pin OC2B (=PD3)

if(percounter==0) {
/*Block TWI Interrupt*/
percounter=PERIOD; //New period starts
sigcount_3=sig_3; PORTB|=(0x02); //Set Pin OC1A (=PB1)
sigcount_4=sig_4; PORTB|=(0x04); //Set Pin OC1B (=PB2)
sigcount_5=sig_5; PORTB|=(0x08); //Set Pin OC2A (=PB3)
sigcount_6=sig_6; PORTD|=(0x08); //Set Pin OC2B (=PD3)
OCR0A=255;
}

OCR0A=min(255,percounter,sigcount_3,sigcount_4,sig count_5,sigcount_6); //smallest value that is GREATER THAN ZERO (see min() )
if((sigcount_3==0) && (sigcount_4==0) && (sigcount_5==0) && (sigcount_6==0)) /*release TWI Interrupt*/;
}

ISR(SIG_OVERFLOW0) {
if(auxcounter<39000) auxcounter++;
else {
auxcounter=0;
i++;
if(i>14) i=0;
sig_3=testarray[i];
sig_4=testarray[i];
sig_5=testarray[i];
sig_6=testarray[i];
}
}

int main(void) {

DDRB = 0xFF;
DDRD = 0xFF;

TIMSK0 = (1<<OCIE0A)|(1<<TOIE0); // Activate Overflow- and OutputCompare interrupts
TCCR0B = (1<<CS01); // Prescaler=8 --> 16 MHz/8 = 2 MHz --> 1 click = 0.5 µs
OCR0A = 255;

sig_3=testarray[i];
sig_4=testarray[i];
sig_5=testarray[i];
sig_6=testarray[i];
sigcount_3=sig_3;
sigcount_4=sig_4;
sigcount_5=sig_5;
sigcount_6=sig_6;

sei();

while(1) {

}

return 0;
}

Kann jemand helfen?

Vielen Dank,

Nils

yaro
01.06.2009, 22:10
Hab mir den Code zwar nicht richtig angeguckt, aber das problem hört sich sehr nach einem Variablenüberlauf an.
Übrigens, wieso verwendest du keinen 16bit Timer? Vielleicht liegt das Problem dort.

Gruß, Yaro

SprinterSB
01.06.2009, 23:34
Ganz sicher zu Problemen führt die Verwendung des volatile-Zeugs.

Weiterlesen zB hier:

http://www.rn-wissen.de/index.php/Fallstricke_bei_der_C-Programmierung#Nicht-atomarer_Code