Génération de signal sinusoïdal à l'aide de PWM

16

Nous ne pouvons pas générer correctement un signal sinusoïdal à l'aide d'un microcontrôleur MC68HC908GP32 . La description du PWM commence à la page 349. La fréquence d'horloge est de 2,4 MHz, tandis que nous avons utilisé le PWM à 7 kHz en utilisant le pré-échelle et en réglant le module de minuterie sur 350 comme suit:

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

La sortie PWM est filtrée par le filtre RLC suivant, puis DC est retiré à l'aide d'un capuchon de 1 uF série. La fréquence de coupure est bien inférieure à 7 kHz de PWM.

entrez la description de l'image ici

Tout d'abord, nous avons essayé d'utiliser une LUT, dont les échantillons ont été générés en utilisant ce site (100 échantillons, amplitude = 250). Cela comprend une seule période.

 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 largeur de l'impulsion suivante est calculée à chaque cycle 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(;;);   
}

Lorsque vous le branchez dans la portée, nous obtenons le signal suivant. Nous ne pouvons pas éviter cet étrange pic proche du minimum.

entrez la description de l'image ici

En zoomant autour de ce pic, nous pouvons voir comment la sortie PWM (vers le haut) est en fait incorrecte.

entrez la description de l'image ici

Ainsi, après avoir gâché pendant un certain temps et être incapable de s'en débarrasser, nous avons essayé de calculer le signal sinusoïdal dans le MCU, au lieu de coder en dur la valeur de chaque échantillon. Nous avons ajouté le code suivant dans la fonction principale, juste avant toute la configuration du compteur:

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

Mais les résultats ne ressemblent même pas à une sinusoïde:

entrez la description de l'image ici

Après des heures de lutte, nous n'avons pas pu trouver notre erreur. Nous apprécierions un conseil.

Serge
la source
Pourriez-vous publier la liste complète des valeurs PWM?
pjc50
@ pjc50 Le voici: pastebin.com/sNyA0Hki . Merci beaucoup.
Serge
Essayez de remplacer toutes les valeurs "0" au milieu par "1"; Je soupçonne que 0 vous donne ce signal haut large plutôt qu'un signal bas que vous voulez.
pjc50
@Serge - Veuillez intégrer les données. La pâte pourrait disparaître et il serait mauvais de perdre une partie de la question. Mais veuillez le formater pour qu'il n'utilise pas beaucoup d'espace. Merci.
Trygve Laugstøl
Ce n'est clairement pas le filtre - bonne chance - votre table est corrompue ou vous perdez votre pointeur.
Andy aka

Réponses:

16

Au bas de la page 350 de la fiche technique du microcontrôleur, il mentionne que l'écriture d'une petite valeur dans le registre des valeurs du temporisateur pendant l'interruption de débordement peut provoquer le déclenchement de l'interruption suivante uniquement lors de l'itération pwm suivante, car le temporisateur continue de compter pendant que le la routine d'interruption est en cours d'exécution.

Une écriture non synchronisée dans les registres de canal TIM pour modifier une valeur de largeur d'impulsion peut entraîner un fonctionnement incorrect pendant jusqu'à deux périodes PWM. Par exemple, l'écriture d'une nouvelle valeur avant que le compteur n'atteigne l'ancienne valeur mais après que le compteur atteigne la nouvelle valeur empêche toute comparaison pendant cette période PWM. De plus, l'utilisation d'une routine d'interruption de débordement TIM pour écrire une nouvelle valeur de largeur d'impulsion plus petite peut entraîner l'échec de la comparaison. Le TIM peut transmettre la nouvelle valeur avant son écriture.

Ceci est confirmé par le fait que la valeur pwm est maintenue élevée pendant une période d'horloge pwm entière + ce qui ressemble à la longueur du temporisateur (sur la base des longueurs environnantes). La valeur en cours d'écriture dans le registre de longueur du temporisateur est probablement proche de 0 au moment de l'erreur, il est donc tout à fait viable que le compteur ait dépassé la valeur la plus petite pendant l'interruption et ne se déclenche qu'au cycle suivant.

Cela pourrait être résolu en augmentant le niveau minimum de la sinusoïde à un niveau supérieur au temps nécessaire pour exécuter l'ISR, ou en changeant le mécanisme par lequel le nouveau niveau est défini. Le haut de la page 351 explique comment procéder.

Stanri
la source
1
Je ne sais pas comment je pourrais ignorer cela en lisant la fiche technique. Je vous remercie!
Serge