Mit einem MC68HC908GP32- Mikrocontroller können wir kein Sinussignal richtig erzeugen. Die PWM-Beschreibung beginnt auf Seite 349. Die Taktfrequenz beträgt 2,4 MHz, während wir 7-kHz-PWM verwendet haben, indem wir den Prescaler verwendet und den Timer-Modulo wie folgt auf 350 eingestellt haben:
T1SC = 0x60; // Prescaler: Div entre 64
//Counter modulo = 0x015E = 350
T1MODH = 0x01; // High
T1MODL = 0x5E; // Low
Der PWM-Ausgang wird durch den folgenden RLC-Filter gefiltert, und dann wird DC mit einer 1uF-Kappe der Serie entfernt. Die Grenzfrequenz liegt weit unter den 7kHz von PWM.
Zuerst haben wir es mit einer LUT versucht, welche Samples mit dieser Seite generiert wurden (100 Samples, Amplitude = 250). Diese umfasst eine einzelne Periode.
int seno[100]={ 125, 133, 141, 148, 156, 164, 171, 178, 185, 192, 198, 205, 211, 216, 221, 226, 231, 235, 238, 241, 244, 246, 248, 249, 250, 250, 250, 249, 248, 246, 244, 241, 238, 235, 231, 226, 221, 216, 211, 205, 198, 192, 185, 178, 171, 164, 156, 148, 141, 133, 125, 117, 109, 102, 94, 86, 79, 72, 65, 58, 52, 45, 39, 34, 29, 24, 19, 15, 12, 9, 6, 4, 2, 1, 0, 0, 0, 1, 2, 4, 6, 9, 12, 15, 19, 24, 29, 34, 39, 45, 52, 58, 65, 72, 79, 86, 94, 102, 109, 117};
Die Breite des folgenden Impulses wird bei jedem PWM-Zyklus berechnet:
interrupt 4 void rsi_t1ch0 (void)
{
//-- disable interruption flag
T1SC0&=(~0x80);
//-- pwm to '0'
PTB&=0xFD;
//some sensor measures are done here.... 100 out of the 350 cycles are left for this
}
/************************************************************/
/* TIM1 overflow rutine */
/************************************************************/
interrupt 6 void rsi_ov1 (void)
{
T1SC&=(~0x80);
//-- set PWM to 1
PTB|=0x02;
T1CH0H = ((seno[fase])>>8); // high bits
T1CH0L = (seno[fase])&0xFF; // low bits
fase+=1;
if (fase >= 99)
fase=0;
}
void main(void)
{
float temp;
int i;
CONFIG1|=0x01;
DDRB=0xFF; //-- Port B is set as output
PTB=0x00;
//Timer setup
T1SC = 0x60; // Prescaler: Div by 64
T1MODH = 0x01; //Counter modulo
T1MODL = 0x5E;
T1SC0 = 0x50; //Comparator setup
//-- Initial width
T1CH0H = 0x00;
T1CH0L = 0x53;
EnableInterrupts;
T1SC&=~(0x20); //Run timer forever
for(;;);
}
Beim Einstecken in das Oszilloskop erhalten wir das folgende Signal. Wir sind nicht in der Lage, diese seltsame Spitze in der Nähe des Minimums zu vermeiden.
Wenn wir um diese Spitze herumzoomen, können wir sehen, dass der PWM-Ausgang (nach oben) tatsächlich falsch ist.
Nachdem wir also eine Weile herumgespielt und es nicht losgeworden waren, haben wir versucht, das Sinussignal in der MCU zu berechnen, anstatt den Wert für jedes Sample fest zu codieren. Wir haben den folgenden Code in der Hauptfunktion hinzugefügt, kurz vor der gesamten Zählereinrichtung:
for(i=0;i<99;i++) {
temp=100*(sin(2*3.14159*i/100)+1);
seno[i]=(int)temp;
}
Aber die Ergebnisse sehen nicht einmal wie eine Sinuskurve aus:
Nachdem wir stundenlang damit gekämpft haben, konnten wir unseren Fehler nicht finden. Wir würden uns über einen Rat freuen.
Unten auf Seite 350 des Mikrocontroller-Datenblatts wird erwähnt, dass das Schreiben eines kleinen Werts in das Timer-Wertregister während des Überlauf-Interrupts dazu führen kann, dass der nächste Interrupt erst bei der nächsten pwm-Iteration ausgelöst wird, da der Timer währenddessen weiterzählt Interrupt-Routine wird ausgeführt.
Ein unsynchronisiertes Schreiben in die TIM-Kanalregister zum Ändern eines Impulsbreitenwerts könnte einen fehlerhaften Betrieb für bis zu zwei PWM-Perioden verursachen. Beispielsweise verhindert das Schreiben eines neuen Werts, bevor der Zähler den alten Wert erreicht, aber nachdem der Zähler den neuen Wert erreicht, jeglichen Vergleich während dieser PWM-Periode. Außerdem kann die Verwendung einer TIM-Überlauf-Unterbrechungsroutine zum Schreiben eines neuen, kleineren Impulsbreitenwerts dazu führen, dass der Vergleich verpasst wird. Das TIM kann den neuen Wert übergeben, bevor er geschrieben wird.
Dies wird durch die Tatsache bestätigt, dass der PWM-Wert für eine ganze PWM-Taktperiode hoch gehalten wird + was wie die Timer-Länge aussieht (basierend auf den umgebenden Längen). Der Wert, der in das Timer-Längenregister geschrieben wird, ist zum Zeitpunkt des Fehlers wahrscheinlich nahe 0, daher ist es durchaus möglich, dass der Zähler während des Interrupts den kleineren Wert überschritten hat und erst im folgenden Zyklus auslösen würde.
Dies könnte behoben werden, indem der sinusförmige Mindestpegel auf einen Pegel erhöht wird, der höher ist als die Zeit, die zum Ausführen der ISR benötigt wird, oder indem der Mechanismus geändert wird, durch den der neue Pegel eingestellt wird. Oben auf Seite 351 wird detailliert beschrieben, wie dies durchgeführt werden kann.
pjc50
Serge
pjc50
Trygve Laugstøl
Andi aka
Serge
T1CH0H = ((seno[fase]+10)>>8);
undT1CH0L = (seno[fase]+10)&0xFF;
) und ein ähnliches Ergebnis erzielt . Ich finde einfach keine Logik dahinter.Serge
Anindo Ghosh
Anindo Ghosh
255 - value
, undindexMax - index
-Kombinationen abgeleitet werden.Jippie
T1CH0H
undT1CH0L
über seriell drucken, damit Sie die tatsächlichen Werte sehen können, die in die PWM-Register geschrieben wurden?Jippie
seno
, damit es zwei volle Wellen enthält, undfase
zählen Sie dann bis 199 statt 99. Wenn die Verzerrung immer noch bei jedem Zyklus auftritt, wird sie durch die in die PWM-Kanäle geschriebenen Werte verursacht. Befolgen Sie den Rat von @AnindoGhosh, um die Amplitude zu verringern.