使用PWM产生正弦信号


16

我们无法使用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

通过以下RLC滤波器对PWM输出进行滤波,然后使用串联的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中计算正弦信号,而不是对每个样本的值进行硬编码。在所有计数器设置之前,我们在主要功能中添加了以下代码:

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

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

在此处输入图片说明

经过数小时的努力,我们仍然无法发现错误。我们将不胜感激。


您可以发布整个PWM值列表吗?
pjc50 2013年

@ pjc50这是:pastebin.com/sNyA0Hki。非常感谢你。
Serge 2013年

尝试用“ 1”替换中间的所有“ 0”值;我怀疑0会给您带来较宽的高信号,而不是您想要的低信号。
pjc50

@Serge-请内联数据。粘贴可能会消失,失去一部分问题将很糟糕。但是请格式化它,以免占用太多空间。谢谢。
特里夫洛格斯托尔

显然不是过滤器-祝您好运-看起来您的表已损坏或丢失了指向它的指针。
安迪(aka Andy)

Answers:


16

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

不同步写入TIM通道寄存器以更改脉冲宽度值可能导致多达两个PWM周期的错误操作。例如,在计数器达到旧值之前但在计数器达到新值之后写入新值可防止在该PWM周期内进行任何比较。同样,使用TIM溢出中断例程写入新的较小的脉冲宽度值可能会导致比较丢失。TIM可能会在写入新值之前通过新值。

这可以通过以下事实得到确认:pwm值在整个pwm时钟周期+看起来像计时器长度(基于周围长度)的过程中保持较高。发生错误时,写入计时器长度寄存器的值可能接近于0,因此计数器在中断期间传递较小的值是很可行的,并且仅在下一个周期触发。

可以通过将正弦曲线最小级别提高到高于执行ISR所需时间的级别或更改设置新级别的机制来解决此问题。页面351的顶部详细说明了如何完成此操作。


1
我不知道如何在阅读数据表时跳过它。谢谢!
Serge 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.