Geração de sinal senoidal usando PWM

16

Não conseguimos gerar um sinal senoidal adequadamente usando um microcontrolador MC68HC908GP32 . A descrição do PWM começa na página 349. A frequência do relógio é de 2,4 MHz, enquanto usamos o PWM de 7 kHz usando o prescaler e configurando o módulo do temporizador para 350 da seguinte maneira:

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

A saída PWM é filtrada pelo seguinte filtro RLC e o DC é removido usando uma tampa de 1uF da série. A frequência de corte está bem abaixo dos 7kHz do PWM.

insira a descrição da imagem aqui

Primeiro, tentamos usar um LUT, cujas amostras foram geradas usando este site (100 amostras, amplitude = 250). Isso compreende um único 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}; 

A largura do pulso a seguir é calculada a 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(;;);   
}

Ao conectá-lo ao escopo, obtemos o seguinte sinal. Não conseguimos evitar esse pico estranho próximo ao mínimo.

insira a descrição da imagem aqui

Ao ampliar esse pico, podemos ver como a saída PWM (para cima) está de fato incorreta.

insira a descrição da imagem aqui

Portanto, depois de mexer um pouco e sem conseguir nos livrar dele, tentamos calcular o sinal senoidal no MCU, em vez de codificar o valor de cada amostra. Nós adicionamos o seguinte código na função principal, imediatamente antes de toda a configuração do contador:

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

Mas os resultados nem parecem sinusóides:

insira a descrição da imagem aqui

Depois de horas lutando com isso, não conseguimos encontrar nosso erro. Gostaríamos de receber um conselho.

Sarja
fonte
Você poderia postar a lista inteira de valores PWM?
Pjc50
@ pjc50 Aqui está: pastebin.com/sNyA0Hki . Muito obrigado.
Serge
Tente substituir todos os valores "0" no meio por "1"; Eu suspeito que 0 dê a você aquele sinal alto alto, em vez de um sinal baixo que você deseja.
pjc50
@ Emerge - Por favor, inline os dados. A pasta pode desaparecer e seria ruim perder parte da pergunta. Mas formate-o para não usar tanto espaço. Obrigado.
Trygve Laugstøl
Claramente não é o filtro - boa sorte - parece que sua mesa está corrompida ou você perde o ponteiro para ela.
Andy aka

Respostas:

16

Na parte inferior da página 350 da folha de dados do microcontrolador, ele menciona que gravar um pequeno valor no registro do valor do timer durante a interrupção de estouro pode fazer com que a próxima interrupção seja acionada apenas na próxima iteração pwm, uma vez que o timer continua a contar enquanto o rotina de interrupção está sendo executada.

Uma gravação não sincronizada nos registradores do canal TIM para alterar um valor de largura de pulso pode causar operação incorreta por até dois períodos PWM. Por exemplo, escrever um novo valor antes que o contador atinja o valor antigo, mas depois que o contador atingir o novo valor, impede qualquer comparação durante esse período do PWM. Além disso, o uso de uma rotina de interrupção de estouro TIM para gravar um novo valor menor da largura de pulso pode fazer com que a comparação seja perdida. O TIM pode passar o novo valor antes de ser gravado.

Isso é confirmado pelo fato de que o valor pwm é mantido alto por um período inteiro do relógio pwm + o que parece com a duração do temporizador (com base nos comprimentos circundantes). O valor que está sendo gravado no registro de duração do timer provavelmente está próximo de 0 no momento do erro, portanto, é bastante viável que o contador tenha passado o valor menor durante a interrupção e seria acionado apenas no ciclo a seguir.

Isso pode ser corrigido aumentando o nível mínimo do senoide para um nível superior ao tempo necessário para executar o ISR ou alterando o mecanismo pelo qual o novo nível é definido. A parte superior da página 351 detalha como isso pode ser feito.

Stanri
fonte
11
Não sei como pular isso ao ler a folha de dados. Obrigado!
27413 Serge