No podemos generar una señal sinusoidal correctamente con un microcontrolador MC68HC908GP32 . La descripción de PWM comienza en la página 349. La frecuencia del reloj es de 2,4 MHz, mientras que hemos usado PWM de 7 kHz usando el preescalador y configurando el módulo del temporizador en 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 con el siguiente filtro RLC, y luego se elimina la CC usando un límite de serie de 1uF. La frecuencia de corte está muy por debajo de los 7kHz de PWM.
Primero, hemos intentado usar un LUT, cuyas muestras se generaron usando este sitio (100 muestras, amplitud = 250). 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 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(;;);
}
Al enchufarlo en el alcance, obtenemos la siguiente señal. No podemos evitar ese pico extraño cerca del mínimo.
Al hacer zoom alrededor de ese pico, podemos ver cómo la salida PWM (hacia arriba) es incorrecta.
Entonces, después de perder el tiempo por un tiempo 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:
Después de horas luchando con él, no hemos podido encontrar nuestro error. Agradeceríamos un consejo.
En la parte inferior de la página 350 de la hoja de datos del microcontrolador, se menciona que escribir un valor pequeño en el registro de valor del temporizador durante la interrupción de desbordamiento podría causar que la siguiente interrupción se active solo en la siguiente iteración de 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 hasta por dos períodos de 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 de PWM. Además, el uso de una rutina de interrupción de desbordamiento de 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 un período completo de reloj de pwm + lo que parece ser la duración del temporizador (basado en las longitudes circundantes). El valor que se escribe en el registro de duración del temporizador probablemente esté cerca de 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 active en el ciclo siguiente.
Esto podría solucionarse aumentando el nivel mínimo de la sinusoide a un nivel superior al tiempo que lleva ejecutar la ISR, o cambiando el mecanismo mediante el cual se establece el nuevo nivel. La parte superior de la página 351 detalla cómo se puede hacer esto.
pjc50
Sarga
pjc50
Trygve Laugstöl
Andy alias
Sarga
T1CH0H = ((seno[fase]+10)>>8);
yT1CH0L = (seno[fase]+10)&0xFF;
), obteniendo un resultado similar . Simplemente no puedo encontrar ninguna lógica detrás de esto.Sarga
Anindo Ghosh
Anindo Ghosh
255 - value
yindexMax - index
combinaciones.yippie
T1CH0H
yT1CH0L
sobre la serie, para que pueda ver los valores reales escritos en los registros PWM?yippie
seno
modo que contenga dos ondas completas y luegofase
cuente hasta 199 en lugar de 99. Si la distorsión aún aparece en cada ciclo, es causada por los valores escritos en los canales PWM. Siga el consejo de @AnindoGhosh para disminuir la amplitud.