Generazione del segnale sinusoidale tramite PWM


16

Non siamo in grado di generare correttamente un segnale sinusoidale utilizzando un microcontrollore MC68HC908GP32 . La descrizione di PWM inizia a pagina 349. La frequenza di clock è 2,4 MHz, mentre abbiamo utilizzato PWM a 7 kHz utilizzando il prescaler e impostando il modulo timer su 350 come segue:

T1SC = 0x60;    // Prescaler: Div entre 64
//Counter modulo = 0x015E = 350
T1MODH = 0x01;   // High
T1MODL = 0x5E;   // Low

L'uscita PWM viene filtrata dal seguente filtro RLC, quindi CC viene rimosso utilizzando un cappuccio serie 1uF. La frequenza di taglio è molto al di sotto dei 7kHz di PWM.

inserisci qui la descrizione dell'immagine

Innanzitutto, abbiamo provato a utilizzare un LUT, i quali campioni sono stati generati utilizzando questo sito (100 campioni, ampiezza = 250). Ciò comprende un singolo periodo.

 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}; 

La larghezza del seguente impulso viene calcolata ad ogni ciclo PWM:

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(;;);   
}

Quando lo inseriamo nel campo di applicazione, otteniamo il seguente segnale. Non siamo in grado di evitare quello strano picco vicino al minimo.

inserisci qui la descrizione dell'immagine

Quando si esegue lo zoom attorno a quel picco, possiamo vedere come l'uscita PWM (su) sia effettivamente errata.

inserisci qui la descrizione dell'immagine

Quindi, dopo aver pasticciato per un po 'e non essere in grado di liberarcene, abbiamo provato a calcolare il segnale sinusoidale nell'MCU, invece di codificare il valore per ogni campione. Abbiamo aggiunto il seguente codice nella funzione principale, appena prima di tutte le impostazioni del contatore:

 for(i=0;i<99;i++) {
     temp=100*(sin(2*3.14159*i/100)+1);
     seno[i]=(int)temp;
 }

Ma i risultati non sembrano nemmeno una sinusoide:

inserisci qui la descrizione dell'immagine

Dopo ore di difficoltà, non siamo riusciti a trovare il nostro errore. Gradiremmo un consiglio.


Potresti pubblicare l'intero elenco di valori PWM?
pjc50,

@ pjc50 Eccolo: pastebin.com/sNyA0Hki . Grazie mille.
Serge,

Prova a sostituire tutti i valori "0" nel mezzo con "1"; Ho il sospetto che 0 ti dia quel segnale alto e largo piuttosto che un segnale basso che desideri.
pjc50,

@Serge - Ti preghiamo di inserire i dati. La pasta potrebbe sparire e sarebbe male perdere una parte della domanda. Ma per favore formattalo in modo che non usi molto spazio. Grazie.
Trygve Laugstøl,

Chiaramente non è il filtro - buona fortuna - sembra che il tuo tavolo sia danneggiato o perdi il puntatore.
Andy aka

Risposte:


16

Nella parte inferiore della pagina 350 del foglio dati del microcontrollore, menziona che la scrittura di un piccolo valore nel registro dei valori del timer durante l'interruzione di overflow potrebbe causare l'attivazione dell'interruzione successiva solo sulla successiva iterazione pwm, poiché il timer continua a contare mentre il la routine di interruzione è in esecuzione.

Una scrittura non sincronizzata nei registri del canale TIM per modificare un valore di ampiezza dell'impulso potrebbe causare un funzionamento errato per un massimo di due periodi PWM. Ad esempio, scrivere un nuovo valore prima che il contatore raggiunga il valore precedente ma dopo che il contatore raggiunge il nuovo valore impedisce qualsiasi confronto durante quel periodo PWM. Inoltre, l'utilizzo di una routine di interrupt di overflow TIM per scrivere un nuovo valore di durata dell'impulso più piccolo può causare il mancato rispetto del confronto. TIM può passare il nuovo valore prima che sia scritto.

Ciò è confermato dal fatto che il valore pwm viene mantenuto alto per un intero periodo di orologio pwm + ciò che sembra la lunghezza del timer (in base alle lunghezze circostanti). Il valore che viene scritto nel registro della lunghezza del timer è probabilmente vicino a 0 al momento dell'errore, quindi è abbastanza fattibile che il contatore abbia superato il valore più piccolo durante l'interruzione e si attivi solo nel ciclo successivo.

Ciò potrebbe essere risolto aumentando il livello minimo sinusoidale a un livello superiore al tempo necessario per eseguire l'ISR o modificando il meccanismo con cui viene impostato il nuovo livello. La parte superiore della pagina 351 descrive in dettaglio come è possibile farlo.


1
Non so come potrei saltarlo leggendo il foglio dati. Grazie!
Serge
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.