Sinussignalerzeugung mit PWM

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.

Geben Sie hier die Bildbeschreibung ein

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.

Geben Sie hier die Bildbeschreibung ein

Wenn wir um diese Spitze herumzoomen, können wir sehen, dass der PWM-Ausgang (nach oben) tatsächlich falsch ist.

Geben Sie hier die Bildbeschreibung ein

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:

Geben Sie hier die Bildbeschreibung ein

Nachdem wir stundenlang damit gekämpft haben, konnten wir unseren Fehler nicht finden. Wir würden uns über einen Rat freuen.

Könnten Sie die gesamte Liste der PWM-Werte posten?
@pjc50 Hier ist es: pastebin.com/sNyA0Hki . Ich danke Ihnen sehr.
Versuchen Sie, alle "0"-Werte in der Mitte durch "1" zu ersetzen; Ich vermute, dass 0 Ihnen eher das breite hohe Signal als ein niedriges Signal gibt, das Sie wollen.
@Serge - Bitte inline die Daten. Die Paste könnte verschwinden und es wäre schlecht, einen Teil der Frage zu verlieren. Aber bitte formatieren Sie es so, dass es nicht so viel Platz verbraucht. Vielen Dank.
Es ist eindeutig nicht der Filter - viel Glück - sieht aus, als ob Ihre Tabelle beschädigt wird oder Sie Ihren Zeiger darauf verlieren.
@pjc50 Danke. Ich habe versucht, 1s in 0s zu ändern, um dies zu erhalten . Dann habe ich versucht, einen Offset auf das gesamte Signal anzuwenden (dh mit T1CH0H = ((seno[fase]+10)>>8);und T1CH0L = (seno[fase]+10)&0xFF;) und ein ähnliches Ergebnis erzielt . Ich finde einfach keine Logik dahinter.
@trygvis Danke für den Rat. Ich habe die Frage aktualisiert.
Bitte versuchen Sie dies und teilen Sie uns die Ergebnisse mit: Gehen Sie zurück zur LUT-Methode, aber generieren Sie Werte mit einem Bereich von 1 bis 254, nicht 0 bis 255, und versuchen Sie es erneut.
Außerdem müssen Sie keine LUT für den gesamten Zyklus generieren, dies kann mit einem Viertelzyklus (mit einem Bereich von 1 bis 127) erfolgen. Aufeinanderfolgende Viertelzyklen können unter Verwendung von 255 - value, und indexMax - index-Kombinationen abgeleitet werden.
Können Sie die Werte für T1CH0Hund T1CH0Lüber seriell drucken, damit Sie die tatsächlichen Werte sehen können, die in die PWM-Register geschrieben wurden?
Zur Fehlerbehebung: Verdoppeln Sie die Länge von seno, damit es zwei volle Wellen enthält, und fasezä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.

Antworten (1)

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.

Ich weiß nicht, wie ich das überspringen könnte, wenn ich das Datenblatt lese. Danke dir!