lpc1752 adc抖动过大。有没有同样经历的?
无论是单次转换还是用burst方式。每次经过中断读出来的数偏差好大。有时偶尔出现fff,下面是每0.5秒读出来的数据。用表测量电压是稳定的。720
719
71d
723
723
71b
717
720
/*****************************************************************************
* adc.c:ADC module file for NXP LPC17xx Family Microprocessors
*
* Copyright(C) 2009, NXP Semiconductor
* All rights reserved.
*
* History
* 2009.05.25ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
#include "lpc17xx.h"
#include "common.h"
#include "adc.h"
#include "queue_data.h"
#include "timer.h"
#include "app_adc.h"
/*********************************************************************************************************
**A/D Converters
*********************************************************************************************************/
#define ADC_DETECT_TOTAL 64
uint16_t ADC0Value;
uint32_t ADC0Value_total;
uint16_t ADC0Value_index;
uint8_t ADC0IntDone;
// 0,1,2,3,4,5,6,7
static const int channel_map={0,0,0,1,2,3,0,0};
int adc_pclk;
static char flag_start=0;
uint32_t timer11;;
static u4t Round_schmitt_u4(u4t dividend, u4t divisor,u1t i)
{
static u4t backup;
u4t quotient;
quotient = dividend / divisor;
if ((dividend % divisor) != 0)
{
if (backup>quotient)
{
++quotient;
}
}
backup = quotient;
return (quotient);
}
#if BURST_MODE
volatile uint32_t channel_flag;
#endif
#define ADC_CHANNEL_MASK 0X3C //0x30 45//0X3C 2345
#if ADC_INTERRUPT_FLAG
/******************************************************************************
** Function name: ADC_IRQHandler
**
** Descriptions: ADC interrupt handler
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void ADC_IRQHandler (void)
{
volatile uint32_t regVal,tmp;
int index;
key_element_t el;
k3=regVal = LPC_ADC->ADSTAT; /* Read ADC will clear the interrupt */
++counter1;
el.dat=regVal;
el.index=counter1;
Key_queue_in(&el);
if ( regVal & 0x0000FF00 ) /* check OVERRUN error first */
{
regVal = (regVal & 0x0000FF00) >> 0x08;
/* if overrun, just read ADDR to clear */
/* regVal variable has been reused. */
switch ( regVal )
{
case 0x01:
regVal = LPC_ADC->ADDR0;
break;
case 0x02:
regVal = LPC_ADC->ADDR1;
break;
case 0x04:
regVal = LPC_ADC->ADDR2;
break;
case 0x08:
regVal = LPC_ADC->ADDR3;
break;
case 0x10:
regVal = LPC_ADC->ADDR4;
break;
case 0x20:
regVal = LPC_ADC->ADDR5;
break;
case 0x40:
regVal = LPC_ADC->ADDR6;
break;
case 0x80:
regVal = LPC_ADC->ADDR7;
break;
default:
break;
}
LPC_ADC->ADCR &= 0xF8FeFFFF;/* stop ADC now */
//ADC0IntDone = 1;
//el.dat=0;
//el.index=999;
// Key_queue_in(&el);
return;
}
if ( (regVal & ADC_ADINT)!=0 )
{
switch ( regVal & 0xFF ) /* check DONE bit */
{
case 0x01:
tmp=( LPC_ADC->ADDR0 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
case 0x02:
tmp=( LPC_ADC->ADDR1 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
case 0x04:
tmp=( LPC_ADC->ADDR2 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
el.dat=tmp;
el.index=2;
Key_queue_in(&el);
break;
case 0x08:
tmp=( LPC_ADC->ADDR3 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
case 0x10:
tmp=( LPC_ADC->ADDR4 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
el.dat=tmp;
el.index=4;
Key_queue_in(&el);
break;
case 0x20:
tmp=( LPC_ADC->ADDR5 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
case 0x40:
tmp=( LPC_ADC->ADDR6 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
case 0x80:
tmp=( LPC_ADC->ADDR7 >> 4 ) & 0xFFF;
ADC0Value_total] += tmp;
++ADC0Value_index];
break;
default:
break;
}
if (flag_start==1 && ADC0Value_index==ADC_DETECT_TOTAL)
{
flag_start=2;
regVal=TIMER0_get_value();
//el.dat=regVal-timer11;
//el.index=1000; //10个周期时,5分频是12842个定时器节拍。
// Key_queue_in(&el);
for (index=0; index<ADC_NUM; index++)
{
ADC0Value=Round_schmitt_u4(ADC0Value_total,ADC0Value_index,index);
ADC0Value_total=0;
ADC0Value_index=0; //有必要
ADC0IntDone = 1;
}
LPC_ADC->ADINTEN = 0; /* disableinterrupts, 虽然禁止了中断,但由于标志等下会产生,所以在下次再使能中断时会马上产生中断,所以在下次使能中断前先读一次所有的AD值(LPC_ADC->ADDRn)才清楚标志 */
LPC_ADC->ADCR &= 0xF8FeFFFF;/* stop ADC now 虽然停止了Burst,但还是会有一次中断进来,是最前那个道通的中断 执行LPC_ADC->ADINTEN = 0;可解决*/
}
}
return;
}
#endif
/*****************************************************************************
** Function name: ADCInit
**
** Descriptions: initialize ADC channel
**
** parameters: ADC clock rate
** Returned value: true or false
**
*****************************************************************************/
uint32_t ADCInit( uint32_t ADC_Clk )
{
uint32_t pclkdiv, pclk;
/* Enable CLOCK into ADC controller */
LPC_SC->PCONP |= (1 << 12);
/* all the related pins are set to ADC inputs, AD0.2~7 */
//LPC_PINCON->PINSEL0 |= 0x000000a0; /* P0.2~3, AD6,AD7,*/
LPC_PINCON->PINSEL1 |= 0x00140000; /* P0.25~26, AD2,AD3,*/
LPC_PINCON->PINSEL3 |= 0xF0000000; /* P1.30~31, AD4,AD5,*/
/* By default, the PCLKSELx value is zero, thus, the PCLK for
all the peripherals is 1/4 of the SystemFrequency. */
pclkdiv = (LPC_SC->PCLKSEL0 >> 24) & 0x03;
switch ( pclkdiv )
{
case 0x00:
default:
pclk = SystemFrequency/4;
break;
case 0x01:
pclk = SystemFrequency;
break;
case 0x02:
pclk = SystemFrequency/2;
break;
case 0x03:
pclk = SystemFrequency/8;
break;
}
adc_pclk=pclk;
//AD0CR
LPC_ADC->ADCR = ( ADC_CHANNEL_MASK << 0 ) | /* SEL=0xdc,select channel 2~7 on ADC0 */
//18M pclk,CLKDIV=3(4分频)时机率性有AD值是FFF,CLKDIV=4(5分频)时没有FFF出现,但AD值有21个单位的波动
// CLKDIV=5(6分频)时D值有3个单位的波动
// ( ( pclk/ ADC_Clk - 1 ) << 8 ) |/* CLKDIV = Fpclk / ADC_Clk - 1 */
( 2 << 8 ) |
( 0 << 16 ) | /* BURST = 0, no BURST, software controlled */
( 0 << 17 ) | /* CLKS = 0, 11 clocks/10 bits */
( 1 << 21 ) | /* PDN = 1, normal operation */
( 0 << 24 ) | /* START = 0 A/D conversion stops */
( 0 << 27 ); /* EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion) */
/* If POLLING, no need to do the following */
#if ADC_INTERRUPT_FLAG
LPC_ADC->ADINTEN = 0x100|ADC_CHANNEL_MASK; /* Enableinterrupts */
NVIC_EnableIRQ(ADC_IRQn);
#endif
return (TRUE);
}
static void get_adc0_value2(void)
{
key_element_t el;
if (ADC0IntDone==(uint8_t)1)
{
ADC0IntDone=(uint8_t)2;
app_adc_get16bit(ADC0Value);
el.dat=ADC0Value;
el.index=777;
Key_queue_in(&el);
}
}
boolt get_adc0_value(u2t* val,int channel)
{
if (ADC0IntDone]==(uint8_t)1)
{
ADC0IntDone]=(uint8_t)2;
*val=ADC0Value];
return TRUE;
}
else
{
return FALSE;
}
}
volatile int _temp;
/*****************************************************************************
** Function name: ADC0BurstRead
**
** Descriptions: Use burst mode to convert multiple channels once.
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void ADCBurstRead( void )
{
int i;
for (i=0; i<ADC_NUM; i++)
{
ADC0Value_total=0;
ADC0Value_index=0;
ADC0IntDone=0;
}
counter1=0;
_temp=LPC_ADC->ADDR0;
_temp=LPC_ADC->ADDR1;
_temp=LPC_ADC->ADDR2;
_temp=LPC_ADC->ADDR3;
_temp=LPC_ADC->ADDR4;
_temp=LPC_ADC->ADDR5;
_temp=LPC_ADC->ADDR6;
_temp=LPC_ADC->ADDR7;
/* Read all channels, 2 through 7. */
LPC_ADC->ADCR |= (ADC_CHANNEL_MASK);
LPC_ADC->ADCR |= (0x1<<16); /* Set burst mode and start A/D convert */
timer11 = TIMER0_get_value();
LPC_ADC->ADINTEN = ADC_CHANNEL_MASK; /* Enableinterrupts */
return; /* the ADC reading is done inside the
handler, return 0. */
}
int j1=0;
void ADCTimer(void)
{
if (++j1==50)
{
j1=0;
flag_start=0;
}
//
}
void ADCProcess(void)
{
if (flag_start==0)
{
flag_start=1;
ADCBurstRead();
}
get_adc0_value2();
}
/*********************************************************************************
** End Of File
*********************************************************************************/
我那个1754的开发板,某些分频是稳定没抖动。这个lpc摸透还需要折腾
页:
[1]