Edesigner. 发表于 2019-10-10 21:05:44

lpc1752 adc抖动过大。有没有同样经历的?

无论是单次转换还是用burst方式。每次经过中断读出来的数偏差好大。有时偶尔出现fff,下面是每0.5秒读出来的数据。用表测量电压是稳定的。

720
719
71d
723
723
71b
717
720

Edesigner. 发表于 2019-10-10 21:07:44

/*****************************************************************************
*   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
*********************************************************************************/

Edesigner. 发表于 2019-10-11 07:59:45

我那个1754的开发板,某些分频是稳定没抖动。这个lpc摸透还需要折腾
页: [1]
查看完整版本: lpc1752 adc抖动过大。有没有同样经历的?