首页 > 技术知识 > 正文

define USE_FLOAT 1 define PRINT_STATISTICS 1 define PRINT_SAMPLES 0 define PRINT_VOLTAGES 0

//—————————————————————————– // Includes //—————————————————————————–

include // SFR declarations include // Standard I/O Library include

//—————————————————————————– // 16-bit SFR Definitions for F35x //—————————————————————————–

sfr16 DP = 0x82; // data pointer sfr16 TMR3RL = 0x92; // Timer3 reload value sfr16 TMR3 = 0x94; // Timer3 counter sfr16 ADC0DEC = 0x9a; sfr16 TMR2RL = 0xca; // Timer2 reload value sfr16 TMR2 = 0xcc; // Timer2 counter sfr16 PCA0CP0 = 0xe9; // PCA0 Module 1 Capture/Compare sfr16 PCA0CP1 = 0xeb; // PCA0 Module 2 Capture/Compare sfr16 PCA0CP2 = 0xed; // PCA0 Module 2 Capture/Compare sfr16 PCA0 = 0xf9; // PCA0 counter

//—————————————————————————– // Global CONSTANTS //—————————————————————————–

define SYSCLK 49000000 // SYSCLK frequency (Hz) define BAUDRATE 115200 // UART0 Baudrate (bps) define MDCLK 2457600 // Modulator Clock (Hz) define OWR 10 // desired Output Word Rate in Hz define VREF 250L // External VREF (x 10^-2 V)

/*

define VREF 243UL // Internal VREF (x 10^-2 V)

*/

sbit LED0 = P0^6; // LED0=1 means ON sbit LED1 = P0^7; // LED1=1 means ON sbit SW2 = P1^0; // SW2=0 means switch pressed

//—————————————————————————– // Function PROTOTYPES //—————————————————————————– void SYSCLK_Init (void); void PORT_Init (void); void ADC0_Init (void); void IDA0_Init (void); void UART0_Init (void);

//—————————————————————————– // MAIN Routine //—————————————————————————– void main (void) {

volatile long ADC_OutputVal=0; // Concatenated ADC output value long xdata sample_array[64]; unsigned i; long min; long max; long l_temp; long l_average; long l_variance; long l_owr;

// float xdata tf[5]; // float *p=tf; // int c=0; // float d=0;

if (USE_FLOAT == 1)

float temp; float average; float variance; float stdev; float owr;

endif // USE_FLOAT

// disable watchdog timer PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer // enable)

SYSCLK_Init(); // Initialize system clock to 49 MHz

PORT_Init(); // Initialize crossbar and GPIO

LED0 = 0; LED1 = 0;

ADC0_Init(); // Initialize ADC0

UART0_Init(); // Initialize UART0

EA = 1; // enable global interrupts

printf(“\nMeasurements using the 24-bit ADC in C8051F350\n”); printf(“\nCalibrating …\n”);

EIE1 &= ~0x08; // Disable ADC0 interrupts

ADC0MD |= 0x01; // Init Internal Full cal

while (!AD0CALC); // Wait for calibration complete

ADC0MD &= ~0x07; // clear bits (put ADC0 in IDLE // mode)

printf(“Calibration complete\n\n”);

AD0INT = 0; // clear pending sample indication ADC0MD = 0x83; // Start continuous conversions

while(1) {

// capture 128 samples printf (“Collecting 64 samples…\n”); LED0 = 1; for (i = 0; i < 64; i++) { while(!AD0INT); // wait till conversion complete AD0INT = 0; // clear AD0 interrupt flag // concatenate ADC0 data bytes to form the 24-bit value ADC_OutputVal = (char)ADC0H; ADC_OutputVal <<= 16; ADC_OutputVal += (long)ADC0L + ((long)ADC0M << 8); sample_array[i] = ADC_OutputVal; } LED0 = 0; // calculate mean, min, and max if (USE_FLOAT == 1) average = 0; endif // USE_FLOAT l_average = 0L; min = 0x7fffffffL; max = 0x80000000L; for (i = 0; i < 64; i++) { ADC_OutputVal = sample_array[i]; l_average = l_average + ADC_OutputVal; if (ADC_OutputVal < min) min = ADC_OutputVal; if (ADC_OutputVal > max) max = ADC_OutputVal; if (USE_FLOAT == 1) average = average + (float) ADC_OutputVal; endif // USE_FLOAT } l_average = l_average / 64; if (USE_FLOAT == 1) average = average / 64.0; endif // USE_FLOAT // calculate variance l_variance = 0L; if (USE_FLOAT == 1) variance = 0; endif // USE_FLOAT for (i = 0; i < 64; i++) { ADC_OutputVal = sample_array[i]; l_temp = ADC_OutputVal; l_temp = l_temp – l_average; l_temp = l_temp * l_temp; l_variance = l_variance + l_temp; if (USE_FLOAT == 1) temp = (float) ADC_OutputVal; temp = temp – average; temp = temp * temp; variance = variance + temp; endif // USE_FLOAT } l_variance = l_variance / 63; // unbiased variance l_owr = (long) SYSCLK / (long)(ADC0CLK + 1); l_owr = (long) l_owr / (long)(ADC0DEC + 1); l_owr = (long) l_owr / (long)64; if (USE_FLOAT == 1) variance = variance / 63; // unbiased variance stdev = sqrt (variance); owr = SYSCLK /(ADC0CLK + 1); owr = owr / (ADC0DEC + 1); owr = owr / 64; endif // USE_FLOAT // print statistics if (PRINT_STATISTICS == 1) LED1 = 1; printf (“SYSCLK = %lu\n”, (unsigned long) SYSCLK); printf (“ADC0CLK = 0x%02x\n”, (unsigned) ADC0CLK); printf (“ADC0DEC = 0x%02x%02x\n”, (unsigned) ADC0DECH, (unsigned) ADC0DECL); printf (“min = %ld\n”, min); printf (“max = %ld\n”, max); if (USE_FLOAT == 1)

// *p++=average; // c++; // printf(“c=%d \n”,c); // if(c==5) // { // for(c=0;c<5;c++) // { // d+=tf[c]; // } //

// printf(“****

“); // for(c=0;c<10;c++) // printf(” \n”); // printf(“0V输入:%.8f”,d/5.0/8388607*2.5004-0.000689+0.001955);

// for(c=0;c<10;c++) // printf(” \n”); // printf(“****“); // p=tf; // c=0; // } printf (“average = %.6f\n”, average); printf (“real = %.6f\n”, average/8388607*2.5004-0.000689+0.001855); printf (“stdev = %.5f\n”, stdev); printf (“variance = %.5f\n”, variance); printf (“OWR = %.5f Hz\n”, owr); else printf (“average = %ld\n”, l_average); printf (“variance = %ld\n”, l_variance); printf (“OWR = %ld Hz\n”, l_owr); endif // USE_FLOAT printf (“\n”); LED1 = 0; endif // PRINT_STATISTICS // print samples if (PRINT_SAMPLES == 1) for (i = 0; i < 64; i++) { ADC_OutputVal = sample_array[i]; printf (“%6ld\n”, ADC_OutputVal);

// printf (“0x%06lx\n”, ADC_OutputVal);

} endif // PRINT_SAMPLES // print voltages if (PRINT_VOLTAGES == 1) for (i = 0; i < 64; i++) { long Calculated_uV; // Measured voltage in uV ADC_OutputVal = sample_array[i]; // Caculate measured voltage in uV: // V (in uV) = ADCcode * VREF * 10 / 2^24 // Note1: Multiplying by 10 because VREF is in 10^-2 V // Note2: Shifting by 4 before multiplying 10 to prevent overflow // of unsigned long variable (32 bits) Calculated_uV = ((((((ADC_OutputVal*2*VREF)/16)*10)/1024)*1000)/1024); // Output result: printf(“ADC Output Code = %6ld [Calculated voltage = %+07ld uV]\n”, ADC_OutputVal, Calculated_uV); } endif // PRINT_VOLTAGES

}// end while(1) }

//—————————————————————————– // SYSCLK_Init //—————————————————————————– // // This routine initializes the system clock to use the internal 24.5MHz // oscillator as its clock source, with x 2 multiply for // 49 MHz operation. Also enables missing clock detector reset. // void SYSCLK_Init (void) { unsigned i;

OSCICN = 0x80; // enable intosc CLKSEL = 0x00; // select intosc as sysclk source

// INTOSC configure

OSCICN = 0x83;

// PLL configure

CLKMUL = 0x00; // Reset Clock Multiplier

CLKMUL &= ~0x03; // select INTOSC / 2 as PLL source

CLKMUL |= 0x80; // Enable 4x Multipler (MULEN = 1)

for (i = 0; i < 125; i++); // Delay for at least 5us

CLKMUL |= 0xC0; // Initialize Multiplier

while (!(CLKMUL & 0x20)); // Poll for Multiply Ready

// SYSCLK configure

VDM0CN = 0x80; // enable VDD monitor RSTSRC = 0x06; // enable missing clock detector // and VDD monitor reset sources CLKSEL = 0x02; // select PLL as clock source }

//—————————————————————————– // PORT_Init //—————————————————————————– // // Configure the Crossbar and GPIO ports. // P0.4 – TX0 (push-pull) // P0.5 – RX0 // P0.6 – LED1 (push-pull) // P0.7 – LED2 (push-pull) // void PORT_Init (void) { XBR0 = 0x01; // UART0 Selected XBR1 = 0x40; // Enable crossbar and weak pull-ups P0MDOUT |= 0xD0; // TX, LEDs = Push-pull }

//—————————————————————————– // ADC0_Init extVREF Bipolar AIN0.1-AIN0.0 //—————————————————————————– // // This function initializes the ADC to measure across AIN0.1 and AIN0.0 // on the Target Board (Differential measurements, Bipolar codes) // void ADC0_Init (void) { unsigned ADC0_decimation;

REF0CN &= ~0x01; // disable internal vref / REF0CN |= 0x01; // (enable if using internal vref) / ADC0CN = 0x10; // Bipolar output codes, GAIN=1

/ ADC0CF = 0x00; // interrupts upon SINC3 filter output // and uses internal VREF / ADC0CF = 0x04; // interrupts upon SINC3 filter output // and uses external VREF // Generate MDCLK for modulator. // Ideally MDCLK = 2.4576 ADC0CLK = (SYSCLK/MDCLK)-1; // Ideally, MDCLK = 2.4576 MHz // ADC0DEC = 0x7FF; // set slowest OWR // program decimation rate for desired OWR ADC0_decimation = (unsigned long) SYSCLK/ (unsigned long) OWR / (unsigned long) (ADC0CLK+1)/(unsigned long)128; ADC0_decimation–; ADC0DEC = ADC0_decimation; /****/ ADC0BUF = 0x00; // Turn off Input Buffers // Select Mux inputs

// ADC0MUX = 0x08; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.0 // AIN- => AGND // ADC0MUX = 0x00; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.0 // AIN- => AIN0.0 // ADC0MUX = 0x01; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.0 // AIN- => AIN0.1 // ADC0MUX = 0x10; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.1 // AIN- => AIN0.0 ADC0MUX = 0x32; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.3 // AIN- => AIN0.2 // ADC0MUX = 0x54; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.5 // AIN- => AIN0.4 // ADC0MUX = 0x76; // Input pin selection: // Setup for differential measurements // AIN+ => AIN0.7 // AIN- => AIN0.6 // ADC0MUX = 0xff; // Input pin selection: // Setup for differential measurements // AIN+ => Temp+ // AIN- => Temp- // ADC0MUX = 0x88; // Input pin selection: // Setup for differential measurements // AIN+ => AGND // AIN- => AGND ADC0MD = 0x80; // Enable the ADC0 (IDLE Mode) }

//—————————————————————————– // UART0_Init //—————————————————————————– // // Configure the UART0 using Timer1, for and 8-N-1. // void UART0_Init (void) { SCON0 = 0x10; // 8-bit variable bit rate // level of STOP bit is ignored // RX enabled // ninth bits are zeros // clear RI0 and TI0 bits if (SYSCLK/BAUDRATE/2/256 < 1) { TH1 = -(SYSCLK/BAUDRATE/2); CKCON |= 0x08; // T1M = 1; SCA1:0 = xx } else if (SYSCLK/BAUDRATE/2/256 < 4) { TH1 = -(SYSCLK/BAUDRATE/2/4); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01 CKCON |= 0x01; } else if (SYSCLK/BAUDRATE/2/256 < 12) { TH1 = -(SYSCLK/BAUDRATE/2/12); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00 } else { TH1 = -(SYSCLK/BAUDRATE/2/48); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10 CKCON |= 0x02; } TL1 = TH1; // init Timer1 TMOD &= ~0xf0; // TMOD: timer 1 in 8-bit autoreload TMOD |= 0x20; TR1 = 1; // START Timer1 TI0 = 1; // Indicate TX0 ready } /*****以上是官方提供的,部分改****/ 大体步骤是配置好串口,时钟分频,引脚和ADC基本设置,然后就是处理采集数据的处理,包括对结果进行校准和多次采样取平均值来提高精度。 但实际测量后还是发现精度达不到24位的最低要求,其中一定原因是因为外部电压在小幅度变化,会严重影响高精度测试,于是我采集0v输入时adc采集到的大量数据,取平均值,然后减去这个值,还是发现数据达不到精度,经过大量观察数据,发现输入电压和采集电压的差值能到千分位,于是加上这个千分位差值,发现经过处理后的数据千分位能达到,但如果想要进一步达到更高的精度那就必须得让外部电压稳定在某一固定的值,然后通过大量的数据采集来获取更高精度的偏移量来修正。ADC精度测试

猜你喜欢