原创 单片机的正弦信号产生中改变正弦信号频率时仍旧保持采样频率的算法

2006-9-22 08:37 5597 11 8 分类: 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条评论)

登录后参与讨论

用户29289 2006-9-26 19:18

试了一下,不错,
数字信号处理的方法,
相关推荐阅读
mubo_996067292 2010-11-07 23:09
继续升级,CTE1.3
新增:rms2vpp <rms value> -- sine signal amplitude convertvpp2rms <vpp value> -- sine signa...
mubo_996067292 2010-10-23 02:10
关于天灾
    胡公,温公,世之英杰。而其享国之日,天灾频现。自胡公七年(西历二千零八年)至于今日,三年之中,凡日蚀二,大地震二,大旱一。    方今之日,中国日强,使夷狄不敢正视,此千秋之功也。而剥其表视其...
mubo_996067292 2010-09-03 00:27
继续升级:mil-mm,db-倍数,m/s-km/h,电阻并联转换计算器
新增:    增加了电阻并联计算。另:   所有的转换和计算,输入数字的时候都不能有数字之外的字符。...
mubo_996067292 2010-08-27 00:47
mil-mm,db-倍数,m/s-km/h转换计算器
几组常用的转换。...
mubo_996067292 2010-08-03 22:59
mm和mil转换
命令行模式,四个命令:help显示帮助信息quit 退出程序mil2mm <mil值>  mil转换为mmmm2mil <mm值>  mm转换为mil 直接找了个朋友在单片机上...
mubo_996067292 2010-03-09 22:31
雨夜弹琴
雨落深圳寒,加班夜归晚。坐闻窗飒飒,发性抚琴弹。...
EE直播间
更多
我要评论
1
11
关闭 站长推荐上一条 /3 下一条