在固定快速PWM模式下,因引入变量的传递而使频率改变的问题(急,求救,马老师)
马老师您好!好不容易找到这个网站,感觉好象是找到救星了,希望您能够给我指点一二,在下不胜感激!
我的问题是这样的,我做的是用ATmega8控制spwm波形,频率保持不变,但要求对幅值进行调整,调整办法是通过匹配值乘或除一个系数.我的部分程序是这样的:
#include <iom8v.h>
#include <macros.h>
#pragma data:code
// 128点正弦波样本表
const unsigned int auc_SinParam = {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)/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)/volt+0.5));改成OCR2=(int)(auc_SinParam)/volt);频率竟然改变了,真的很奇怪,不就把赋了个变量么?问题怎么会这么严重,难道非要写成
OCR2=auc_SinParam;才对吗,哪个volt是AD采样值,必须的用.
救救我吧,马老师! 在我的讲义中已经明确的说明一个原则:中断服务程序应尽可能的短。
你的中断中使用了 OCR2=(int)((float)((auc_SinParam)/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个? 谢谢马老师的指教,真没想到这么快能够得到马老师的回复,感谢您百忙之中热心的抽出时间来看我的程序,还对我的问题进行了耐心的分析和详解,真是万分感谢!您对该程序提出的问题一针见血!按照您的建议,我把浮点运算放在主程序里面了,情况大为改观,但又出现的一个新问题,就是AD 转换时间不够的问题,把AD转换程序层层细分,出现的竟然是一个不变的方波,真是让我郁闷之及!这是我改过的全程序,特向马老师请教:
#include <iom8v.h>
#include <macros.h>
#pragma data:code
// 128点正弦波样本表
const unsigned int auc_SinParam = {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)*1000000/volt)+500)/1000);顺便提一个问题,浮点运算转整型运算
为什么会不行?
x = (int)((float)(auc_SinParam)/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!
页:
[1]