搜索
bottom↓
回复: 2

在固定快速PWM模式下,因引入变量的传递而使频率改变的问题(急,求救,马老师)

[复制链接]

出0入0汤圆

发表于 2007-10-17 22:15:09 | 显示全部楼层 |阅读模式
马老师
  您好!好不容易找到这个网站,感觉好象是找到救星了,希望您能够给我指点一二,在下不胜感激!
我的问题是这样的,我做的是用ATmega8控制spwm波形,频率保持不变,但要求对幅值进行调整,调整办法是通过匹配值乘或除一个系数.我的部分程序是这样的:
#include <iom8v.h>
#include <macros.h>

#pragma data:code
// 128点正弦波样本表
const unsigned int auc_SinParam[256] = {0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 62, 69, 75, 81, 87, 92,
98, 104, 110, 115, 121, 127, 132, 137, 143, 148, 153, 158, 163, 168, 172, 177,
181, 186, 190, 194, 198, 202, 206, 210, 213, 217, 220, 223, 226, 229, 231, 234,
236, 239, 241, 243, 245, 246, 248, 249, 251, 252, 253, 253, 254, 255, 255, 255,
255, 255, 255, 254, 253, 253, 252, 251, 249, 248, 246, 245, 243, 241, 239, 236,
234, 231, 229, 226, 223, 220, 217, 213, 210, 206, 202, 198, 194, 190, 186, 181,
177, 172, 168, 163, 158, 153, 148, 143, 137, 132, 127, 121, 115, 110, 104, 98,
92, 87, 81, 75, 69, 62, 56, 50, 44, 38, 31, 25, 19, 13, 6, 0,
0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 62, 69, 75, 81, 87, 92,
98, 104, 110, 115, 121, 127, 132, 137, 143, 148, 153, 158, 163, 168, 172, 177,
181, 186, 190, 194, 198, 202, 206, 210, 213, 217, 220, 223, 226, 229, 231, 234,
236, 239, 241, 243, 245, 246, 248, 249, 251, 252, 253, 253, 254, 255, 255, 255,
255, 255, 255, 254, 253, 253, 252, 251, 249, 248, 246, 245, 243, 241, 239, 236,
234, 231, 229, 226, 223, 220, 217, 213, 210, 206, 202, 198, 194, 190, 186, 181,
177, 172, 168, 163, 158, 153, 148, 143, 137, 132, 127, 121, 115, 110, 104, 98,
92, 87, 81, 75, 69, 62, 56, 50, 44, 38, 31, 25, 19, 13, 6, 0
};
#pragma data:data
void timer2_ovf_isr(void);
void port_init(void);
void init_devices(void);
void adc_init(void);
unsigned char x_SW = 1,X_LUT = 0;
unsigned int adc_data;
float volt = 1.5;     ????????
void main(void)
{
init_devices();
   TCCR2 = 0x69; // 快速PWM模式,分频系数=1,正向控制OC0
   TIMSK = 0x40; // T/C0溢出中断允许
   SEI(); // 使能全局中断
   //for (;;)
   while(1)
    {}
}
#pragma interrupt_handler timer2_ovf_isr:5
void timer2_ovf_isr(void)
{   
     if (X_LUT >255)
    { X_LUT= 0; // 样点指针调整
      }
                //把AD采样值送给匹配寄存器
  
  OCR2=(int)((float)((auc_SinParam[X_LUT])/volt+0.5));//把上面的数表除以1.5,四舍五入后取整,按理频率不会改变,但是以外的是滤波以后的正玄波频
                                                       率改变了,但是当把上面的数表重新除以1.5,四舍五入后取整重新建立一个新数表代替前面的
                                                         数表的,赋 给匹配值,这个结果很好,频率没有改变,这到底是怎么回事情啊 ???????????
   

// 取样点指针到比较匹配寄存器
       
         X_LUT += x_SW; // 新样点指针

}

void port_init(void)
{
PORTB = 0xFF;
DDRB  = 0xFF;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0xFF;
DDRD  = 0xFB;
}

//call this routine to initialise all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x00;
port_init();
adc_init();
  } //timer interrupt sources
//re-enable interrupts
//all peripherals are now initialised

而且假如把float volt = 1.5;改成int volt=1 , OCR2=(int)((float)((auc_SinParam[X_LUT])/volt+0.5));改成OCR2=(int)(auc_SinParam[X_LUT])/volt);频率竟然改变了,真的很奇怪,不就把赋了个变量么?问题怎么会这么严重,难道非要写成
OCR2=auc_SinParam[X_LUT];才对吗,哪个volt是AD采样值,必须的用.
救救我吧,马老师!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2007-10-18 00:24:43 | 显示全部楼层
在我的讲义中已经明确的说明一个原则:中断服务程序应尽可能的短。

你的中断中使用了 OCR2=(int)((float)((auc_SinParam[X_LUT])/volt+0.5))这样的语句,这是浮点运算,需要占用大量的时间。你的中断服务时间太长,估计已经超过了一次T2的比较匹配甚至是全程计数的时间了。

举例:T2从溢出中断后,继续从0开始加1。你的中断经过长时间计算,得到OCR2 = 5,中断返回后,实际T2的数已经过了5了,波形就不对了。

解决办法:
1。提高AVR工作频率
2。采用整形数运算
3。在RAM中建立一个工作表,得到一个新的AD后,在主程序中进行计算,得到新的样值表,放入RAM的工作表中,然后在T2中断中调用,这样在T2中断中,只要使用赋值语句了。
4。根据你的样本表,一个正弦波最多为128个样点构成,根据你的应用条件频率不变,如果要求精度不高的话,可以使用64或32个样点。比如使用64点,当AD采样一次后,根据新的AD值,换算出新的64点的样本值,并且在T2的64次中断后使用新的样本表。


另外,你的程序中还有另外的问题,更换样值表应该是在一个完整的正弦波输出后。如果你的一个周期的正弦波是由128点组成,那么应该在第128点输出后才能使用新的样本表。而你的程序,在中断中的volt是随便变化的,还是每隔规定的点(如128次)后才改变的?

你程序中的样本表为什么使用INT型?为什么为256个?

出0入0汤圆

 楼主| 发表于 2007-10-19 16:14:50 | 显示全部楼层
谢谢马老师的指教,真没想到这么快能够得到马老师的回复,感谢您百忙之中热心的抽出时间来看我的程序,还对我的问题进行了耐心的分析和详解,真是万分感谢!您对该程序提出的问题一针见血!按照您的建议,我把浮点运算放在主程序里面了,情况大为改观,但又出现的一个新问题,就是AD 转换时间不够的问题,把AD转换程序层层细分,出现的竟然是一个不变的方波,真是让我郁闷之及!这是我改过的全程序,特向马老师请教:

#include <iom8v.h>
#include <macros.h>
#pragma data:code
// 128点正弦波样本表
const unsigned int auc_SinParam[256] = {0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 62, 69, 75, 81, 87, 92,
98, 104, 110, 115, 121, 127, 132, 137, 143, 148, 153, 158, 163, 168, 172, 177,
181, 186, 190, 194, 198, 202, 206, 210, 213, 217, 220, 223, 226, 229, 231, 234,
236, 239, 241, 243, 245, 246, 248, 249, 251, 252, 253, 253, 254, 255, 255, 255,
255, 255, 255, 254, 253, 253, 252, 251, 249, 248, 246, 245, 243, 241, 239, 236,
234, 231, 229, 226, 223, 220, 217, 213, 210, 206, 202, 198, 194, 190, 186, 181,
177, 172, 168, 163, 158, 153, 148, 143, 137, 132, 127, 121, 115, 110, 104, 98,
92, 87, 81, 75, 69, 62, 56, 50, 44, 38, 31, 25, 19, 13, 6, 0,
0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 62, 69, 75, 81, 87, 92,
98, 104, 110, 115, 121, 127, 132, 137, 143, 148, 153, 158, 163, 168, 172, 177,
181, 186, 190, 194, 198, 202, 206, 210, 213, 217, 220, 223, 226, 229, 231, 234,
236, 239, 241, 243, 245, 246, 248, 249, 251, 252, 253, 253, 254, 255, 255, 255,
255, 255, 255, 254, 253, 253, 252, 251, 249, 248, 246, 245, 243, 241, 239, 236,
234, 231, 229, 226, 223, 220, 217, 213, 210, 206, 202, 198, 194, 190, 186, 181,
177, 172, 168, 163, 158, 153, 148, 143, 137, 132, 127, 121, 115, 110, 104, 98,
92, 87, 81, 75, 69, 62, 56, 50, 44, 38, 31, 25, 19, 13, 6, 0
};
#pragma data:data
void timer2_ovf_isr(void);
void port_init(void);
void init_devices(void);
void adc_init(void);
unsigned char x_SW = 1,X_LUT = 0;
//unsigned int volt = 1000;
float volt=1;
int x;
//unsigned int i;

void main(void)
{ long temp;
  unsigned int ui_ADCL,ui_ADCH,adc_data;
  init_devices();
   
  // DDRB |= 0x08; // PB3(OC2)输出
   TCCR2 = 0x69; // 快速PWM模式,分频系数=1,正向控制OC0
   TIMSK = 0x40; // T/C0溢出中断允许
   SEI(); // 使能全局中断
   while(1)   
{   
  if (X_LUT =1)                         // 实行两个半波采样一次,就是256个点AD转换一次
  {
    ADCSRA=(1<<ADSC)|(1<<ADEN);  //启动A/D转换,是单次转换模式!
   }
   
   if (X_LUT =100)
  {
   while(!(ADCSRA&(1<<ADIF)));  // 等待AD转换结束
    ADCSRA |= (1<<ADIF);         //  写1清除标志位
   }
  if (X_LUT =120)
  {
   ui_ADCL = ADCL;           //Read 8 low bits first (important)
   ui_ADCH = ADCH ;          //read 2 high bits and shift into top byte
        adc_data =(ui_ADCH<<8)|ui_ADCL;  
   }
   if (X_LUT =150)
  {
   temp=(long)adc_data*2556;
   
   }
    if (X_LUT >253)
  {
   
    volt=(float)(temp/1024)/1000;
   }
  //x=(int)(((int)((unsigned long)(auc_SinParam[X_LUT])*1000000/volt)+500)/1000);  顺便提一个问题,浮点运算转整型运算
                                                                                       为什么会不行?
  x = (int)((float)(auc_SinParam[X_LUT])/volt+0.5);
}
}
#pragma interrupt_handler timer2_ovf_isr:5
void timer2_ovf_isr(void)

{   
if (X_LUT <127)
        {
         PORTB =(1<<PORTB2);
         
        }
   if (X_LUT >255)
   { X_LUT= 0; // 样点指针调整
      
        }
        if (X_LUT >127)
        {
           PORTB&=~(1<<PORTB2);
         }
        //把AD采样值送给匹配寄存器
     OCR2 =x;   // 取样点指针到比较匹配寄存器
         X_LUT += x_SW; // 新样点指针
}

void port_init(void)
{
PORTB = 0xFF;
DDRB  = 0xFF;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0xFF;
DDRD  = 0xFB;
}

//call this routine to initialise all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x00;
port_init();
adc_init();
  } //timer interrupt sources
//re-enable interrupts
//all peripherals are now initialised

void adc_init(void)
{
ADCSR = 0x00; //disable adc
ACSR  = 0x80; //关闭模拟比较器)
//SFIOR = 0x10; //高速转换
//ACSR  =(1<<ACD);//关闭模拟比较器
ADCSRA = 0x81;  //单次转换模式,转换使能,中断不使能,时钟分频为1
ADMUX = 0xc3;  //select adc input AD3  右对齐
}

我这里的样本表是两个正半波型,为了后续的与或运算服务!其实是256个样本表,不是128!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-22 22:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表