//*********************************************************************************//
//正弦信号发生;
//实现单片机: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();
}
}
用户1547295 2007-3-14 22:44