ADC精度测试

卟留遗憾灬 2020-07-10 13:39:01 2632

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数据

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 1 2 评论 打赏
评论
1个
内容存在敏感词
手气红包
  • 雨林霖 2020-07-10 16:58:13
    回复

    可以加点代码说明吗?

相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
卟留遗憾灬
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区