使用 PWM 生成正弦信号

电器工程 微控制器 C 脉宽调制
2022-01-08 14:12:05

我们无法使用MC68HC908GP32微控制器正确生成正弦信号。PWM 描述从第 349 页开始。时钟频率为 2.4MHz,而我们通过使用预分频器并将定时器模数设置为 350 来使用 7 kHz PWM,如下所示:

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

PWM 输出通过以下 RLC 滤波器进行滤波,然后使用串联的 1uF 电容去除 DC。截止频率远低于 PWM 的 7kHz。

在此处输入图像描述

首先,我们尝试使用 LUT,这些样本是使用此站点生成的(100 个样本,幅度 = 250)。这包括一个时期。

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

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

将其插入示波器时,我们会收到以下信号。我们无法避免接近最小值的那个奇怪的峰值。

在此处输入图像描述

当放大该峰值时,我们可以看到 PWM 输出(向上)实际上是如何不正确的。

在此处输入图像描述

因此,在搞砸了一段时间并无法摆脱它之后,我们尝试在 MCU 中计算正弦信号,而不是对每个样本的值进行硬编码。我们在 main 函数中添加了以下代码,就在所有计数器设置之前:

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

但结果甚至看起来不像正弦曲线:

在此处输入图像描述

经过几个小时的努力,我们一直无法找到我们的错误。我们将不胜感激。

1个回答

在微控制器数据表第 350 页的底部,它提到在溢出中断期间向定时器值寄存器写入一个小值可能会导致仅在下一次 pwm 迭代时触发下一个中断,因为定时器继续计数,而正在执行中断程序。

对 TIM 通道寄存器进行非同步写入以更改脉冲宽度值可能会导致最多两个 PWM 周期的错误操作。例如,在计数器达到旧值之前但在计数器达到新值之后写入一个新值会阻止在该 PWM 周期内进行任何比较。此外,使用 TIM 溢出中断程序写入一个新的、更小的脉冲宽度值可能会导致比较失败。TIM 可能会在新值被写入之前传递它。

这可以通过以下事实得到证实:pwm 值在整个 pwm 时钟周期内保持高电平 + 看起来像计时器长度(基于周围长度)。错误时写入定时器长度寄存器的值可能接近 0,因此计数器在中断期间已通过较小的值是完全可行的,并且只会在下一个周期触发。

这可以通过将正弦波最小级别增加到高于执行 ISR 所需时间的级别,或更改设置新级别的机制来解决。第 351 页的顶部详细说明了如何执行此操作。