PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verzögerte PWM ausgabe. Ansatz gesucht.



BlaueLed
26.07.2010, 22:51
Hallo zusammen,

ich steh momentan auf dem Schlauch. Ich lese über Getadc(0) einen Analogwert ein und gebe diesen 1:1 über pwm1a wieder aus. Jetzt ist es aber so, das der Wert sprungartig = 1023 ist. Dann würde meine PWM auch sprungartig auf den Wert 1023 springen. Das will ich aber verhindern. Wenn der Wert des ADC sprungartig ansteigt, soll meine PWM auf diesen Wert langsam ( 1-3 sec ) hochlaufen. Mir fehlt aber momentan der Lösungsansatz dafür. Kann mir bitte jemand einen Denkanstoß geben ?

Gruß Kay

Felix H.
26.07.2010, 23:13
du hast ja deinen ADC in eine Variable geladen. Den vorherigen Wert machst du auch in eine Variable. Dann schaust du ob der neue Wert kleiner oder größer is und zählst in einer schleife einfach den wert um 1 hoch bzw. runter und wartest ein paar millisekunden. Das machst du solange bis dein Wert dem Getadc entspricht.



Oder ist es wichtig, dass dieser Teil des Codes den restlichen Code nicht aufhält?

DeVlinder
26.07.2010, 23:24
Ich denke du könntest einen Tiefpass, ein PT1-Glied implementieren, siehe zB hier: http://de.wikipedia.org/wiki/PT1-Glied#Zeitdiskretes_PT1-Glied

Das sorgt für ein "weiches" Sprungverhalten und damit Dämpfen von hohen Frequenzen.

BlaueLed
27.07.2010, 01:06
Danke für die Antworten. Wait wollte ich zuerst auch benutzen, aber es kann durchaus sein, das der Wert auch wieder sprungartig zurückgeht. Dann muss die PWM allerdings in diesem Moment auch zurück gehen. Nur beim ansteigen soll es langsam mit ansteigen.

Gruß Kay

Richard
27.07.2010, 07:12
Dann prpüfe doch einfach auf ADC > PWM und führe nur
wenn Ja ein "for PWM = PWM TO ADC Step xyz " aus was
Du bei ADC < PWM überspringst....

Gruß Richard

s.o.
27.07.2010, 09:36
Quick 'n' Dirty Vorschlag, der was von Tiefpass hat.

Ich notier dir das ganze aber in C, da ich von Basecom absolut garnichts halte. (DA TOTAL INEFFIZENT!)


16 Bit variablen:
currentadcval: Momentaner ADC wert
preadcval: ADC wert vom Vorherigen durchlauf
diff: Differenz der Werte

void pwm_output(currentadcval){
if(currentadcval>preadcval){
diff=currentadcval-preadcval;
PWM+=diff/4; // Faktor entsprend skalieren, aber nicht zu groß machen und immer Potenzen von 2 verwenden! (Hät den Code klein!)
}else{
PWM=currentadcval;
}
preadcval=currentadcval;
}


So, wenn du die Funktion jetzt alle 1/4 sec aufrufst (ja nicht zu oft, sonst wird die Änderung zu krass), sollte das ganze passen.

DeVlinder
27.07.2010, 11:33
@ s.o. :
Ich glaube bei deiner Funktion treten zwei Probleme auf.

Fall 1: Die ADC-Messung steigt stark an und bleibt dann auf einem Wert oder sinkt ganz leicht. Dann wird im ersten Schritt zwar verzögert, aber im zweiten Schritt der PWM-Wert sofort nachgeführt, weil in den else-abschnitt gesprungen wird.
Beispiel:
ADC: 0; 0; 1; 1; ...
PWM: 0; 0; 0,25; 1; ...

Fall 2: Der ADC-Wert steigt stark an, und steigt dann ganz leicht weiter... in diesem Fall wird die Variable "diff" sehr sehr klein, und PWM kaum erhöht, der Zielwert also gar nicht erreicht.

Beispiel:
ADC: 0; 0; 0,9; 0,91; 0,92; ...
PWM: 0; 0; 0,225; 0,2275; 0,23; ...

Im Anhang ein Plot von den zwei Problemen

s.o.
27.07.2010, 12:02
Ja, du hast recht, das mit der Differenz führt zu Fehlern. Anderer Vorschlag: Ringpuffer und die ADC Werte mitteln. Falls ADC Wert kleiner als das Mittel, den ausgeben, sonst das Mittel. (Verbraucht aber deutlich mehr Rechenpower)
Wenn jemand eine Lösung OHNE das Speichern alter Werte hat, dann wäre ich darauf gespannt wie ein Fuchs.

EDIT: Ich habe den Fehler gefunden: (hoffentlich!)


16 Bit variablen:
currentadcval: Momentaner ADC wert
preadcval: ADC wert vom Vorherigen durchlauf
diff: Differenz der Werte

void pwm_output(currentadcval){
if(currentadcval>preadcval){
diff=currentadcval-PWM;
PWM+=diff/4; // Faktor entsprend skalieren, aber nicht zu groß machen und immer Potenzen von 2 verwenden! (Hät den Code klein!)
}else{
PWM=currentadcval;
}
preadcval=currentadcval;
}