C8051f120内置12位ADC采集不了交流信号

2020-01-30 13:49发布

我用C8051f120内置12位ADC,直流信号可以采集,但采集的交流信号转换为模拟电压却总是等于Vref值,这个是为什么呀?
我是直接将函数发生器的输出(交流叠加直流所有信号为正极性)加到AIN0.0脚的。下面是我的源程序:
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <math.h>
#include "c8051f120.h"
#include "FFT_Code_Tables.h" // Code Tables for FFT routines
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for ‘F12x
//-----------------------------------------------------------------------------
sfr16 DP = 0x82; // data pointer
sfr16 ADC0 = 0xbe; // ADC0 data
sfr16 ADC0GT = 0xc4; // ADC0 greater than window
sfr16 ADC0LT = 0xc6; // ADC0 less than window
sfr16 RCAP2 = 0xca; // Timer2 capture/reload
sfr16 RCAP3 = 0xca; // Timer3 capture/reload
sfr16 RCAP4 = 0xca; // Timer4 capture/reload
sfr16 TMR2 = 0xcc; // Timer2
sfr16 TMR3 = 0xcc; // Timer3
sfr16 TMR4 = 0xcc; // Timer4
sfr16 DAC0 = 0xd2; // DAC0 data
sfr16 DAC1 = 0xd2; // DAC1 data
sfr16 PCA0CP5 = 0xe1; // PCA0 Module 5 capture
sfr16 PCA0CP2 = 0xe9; // PCA0 Module 2 capture
sfr16 PCA0CP3 = 0xeb; // PCA0 Module 3 capture
sfr16 PCA0CP4 = 0xed; // PCA0 Module 4 capture
sfr16 PCA0 = 0xf9; // PCA0 counter
sfr16 PCA0CP0 = 0xfb; // PCA0 Module 0 capture
sfr16 PCA0CP1 = 0xfd; // PCA0 Module 1 capture

//-----------------------------------------------------------------------------
// Global CONSTANTS and Variable Type Definitions
//-----------------------------------------------------------------------------
#define NUM_BITS 16         // Number of Bits in Data
#define DATA_BEGIN 0x0000         // Beginning of XRAM Data
#define SYSCLK 49000000         // Output of PLL derived from
                                        // (INTCLK*2/1)

#define VREF 3.3               //参考电压
#define SAMPLE_RATE 20480                // Sample frequency in Hz
#define RUN_ONCE 1     // Setting to a non-zero value will
                       // cause the program to stop after one
                       // data set.
unsigned int xdata Redata[NUM_FFT];
char xdata data_H[NUM_FFT],data_L[NUM_FFT];
int xdata i;
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void SYSCLK_Init (void);
void PORT_Init (void);
void ADC0_Init (void);
void TIMER3_Init (int counts);
void ADC0_ISR (void);
void delay_us(unsigned int);


unsigned int BinNum;
bit Conversion_Set_Complete; // This indicates when the data has been
                                          // stored, and is ready to be processed
                                           // using the FFT routines



//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main()
{
   int xdata i;
   unsigned int xdata data1[NUM_FFT],data2[NUM_FFT],data3[NUM_FFT];
   float xdata Voltage[NUM_FFT];
   char xdata data_H1[NUM_FFT],data_L1[NUM_FFT];
//disable watchdog timer
WDTCN = 0xde;
WDTCN = 0xad;

SYSCLK_Init();                 // initialize external clock and PLL
PORT_Init ();                 // set up Port I/O
TIMER3_Init (SYSCLK/SAMPLE_RATE);                 // initialize Timer3 to overflow at
                                                // <SAMPLE_RATE>
ADC0_Init ();                 // init ADC0

EA = 1;                 // globally enable interrupts
while (1)
{
ADC_Index = 0;
Conversion_Set_Complete = 0;
EIE2 |= 0x02;                         // enable ADC interrupts

SFRPAGE = LEGACY_PAGE;

while(!Conversion_Set_Complete);

for(i=0;i<=NUM_FFT;i++)
{
data1[i]=Real[i];
data_H1[i] = data_H[i];
data_L1[i] = data_L[i];
data2[i] = data1[i] >> 4;
Voltage[i]=data2[i]/4096.0*VREF;    //计算实际电压
}
   
if (RUN_ONCE)
while(1);

}
} // END MAIN


//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
void SYSCLK_Init (void)                 //49MHz
{
        int i;
    char old_SFRPAGE = SFRPAGE;                 // Store current
    SFRPAGE   = CONFIG_PAGE;
    OSCICN    = 0x83;
    CCH0CN    &= ~0x20;
    SFRPAGE   = LEGACY_PAGE;
    FLSCL     = 0x90;
    SFRPAGE   = CONFIG_PAGE;
    CCH0CN    |= 0x20;
    PLL0CN    |= 0x01;
    PLL0DIV   = 0x01;
    PLL0FLT   = 0x21;
    PLL0MUL   = 0x02;
    for (i = 0; i < 15; i++);  // Wait 5us for initialization
    PLL0CN    |= 0x02;
    while ((PLL0CN & 0x10) == 0);
    CLKSEL    = 0x22;

    SFRPAGE = old_SFRPAGE;                 // restore SFRPAGE
}

void PORT_Init (void)       
{
SFRPAGE   = CONFIG_PAGE;
    XBR2      = 0x40;
}

//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Configure ADC0 to use Timer3 overflows as conversion source, to
// generate an interrupt on conversion complete, and to use left-justified
// output mode. Enables ADC0 end of conversion interrupt. Enables ADC0.
//
void ADC0_Init (void)
{
char old_SFRPAGE = SFRPAGE;         // Store current SFRPAGE
SFRPAGE = ADC0_PAGE;                 // Switch to ADC0 Setup Page
ADC0CN = 0x05;                 // ADC disabled; normal tracking
                        // mode; ADC conversions are initiated
                        // on overflow of Timer3, left-justify
REF0CN = 0x03;                 // enable on-chip VREF and output buffer
AMX0CF = 0x00;                 // Single-ended AIN0.0 input
AMX0SL = 0x00;
ADC0CF = (SYSCLK/(2*2500000)) << 3;         // ADC conversion clock <= 2.5MHz
ADC0CF |= 0x00;         // PGA gain = 1
AD0EN = 1;         // enable ADC0
SFRPAGE = old_SFRPAGE;         // restore SFRPAGE
}

//-----------------------------------------------------------------------------
// TIMER3_Init
//-----------------------------------------------------------------------------
//
// Configure Timer3 to auto-reload at interval specified by <counts> (no
// interrupt generated) using SYSCLK as its time base.
//
void TIMER3_Init (int counts)
{
char old_SFRPAGE = SFRPAGE;         // Save Current SFR page
SFRPAGE = TMR3_PAGE;         // Switch to Timer3 Setup Page
TMR3CN = 0x00;                 // Stop Timer3; Clear TF3
TMR3CF = 0x08;                 // use SYSCLK as timebase
RCAP3 = -counts;         // Init reload values
TMR3 = 0xffff;                 // set to reload immediately
EIE2 &= ~0x01;                 // disable Timer3 interrupts
TR3 = 0x01;                 // start Timer3
SFRPAGE = old_SFRPAGE;                 // restore SFRPAGE
}

//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//// ADC end-of-conversion ISR
// The ADC sample is stored in memory, and an index variable is incremented.
// If enough samples have been taken to process the FFT, then a flag is set,
// and ADC interrupts are disabled until the next set is requested.
//
void ADC0_ISR (void) interrupt 15 using 3
{

AD0INT = 0;         // clear ADC conversion complete
                // flag

Real[ADC_Index] = ADC0;         // store ADC value
data_H[ADC_Index] = ADC0H;
data_L[ADC_Index] = ADC0L;
ADC_Index++;                         // Increment the index into memory
if (ADC_Index >= NUM_FFT)         // If enough samples have been collected
{
Conversion_Set_Complete = 1;                 // Tell the Main Routine and...
EIE2 &= ~0x02;                         // disable ADC interrupts
}
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
tangxh
1楼-- · 2020-01-30 16:40
 精彩回答 2  元偷偷看……
locky_z
2楼-- · 2020-01-30 19:54
单电源供电的AD都不能处理电压比GND还负的电压的,你的输入信号是不是有时候比GND还负?
myduanning
3楼-- · 2020-01-30 20:28
tangxh 发表于 2012-5-18 20:40
交流信号是电流的方向发生变化的信号。 你要测的信号应该还是直流信号。  是不是超出量程了? ...

首先没有超出量程!其次我想问,我是想采集正弦信号并对其进行FFT变换,在频率域分析它的频率和功率的。AD用的是c8051f120内置12位ADC,由于ADC的输入必须是极性为正的信号,所以我在前级处理电路中给正弦信号叠加一个直流,让输入ADC的信号全部为正极性信号。可是加上前级处理电路之后,ADC采样的结果转换成电压依然全部为Vref,这个怎么解释呀?
myduanning
4楼-- · 2020-01-31 00:48
locky_z 发表于 2012-5-18 21:43
单电源供电的AD都不能处理电压比GND还负的电压的,你的输入信号是不是有时候比GND还负? ...

没有输入负极性的电压信号。我在前几处理电路中加了一级极性变换电路,就是给正弦信号加一直流电压,让其变为正极性信号,再接入ADC的。
tangxh
5楼-- · 2020-01-31 04:57
myduanning 发表于 2012-5-19 10:05
首先没有超出量程!其次我想问,我是想采集正弦信号并对其进行FFT变换,在频率域分析它的频率和功率的。 ...

你这个做法是对的,大部分交流采样都是这样做的。  你用示波器看看经过电平抬升电路之后的信号是什么样子的。   
OyutianO
6楼-- · 2020-01-31 07:16
 精彩回答 2  元偷偷看……

一周热门 更多>