有没有人为恩智浦LPC17xx ADC编写工作代码?

时间:2013-08-19 13:34:42

标签: c microcontroller lpc adc

我正在使用恩智浦LPC1788微控制器,我正在尝试编写能让我在模拟通道0-7上执行ADC测量的代码。我现在的代码是:

uint16_t getADCChannelValue(uint8_t adcChannel)
{
  uint16_t adc_value;

  ADC_ChannelCmd(LPC_ADC, adcChannel, ENABLE);
  ADC_StartCmd(LPC_ADC, ADC_START_NOW);

  // Wait for measurement to complete.
  while (!(ADC_ChannelGetStatus(LPC_ADC, adcChannel, ADC_DATA_DONE)));

  adc_value = ADC_ChannelGetData(LPC_ADC, adcChannel);
  ADC_ChannelCmd(LPC_ADC, adcChannel, DISABLE);

  // With delay - code works. Without delay - channel 0 is correct,
  // channels 1-7 have values close to channel 0 (~2150) (incorrect).
  //OS_Delay(1);

  return adc_value;
}

随着延迟,代码似乎工作,但我不想在那里任意延迟。我已经玩了几个小时的代码,无论出于什么原因,当延迟存在时,超限标志被设置(也就是说,当函数输出正确的值时,它会抱怨溢出)。

我只将电压施加到模拟通道0.这是我在收到延迟时得到的输出:

Channel 0 = 2151
Channel 1 = 35
Channel 2 = 33
Channel 3 = 34
Channel 4 = 32
Channel 5 = 34
Channel 6 = 32
Channel 7 = 31

如果不包括在内:

Channel 0 = 2150
Channel 1 = 2151
Channel 2 = 2151
Channel 3 = 2150
Channel 4 = 2150
Channel 5 = 2150
Channel 6 = 2149
Channel 7 = 2150

是否有人编写过任何代码,让我可以在没有任意延迟的情况下尽快浏览所有ADC频道并记录其值?

2 个答案:

答案 0 :(得分:1)

标签,我认为您应该使用“突发模式”。以下是我的ADC初始化代码:

void adcHandlerInit()
{
  // Clear all bits of the analog pin registers except for the filter disable
  // bit.
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_23)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_24)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_25)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_26)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_1 * 32
                             + BRD_ADC_CH_PIN_30)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_1 * 32
                             + BRD_ADC_CH_PIN_31)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_12)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_13)*sizeof(uint32_t)))) = 1 << 8;

  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_23, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_24, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_25, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_26, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_1, BRD_ADC_CH_PIN_30, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_1, BRD_ADC_CH_PIN_31, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_12, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_13, BRD_ADC_CH_FUNC_NO_3);

  /* Configuration for ADC :
  *  ADC conversion rate = 400Khz
  */
  ADC_Init(LPC_ADC, 400000);

  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_0, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_1, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_2, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_3, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_4, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_5, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_6, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_7, DISABLE);

  // Start burst mode.
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_0, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_1, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_2, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_3, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_4, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_5, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_6, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_7, ENABLE);
  ADC_StartCmd(LPC_ADC, ADC_START_CONTINUOUS);
  ADC_BurstCmd(LPC_ADC, ENABLE);
}

底部的部分很重要。它将使微控制器在所有ADC通道上执行重复测量。之后,您可以通过以下方式获取通道电压值:

uint16_t getADCChannelValue(uint8_t adcChannel)
{
  return (uint16_t)ADC_ChannelGetData(LPC_ADC, adcChannel);
}

这应该会帮助你。但是,在不使用突发模式的情况下看到这样做的方法会很高兴,所以任何其他没有依赖突发模式的正确答案都应该被授予接受我的答案。

答案 1 :(得分:0)

我注意到,在相同类型和相同生产批次的不同控制器上,每个控制器的行为都不同。

我还有一个问题,即有时通道0正在进行错误的测量

通过在启用频道和启动cmd之间添加延迟来解决此问题。这个延迟是1us。

尽管如此,这种延迟并不适用于每个控制器。现在是4us。但这不是一个充满希望的解决方案。

un16 adcMeasureChannelBlocked(un8 channel)
{
un16 value;

// Enable channel
ADC_ChannelCmd(LP_ADC_PERHIPHERAL, channel, ENABLE);

// Reset delay timer
adcTimeOutTimer = timingGetTicks();
while(!(timingHasElapsed(&adcTimeOutTimer, TIMING_TIME_US(4))));

// Start measurement
ADC_StartCmd(LP_ADC_PERHIPHERAL, ADC_START_NOW);

// Reset timeout timer
adcTimeOutTimer = timingGetTicks();

// Wait until done
while(!ADC_ChannelGetDoneStatus(LP_ADC_PERHIPHERAL, channel, &value));
{
    if (timingHasElapsed(&adcTimeOutTimer, TIMING_TIME_MS(2)))
    {
        bmsStatusEvent(STATUS_EVT_SET,ERROR_HW_ADC_DATA);
    }
}

// Disable channel
ADC_ChannelCmd(LP_ADC_PERHIPHERAL, channel, DISABLE);

return value;
}