guxiangdeyun 发表于 2007-10-19 16:21:08

ATmega8中关于SPWM波形赋值匹配的时间 和AD转换时间相矛盾的问题

谢谢马老师的指教,真没想到这么快能够得到马老师的回复,感谢您百忙之中热心的抽出时间来看我的程序,还对我的问题进行了耐心的分析和详解,真是万分感谢!您对该程序提出的问题一针见血!按照您的建议,我把浮点运算放在主程序里面了,情况大为改观,但又出现的一个新问题,就是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!

machao 发表于 2007-10-19 20:47:16

实在抱歉,我没时间仔细分析你的程序。

从我的理解上讲,时间上应该没问题的,主要是你系统时间的分配要合理。

没有严格的实时系统,也就是说,任何系统从输入,到根据输入到输出的变化都是有时延的。只要你的时延时间能够满足控制的需要就可以的。电子的响应是在us级的,而机械的响应在ms甚至在s级的,应该能行。


简单看了你的程序,AD应该采用中断方式读数据。当然,T2的中断优先级应该是最高,AD的中断要使用中断嵌套的结构。

关于浮点变整形的问题,我只能提供你的例子:

比如知道单价,计算总价格。通常单位为元,1.56元 * 3 = 4.68元。采用整形数,内部使用INT或long int。把单位换成15600(放大10000倍),循环加上3次,结果为46800。显示时,只显示前3位,并把小数点在右起第2位前,你外边看还不是以“元”为单位吗?实际内部已经精确到了1/10厘了。乘和除采用整行法也比浮点快,因为少掉了转换时间。

最后是你的一句语句:

volt=(float)(temp/1024)/1000;

temp 整型,除以1024 为整除,结果也是整数,已经将小数点后面的东西丢掉了,再转换成浮点已经没有用了。正确的写法是:
volt = ((float)temp / 1024) / 1000

guxiangdeyun 发表于 2007-10-19 21:00:22

我的一个周期的SPWM的周期上62us,而AD转换的时间为65us-260us之间,这个时间是肯定来不及的,所以我把AD转换的程序细分来处理

guxiangdeyun 发表于 2007-10-19 21:06:04

我刚开始时,是用AD中断嵌套的,可是,AD中断一允许,就把匹配值给屏蔽了,所以只能用查询了

machao 发表于 2007-10-19 23:42:24

PWM的周期为62us,,那么相当于16K的正弦波了。不知道你的系统功能是什么,如果工业控制,一般不需要这么高的频率。

假定一个周期有128个点构成,那么每隔 62/128 = 0.5us,T2就要中断一次。系统使用16M时,0.5us只能执行8条单周期的指令!!!

那么你的AVR什么也不做,也输出不了正确的PWM波了。因为仅仅是T2的中断服务8条指令也远不够的。除了转移、还要断点保护与恢复、现场的保护和恢复等。

按照你提供的数据,你的设计原则上是错误的,根本不能实现。

先把基本的东西弄清楚。

如果你要做专业的DDS,请放弃使用AVR。AVR的PWM控制主要应用于工业的控制,频率通常在几十到几百Hz。

guxiangdeyun 发表于 2007-10-21 14:49:14

马老师,你误会了我的意思,这样的,我spwm的脉冲周期是62us,也就是16K,既4M/265=16K,由于建立了256个点的样本表,所以16K/256=60Hz,所以输出的正弦波的频率是60hz,也就是说没从样本表中取一个样本值赋值给匹配寄存器,即产生一个SPWM的脉冲就要62us,而AD转换要65us-250us ,所以我尽量在每个脉冲里干其他事情的时间缩短,因此把 AD读取层层细分,可好象是行不通的.
   现考虑用9位固定快速PWM模式,这样每个脉冲的时间是4M/512=8K,即124us,不知道这样AD读取来不来得及,而且,9位固定快速PWM模式,的正弦样建立好象有点困难,我取130个样本点,那可以用
                511*sin(2*pi*x/129)  x属于(0-129)
可这样运行起来从波形上来看好象不对

guxiangdeyun 发表于 2007-10-21 14:50:23

我是做电源这块,用于逆变的控制

guxiangdeyun 发表于 2007-10-21 16:30:47

511*sin(2*pi*x/129)  x属于(0-129)
由于输出两个正半波,所以加了绝对值

machao 发表于 2007-10-21 20:41:29

如果你的系统并不需要每隔65us必须做一次AD转换的话,合理的利用中断嵌套和分配时间的话,应该是可以的,

我不明白你所讲的“把AD读取层层细分”是什么意思。一次AD的转换是需要65us,但不需要专用CPU的时间。CPU只是发一个启动指令,然后就是读AD的值了,读AD值也仅需要几条指令(不包括中断中其它的处理)。

你要评估从输入(AD检测)变化到输出响应的最大的允许滞后时间。我估计在一般的应用中,输入变化到输出的响应时间在10ms范围中已经能够满足使用了,(因为你决不可能做到实时的响应,肯定有滞后时间的,只不过是多少能满足实际的需要)。

注意:通常条件下,AVR的ADC逐次比较电路要达到转换的最大精度,需要一个50K~200KHz的采样时钟。一次正常的ADC转换过程需要13个采样时钟,假定ADC采样时钟为200KHz,那么最高的采样速率为200K/13=15.384K。因此根据采样定理,理论上被测模拟信号的最高频率为7.7K!因此如果你的AD是对60HZ的信号采样的话,是不需要每隔65us做一次AD的。

guxiangdeyun 发表于 2007-10-22 17:39:57

马老师,对于这个问题,主要是我对AD转换还有好些地方没有弄懂,关键的几个问题是:
       1、如果在AD转换过程中(在查询读取方式中),突然发生计数器溢出中断,执行中断服务程序中间,AD应该还在继续转换吧?返回被中断处时,继续读取AD是否没有影响?
      2、我做的工作是这样的,要求输出120hz的正半正弦波,因为我的一个SPWM脉冲波形的频率为16khz,也就是8位计数器从0计数到FF 的溢出时间为62us,每过256个这样的脉冲,我要AD采样一次,AD的预分频为32,4M/32hz对应一个AD时钟周期就是8us,一次常规转换,为116us.

machao 发表于 2007-10-22 18:16:09

如果使用单次转换,一旦AD启动后,“转换过程由ADC硬件完成,与其它无关”。当转换完成,置ADC完成标志,数据保留在ADC的数据寄存器中。如果不使用ADC中断,你可以在任何时间询问ADC标志位,读取转换完成的数据。请仔细看器件手册。

正弦波的AD采样有问题的。一个周期或半周期的正弦波,你只采一点,能表示这个正弦波的什么量?你要得到正弦波的最大幅度值,还是平均值。

你对这些基础的原理东西都没明白,怎么能正确的设计系统?

guxiangdeyun 发表于 2007-10-23 10:28:03

呵呵,谢谢马老师批评指正,应您的指导,我的问题解决了,问题出在AD没有预分频上面,现在行了,另外我的 AD不是去采样正弦波的,采进来的是个直流量,在0-2v 左右,来直输出电压的反馈

maiwa 发表于 2008-1-23 23:19:25

学习了,原来这样啊.正在用AVR做充电控制,还担心如果在AD转换过程中,发生定时器溢出中断会对转换结果产生影响呢.现在看来应该是没影响了

ywl0409 发表于 2008-6-5 09:22:34

收藏

raosibin 发表于 2009-12-16 22:05:59

mark

huangning 发表于 2010-2-3 10:09:07

收藏了。。。

crazy_b-boy 发表于 2010-5-22 21:51:05

回复【6楼】guxiangdeyun
-----------------------------------------------------------------------

我也在做逆变20-100hz可变
帮忙讲解一下读取键盘以后 怎么改变频率比较好 改变定时器初始值吗

dabuyang 发表于 2010-5-26 19:31:40

收藏
页: [1]
查看完整版本: ATmega8中关于SPWM波形赋值匹配的时间 和AD转换时间相矛盾的问题