Generación de señal sinusoidal utilizando PWM

16

No podemos generar una señal sinusoidal correctamente utilizando un microcontrolador MC68HC908GP32 . La descripción de PWM comienza en la página 349. La frecuencia del reloj es de 2.4MHz, mientras que hemos usado PWM de 7 kHz usando el preescalador y configurando el módulo del temporizador a 350 de la siguiente manera:

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

La salida PWM se filtra mediante el siguiente filtro RLC, y luego se elimina la CC con una tapa de serie 1uF. La frecuencia de corte está muy por debajo de los 7kHz de PWM.

ingrese la descripción de la imagen aquí

Primero, hemos intentado usar un LUT, cuyas muestras se generaron usando este sitio (100 muestras, amplitud = 250). Esto comprende un solo período.

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

El ancho del siguiente pulso se calcula en cada 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(;;);   
}

Cuando lo conectamos al alcance, obtenemos la siguiente señal. No podemos evitar ese pico extraño cerca del mínimo.

ingrese la descripción de la imagen aquí

Al hacer zoom alrededor de ese pico, podemos ver cómo la salida PWM (arriba) es de hecho incorrecta.

ingrese la descripción de la imagen aquí

Entonces, después de jugar un rato y no poder deshacernos de él, hemos intentado calcular la señal sinusoidal en la MCU, en lugar de codificar el valor de cada muestra. Hemos agregado el siguiente código en la función principal, justo antes de toda la configuración del contador:

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

Pero los resultados ni siquiera parecen una sinusoide:

ingrese la descripción de la imagen aquí

Después de horas luchando con eso, no hemos podido encontrar nuestro error. Agradeceríamos un consejo.

Sarga
fuente
¿Podría publicar la lista completa de valores PWM?
pjc50
@ pjc50 Aquí está: pastebin.com/sNyA0Hki . Muchas gracias.
Serge
Intente reemplazar todos los valores "0" en el medio con "1"; Sospecho que 0 le da esa señal alta y ancha en lugar de una señal baja que desea.
pjc50
@Serge: incluya los datos en línea. La pasta podría desaparecer y sería malo perder una parte de la pregunta. Pero por favor formateelo para que no use tanto espacio. Gracias.
Trygve Laugstøl
Claramente no es el filtro, buena suerte, parece que su mesa se está corrompiendo o pierde su puntero.
Andy aka

Respuestas:

16

En la parte inferior de la página 350 de la hoja de datos del microcontrolador, menciona que escribir un valor pequeño en el registro del valor del temporizador durante la interrupción por desbordamiento podría provocar que la próxima interrupción se active solo en la siguiente iteración pwm, ya que el temporizador continúa contando mientras el Se está ejecutando la rutina de interrupción.

Una escritura no sincronizada en los registros del canal TIM para cambiar un valor de ancho de pulso podría causar una operación incorrecta por hasta dos períodos PWM. Por ejemplo, escribir un nuevo valor antes de que el contador alcance el valor anterior pero después de que el contador alcance el nuevo valor evita cualquier comparación durante ese período PWM. Además, el uso de una rutina de interrupción de desbordamiento TIM para escribir un nuevo valor de ancho de pulso más pequeño puede hacer que se pierda la comparación. El TIM puede pasar el nuevo valor antes de que se escriba.

Esto se confirma por el hecho de que el valor de pwm se mantiene alto durante todo un período de reloj pwm + lo que parece la duración del temporizador (en función de las longitudes circundantes). El valor que se escribe en el registro de longitud del temporizador probablemente sea cercano a 0 en el momento del error, por lo que es bastante viable que el contador haya pasado el valor más pequeño durante la interrupción, y solo se activará en el siguiente ciclo.

Esto podría solucionarse aumentando el nivel mínimo sinusoide a un nivel superior al tiempo que lleva ejecutar el ISR, o cambiando el mecanismo por el cual se establece el nuevo nivel. La parte superior de la página 351 detalla cómo se puede hacer esto.

Stanri
fuente
1
No sé cómo podría omitir eso al leer la hoja de datos. ¡Gracias!
Serge