基于SPI2M采样速率ADC信号处理经验分享--滤波算法、精度补偿技术(源程序,调试通过!
[复制链接]
/********************************************************************************** 作者: keyong chen 时间: May. 2009 文件: prg.c 硬件: ADuC7021,ADS1675、DAC9881、RS485
开发环境:Keil C for ARM 描述: 软件部分设计重点而且难点有以下几点: 1、采用软件Σ-Δ技术提高现有DAC的分辨率; 2、双通道DAC实现高精度直流电压源与电流源; 3、实现复杂的数字信号处理算法(如二阶吧特沃斯滤波等); 4、输出信号精度补偿(如温度补偿和常规误差补偿)算法。 *********************************************************************************/ #include<ADuC7021.h> #include <stdio.h> #include <math.h>
#define k1 0.99 // 调节启动信号的幅频
#define k2 0.01 /*==================================================================================================== 变量定义 =====================================================================================================*/ unsigned char txDat2=0x00; // The Tx high byte unsigned char txDat1=0x00; // The Tx mid byte unsigned char txDat0=0x00; // The Tx low byte unsigned char rxDat2=0x00; // The Rx high byte unsigned char rxDat1=0x00; // The Rx mid byte unsigned char rxDat0=0x00; // The Rx low byte long rxDat=0x00; // The Rx full byte unsigned int txDat=0x00; // The Tx full byte long sum1=0x00; long val=0x00,sum3=0x00; double val1=0.0;sum2=0.0; long value_buf1[2]={0x00}; unsigned char value_buf2[3]={0x00};
int i=0,j=0,num=1,empty=1,count; /*==================================================================================================== Main Program =====================================================================================================*/ int main (void) {
SysClkInit(); // CPU时钟初始化
REFCON=0x01; // 内部参考电源2.5V连接到VREF引脚输出
GP1CON=0x02220011; // 定义P1.6 ,P1.5and P1.4 工作在 SPI 模式,设置P1.0 和 P1.1分别为 tx & rx,P1.2为RS-485切换控制信号 GP1DAT=0x84840000; // 定义P1.7(DACS)和P1.2为输出 GP2DAT=0x01010000; // 定义P2.0(DACS)为输出,控制ADCNV GP0DAT=0xA0A00000; // 定义P0.5和P0.7(ADCS)为输出,分别控制DAC复位和ADC的/CS // GP0SET=0x00200000; // P0.5置高,上电复位DAC9881 // Delay(20); // GP0CLR=0x00200000; // Delay(20); // GP0SET=0x00200000; // Delay(20); GP1SET=0x00040000; // P1.2置高,使能RS-485 通讯,切换为发送状态 // SPICON=0x1047; // 定义SPI为主机模式 SPIDIV=0x01; // 设置 SPI 时钟,分频公式:40960000/(2x(1+SPIDIV))
// Setting up UART at 115200bps (CD=0,DL=1) COMCON0=0x80; // 设置分频系数寄存器访问设置位(DLAB),使能访问COMDIV0和COMDIV1 COMDIV0=0x0B; // 设置DIV0和DIV1,计算分频数DL值=1 COMDIV1=0x00; COMCON0=0x07; // 使能访问COMRX和COMTX,数据长度为8位,使用2位停止位 COMDIV2=0x883E; // 41.78MHz/(16*2*2^CD*DL*(M+N/2048)) // CD=0 DL=0B=11 // 115.2Kbps M+N/2048 =1.0303 M=1, N=62=0x3EH=000 0011 1110 // comdiv2=0x883E // DAC configuration DAC1CON=0x13; // 配置DAC // 范围在0~AVdd/AGND // 时钟下降沿时更新DAC1 DAC1DAT=0x08000000; // start from midscale
SysInit(); // 系统初始化
while(1) { SPICON=0x00; SPICON=0x47; // 使能 SPI
GP2SET=0x00010000; // P2.0置高(ADCNV) // Delay(0); // 延时时间必须大于62.5ns GP2CLR=0x00010000; // ADCNV 置低,开始转换数据
delay(21); // 延时时间必须大于5.55us /* __asm { nop; nop; nop; } */ GP0CLR=0x00800000; // 将/CS(P0.7)置低,开始发送数据 SPITX=0x00; // 写入SPI寄存器以启动一次数据发送 while(!(SPISTA & 0x08)) ; // while((SPISTA & 0x10) != 0x10); // wait for data in the RX MMR // Delay(1); rxDat2=SPIRX;
SPITX=0x00; // 写入SPI寄存器以启动一次数据发送 while(!(SPISTA & 0x08)) ; // while((SPISTA & 0x10) != 0x10); // wait for data in the RX MMR // Delay(1); rxDat1=SPIRX;
SPITX=0x00; // 写入SPI寄存器以启动一次数据发送 while(!(SPISTA & 0x08)) ; // while((SPISTA & 0x10) != 0x10); // wait for data in the RX MMR // Delay(1); rxDat0=SPIRX;
GP0SET=0x00800000; rxDat=(((rxDat2 & 0xFF)<<16)+((rxDat1 & 0xFF)<<8)+(rxDat0 & 0xFF)); // rxDat = 0x7FFFFF; if(rxDat>0x7FFFFF) // 计算公式为:txDat = rxDat/2+2.5 { rxDat=-(0xFFFFFF-rxDat+1); // txDat=0x20000-val*0.015625; // txDat=0x20000-val*0.009375; // txDat=0x20000-val*0.013375; } value_buf1 = rxDat; // 控制系统稳定时间和超调量,延时1.2us if (i == 1) {sum1 = (k1*value_buf1[1]+k2*sum1);i = 0;} else {sum1 = (k1*value_buf1[0]+k2*sum1);i = 1;}
val=sum1>>6; txDat=0x20000+val; // 发送数据给18位DA
// val1=sum1*0.015625-val; // txDat12=0x800+val1*1638.4; // 发送数据给12位DA,延迟9.8us /* val1=rxDat*0.015625; val1=modf(val1,&val); txDat=0x20000+val; // 发送数据给18位DA txDat12=0x800+val1*1638.4; // 发送数据给12位DA,延迟9.8us */ SPICON=0x00; SPICON=0x1043; // Configure SPI as Master, clock idles high //configure the high byte to be sent txDat2=(txDat>>16); // Copy the first 4 bits of data into the last 4 bits of txDat2 txDat-=(txDat2<<16);
//configure the mid byte to be sent txDat1=(txDat>>8); // Copy the first 4 bits of data into the last 4 bits of txDat1 txDat-=(txDat1<<8); //configure the low byte to be sent txDat0=(txDat); // Copy the last 4 bits of data into the first 4 bits of txDat0 // txDat0&=0xf0; // Insure the first 4 bits of data in txDat0 are empty
//send the data // Delay 50ns,one clock is 0.28us GP1CLR=0x00800000; // Pull DACS Low SPITX=txDat2; // while((SPISTA & 0x02)!=0x02); // while(SPISTA & 0x01); __asm { nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; }
SPITX=txDat1; // while((SPISTA & 0x02)!=0x02); // while(SPISTA & 0x01); __asm { nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; } SPITX=txDat0; // while((SPISTA & 0x02)!=0x02); // while(SPISTA & 0x01); delay(1); GP1SET=0x00800000; // Pull DACS High // DAC1DAT=(txDat12<<16); // 内部DAC输出,9.8us
if(empty==1) { if(j==0) { value_buf2[0]=rxDat2; value_buf2[1]=rxDat1; value_buf2[2]=rxDat0; } else { sum3=sum2/(j-1); value_buf2[0]=(sum3>>16);sum3-=(value_buf2[0]<<16); value_buf2[1]=(sum3>>8 );sum3-=(value_buf2[1]<<8 ); value_buf2[2]=(sum3); j=0; sum2=0.0; } empty=0;
} switch(num) // 二阶博特沃斯滤波,延时24us,输出频率为80Hz { case 75:COMTX=0x0D;break;
case 150:COMTX=value_buf2[0];break;
case 225:COMTX=value_buf2[1];break;
case 300:COMTX=value_buf2[2];empty=1;num=0;break; default :sum2+=sum1;j++; }
num++;
} return 0; }
/*==================================================================================================== ADCpoweron =====================================================================================================*/ void ADCpoweron(int time) { ADCCON=0x20; // 启动ADC while(time>=0) // 等待ADC完全启动 time--; }
void SysClkInit(void) { PLLKEY1=0xAA; PLLCON=0x01; //PLL配置 PLLKEY2=0x55; POWKEY1=0x01; POWCON=0x00; //CPU时钟配置为41.78MHz POWKEY2=0xF4; }
void SysInit(void) { SPICON=0x1043; // Configure SPI as Master, clock idles high
//send the data // Delay 50ns,one clock is 0.28us GP1CLR=0x00800000; // Pull DACS Low }
void delay (int length) { while(length>=0) length--; }
/*==================================================================================================== End Of File =====================================================================================================*/
|