原创 测频算法

2006-9-25 08:37 1991 7 5 分类: MCU/ 嵌入式
单片机的正弦信号产生中改变正弦信号频率时仍旧保持采样频率的算法


//*********************************************************************************//
//正弦信号发生;


//实现单片机:SPCE061A;


//用61板即可直接下载使用;
//可按固定频率步进(在程序中步进值为f0,改变f0可改变步进值);
//可按固定电压进行幅度步进(在程序中值为A0,改变A0可改变幅度步进值);
//取点的采样频率fs为固定值32kHz,这样可以使输出端接的模拟滤波器的设计变得简单;
//61板,P_DAC1输出,KEY1:调整锁(按一次KEY1,可以调整频率,再按一次,可以调整幅度,再按一次,不能调整);KEY2:上调;KEY3:下调;
//由有限字长效应,频率不会很准确,但误差很小;
//!!!!注意:工作在最高频率下,并且要求时钟一直这么工作,所以要把系统时钟设置为强振模式(*osc = 0x98)
//!!!!BUG1:由于计算级数很少(只算了两级),低频(50Hz以下)时相对误差大;
//!!!!BUG2:由于按键调频率时要关中断,所以,在每次频率改变时信号输出会有一段时间的中止(计算x2,k和对x赋0的时间);
//实现算法:递归法;
//差分方程:y(n)=k*y(n-1)-y(n-2);
//k=2*cos(omiga)-------omiga:数字频率,omiga=2*pi*f0/fs;
//初始y(n-2):y(n-2)=-A*sin(omiga);
//**********************************************************************************//


#define pi 3.14
#define f0 5
unsigned int *p0=(unsigned int *)(0x7000);
unsigned int *p0d=(unsigned int *)(0x7002);
unsigned int *p0a=(unsigned int *)(0x7003);
unsigned int *oscu=(unsigned int *)(0x7013);
unsigned int *t0=(unsigned int *)(0x700a);
unsigned int *t0u=(unsigned int *)(0x700b);
unsigned int *intu=(unsigned int *)(0x7010);
unsigned int *intc=(unsigned int *)(0x7011);
unsigned int *dau=(unsigned int *)(0x702a);
unsigned int *da0=(unsigned int *)(0x7017);
unsigned int *da1=(unsigned int *)(0x7016);
unsigned int *wdogc=(unsigned int *)(0x7012);



unsigned int key_num,key_mode,key_have,key_plus,fast;
unsigned int f=400;
unsigned int fs=42000;
unsigned int Fs;
int Am=20000;
unsigned int A0=200;
double omiga;
long x;
long x1;
unsigned int k;
long x2;


unsigned int Init_MCU()
{
 *p0d=0;
 *p0a=0;
 *p0=0;
 key_num=0;
 key_mode=0;
 key_have=0;
 key_plus=0;
 fast=0;
 __asm("int off");
 *oscu=0x98;    //设置采样频率的中断
 *t0u=0x30;
 Fs=fs/1000;
 *t0=65535-24576/Fs;
 *intu=0x1000;
 //初始输出频率定为f;
 fs=Fs*1000;
 omiga=2*pi*f/fs;
 x2=(int)(-Am*omiga);   //这里本来是调用正弦函数的,但函数运算的级数太多,这里因为omiga很小,所以sin(omiga)几乎等于omiga,利用这个,把正弦值直接用omiga值代替;
 k=(int)(32768-omiga*omiga*16384); //这里本来是调用余弦函数,同上面,级数不用太多,用cos(omiga)约等于1-omiga*omiga/2;
 x1=0;
 __asm("irq on");
}


//定时器中断,实现递推过程;
void IRQ1(void) __attribute__ ((ISR));
void IRQ1(void)
{
  x=((k*x1)>>14)-x2;
  x2=x1;
  x1=x;
  *da0=x1+32000;
  *da1=*da0;
  *intc=0x1000;
}  
//扫描键盘;
void Scan_key()

 if(*p0==0)
 {
  key_plus=0;
  key_num=0;
  key_have=0;
 }
 if(*p0==1)
 {
  if(key_have==0)
  {
   if(key_num<1000)
    key_num++;
   else
   {
    key_num=0;
    key_have=1;
    if(key_mode<2)
     key_mode+=1;
    else
     key_mode=0;
   }
  }
 
 }
 if(*p0==2)
 {
  if(key_num<1000)
   key_num++;
  else
  {
   key_num=0;
   if(key_mode==1)
   {
    key_have=1;
    
   // 频率增加f0Hz
    __asm("int off");
    if(f<(fs/8-f0))
    {
     f+=f0;
     omiga=2*pi*f/fs;
  x2=(int)(-Am*omiga);   //这里本来是调用正弦函数的,但函数运算的级数太多,这里因为omiga很小,所以sin(omiga)几乎等于omiga,利用这个,把正弦值直接用omiga值代替;
  k=(int)(32768-omiga*omiga*16384); //这里本来是调用余弦函数,同上面,级数不用太多,用cos(omiga)约等于1-omiga*omiga/2;
     x1=0;
     __asm("irq on");
    }
    else 
     __asm("irq on");
   }
   if(key_mode==2)
   {
    key_have=1;
    
   // 幅度增加A0
    __asm("int off");
    if(Am<31000-A0)
    {
     Am+=A0;
  x2=(int)(-Am*omiga);
     x1=0;
     __asm("irq on");
    }
    else 
     __asm("irq on");
   }
   
  }
 }
 
 if(*p0==4)
 {
  if(key_num<1000)
   key_num++;
  else
  {
   key_num=0;
   if(key_mode==1)
   {
    key_have=1;
    
   // 频率减小f0Hz
    __asm("int off");
    if(f>f0)
    {
     f-=f0;
     omiga=2*pi*f/fs;
  x2=(int)(-Am*omiga);
  k=(int)(32768-omiga*omiga*16384);
     x1=0;
     __asm("irq on");
    }
    else 
     __asm("irq on");
   }
   if(key_mode==2)
   {
    key_have=1;
    
   // 幅度减小A0
    __asm("int off");
    if(Am>A0)
    {
     Am-=A0;
  x2=(int)(-Am*omiga);
     x1=0;
     __asm("irq on");
    }
    else
     __asm("irq on");
   }
  }
 }
}


int main()
{
 Init_MCU();
 while(1)
 {
  *wdogc=1;
  Scan_key();
 }
}

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户1053025 2006-9-25 16:12

我给您投票啦:D 参加博客大赛了吗?
相关推荐阅读
我要评论
1
7
关闭 站长推荐上一条 /1 下一条