搜索
bottom↓
回复: 2

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

[复制链接]

出45入88汤圆

发表于 2019-10-10 21:05:44 | 显示全部楼层 |阅读模式
无论是单次转换还是用burst方式。每次经过中断读出来的数偏差好大。有时偶尔出现fff,下面是每0.5秒读出来的数据。用表测量电压是稳定的。

720
719
71d
723
723
71b
717
720

出45入88汤圆

 楼主| 发表于 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.25  ver 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[ADC_NUM];
uint32_t ADC0Value_total[ADC_NUM];
uint16_t ADC0Value_index[ADC_NUM];

uint8_t ADC0IntDone[ADC_NUM];

//                              0,1,2,3,4,5,6,7
static const int channel_map[8]={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[ADC_NUM];
  u4t quotient;
  quotient = dividend / divisor;
  if ((dividend % divisor) != 0)
  {
    if (backup[i]>quotient)
    {
      ++quotient;
    }
  }
  backup[i] = 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[channel_map[0]] += tmp;
      ++ADC0Value_index[channel_map[0]];
      break;
    case 0x02:
      tmp=( LPC_ADC->ADDR1 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[1]] += tmp;
      ++ADC0Value_index[channel_map[1]];
      break;
    case 0x04:
      tmp=( LPC_ADC->ADDR2 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[2]] += tmp;
      ++ADC0Value_index[channel_map[2]];
      el.dat=tmp;
      el.index=2;
      Key_queue_in(&el);
      break;
    case 0x08:
      tmp=( LPC_ADC->ADDR3 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[3]] += tmp;
      ++ADC0Value_index[channel_map[3]];
      break;
    case 0x10:
      tmp=( LPC_ADC->ADDR4 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[4]] += tmp;
      ++ADC0Value_index[channel_map[4]];
      el.dat=tmp;
      el.index=4;
      Key_queue_in(&el);
      break;
    case 0x20:
      tmp=( LPC_ADC->ADDR5 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[5]] += tmp;
      ++ADC0Value_index[channel_map[5]];
      break;
    case 0x40:
      tmp=( LPC_ADC->ADDR6 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[6]] += tmp;
      ++ADC0Value_index[channel_map[6]];
      break;
    case 0x80:
      tmp=( LPC_ADC->ADDR7 >> 4 ) & 0xFFF;
      ADC0Value_total[channel_map[7]] += tmp;
      ++ADC0Value_index[channel_map[7]];
      break;
    default:
      break;
    }
    if (flag_start==1 && ADC0Value_index[ADC_NUM-1]==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[index]=Round_schmitt_u4(ADC0Value_total[index],ADC0Value_index[index],index);
        ADC0Value_total[index]=0;
        ADC0Value_index[index]=0; //有必要
        ADC0IntDone[index] = 1;
      }
      LPC_ADC->ADINTEN = 0;                /* disable  interrupts, 虽然禁止了中断,但由于标志等下会产生,所以在下次再使能中断时会马上产生中断,所以在下次使能中断前先读一次所有的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;                /* Enable  interrupts */
  NVIC_EnableIRQ(ADC_IRQn);
#endif
  return (TRUE);
}


static void get_adc0_value2(void)
{
  
  key_element_t el;
  if (ADC0IntDone[3]==(uint8_t)1)
  {
    ADC0IntDone[3]=(uint8_t)2;
    app_adc_get16bit(ADC0Value);
    el.dat=ADC0Value[0];
    el.index=777;
    Key_queue_in(&el);
  }
}



boolt get_adc0_value(u2t* val,int channel)
{
  if (ADC0IntDone[channel_map[channel]]==(uint8_t)1)
  {
    ADC0IntDone[channel_map[channel]]=(uint8_t)2;
    *val=ADC0Value[channel_map[channel]];
    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[i]=0;
    ADC0Value_index[i]=0;
    ADC0IntDone[i]=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;                /* Enable  interrupts */
  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
*********************************************************************************/

出45入88汤圆

 楼主| 发表于 2019-10-11 07:59:45 来自手机 | 显示全部楼层
我那个1754的开发板,某些分频是稳定没抖动。这个lpc摸透还需要折腾
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-5 02:36

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表