CC2530中adc的使用记录

CC2530中adc的使用记录

本文主要是记录使用CC2530中adc过程中遇到的问题。同时分析ZigBee协议栈中实现的代码。

  • ADC的基本知识
  • CC2530中ADC相关特性
  • CC2530中和ADC相关的寄存器
  • ZigBee协议栈中的实现代码
  • 参考电压的问题
  • 实验过程中遇到的问题

1. ADC的基本知识

ADC是模数转换的简称,通常是指一个将模拟信号转变为数字信号的电子元件。一般的模数转换器是将一个输入电压信号转换为一个输出的数字信号,也可以看成将一个连续的模拟信号转换成离散的数字信号,主要有取样和保持,量化和编码这个几个步骤,详细的可以考考百度百科数模转换。

下面就通过一个例子来说明:一个具有8位分辨率的模拟数字转换器可以将模拟信号编码成256个不同的离散值(因为2^8= 256),从0到255(即无符号整数)或从-128到127(即带符号整数),假设参考电压,输入的模拟电压是1.25v,那我们得到的数字值是多少呢?
将5V分成256,同时1.25v是5V的1/4,则输出数字值为256/4=64。

2. CC2530中ADC相关特性

ADC支持多达14位的模拟数字转换与高达12位的有效位数。ADC包括一个达8个独立配置通道的模拟多路转换器,和一个参考电压发生器。转换结果通过DMA写入存储器。还具有若干运行模式。

ADC主要特性如下:

   1)、可在有效分辨率7—12字节中选择设置;
   2)、8个独立输入通道,可接受单端或差分信号;
   3)、参考电压可选为内部,外部单端,外部差分,或AVDD5;
   4)、产生中断请求;
   5)、转换结束时的DMA触发;
   6)、温度传感器输入;
   7)、电池测量功能。

ADC输入:

P0引脚上的信号可以作为ADC输入来使用。在下面,这些引脚叫做AIN0—AIN7引脚,输入脚AIN0—AIN7与ADC连接。
入脚可配置成单端或差动输入。如选择差动输入,包含成对输入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5和AIN6-AIN7;注意这些引脚既不能加载负电压,也不能加载大于VDD的电压。在差动模式中,成对脚转换是不同的。
除了输入脚AIN0-AIN7外,片上的温度传感器也可以用来作为ADC温度测量的输入。如要实现这个功能,需设置寄存器TR0.ADCTM和ATEST.ATESTCTRL。
也可以选择AVDD5/3电压作为一个ADC输入。这种输入允许执行,如应用中的电池测量功能。注意,这种参考不能依靠于电池电压,如AVDD5电压不能被用来做参考值。
单端输入AIN0至AIN7可代表通道号0至7,通道号8至11分别代表差动输入AIN0-AIN1,AIN2-AIN3,AIN4-AIN5,AIN6-AIN7;通道12表示GND,通道13表示温度传感器,通道15表示AVDD5/3。这些值在ADCCON2.SCH和ADCCON3.SCH中设置。

ADC转换模式

ADC的转换模式主要有两个,分别是序列转换(连续转换)和单次转换。
序列转换:无需CPU的参与,ADC能够完成一个序列的转换,并通过DMA把结果写入内存。
单次转换:ADC可以通过编程执行单个转换。通过写入ADCCON3寄存器可以触发一个转换,转换立即启动,除非一个转换序列正在进行中,这种情况下,当序列完成后,马上执行单个转换。
关于这边的详解可以阅读官方提供的CC2530 datasheet,也可以参看cc2530手册翻译(ADC)

3. CC2530中和ADC相关的寄存器

主要涉及的寄存器有:ADCL 、ADCH 、ADCCFG、ADCCON1 、ADCCON2 、ADCCON3 、TR0、P0DIR、P0SEL、APCFG。
其中ADCL 、ADCH用来存放转换的得到的数据。ADCCFG用来配置ADC通道的选择。ADCCON1 、ADCCON2 、ADCCON3是ADC模式的配置寄存器,连续转换的时候需要配置ADCCON1和ADCCON2寄存器,单次转换的时候只需要配置寄存器ADCCON3即可。TR0是测试寄存器0,主要用于测试片内温度传感器的值,一般情况下用不到。P0DIR、P0SEL、APCFG这三个寄存器主要用于配置IO来输入外部模拟信号,其中APCFG可以将IO口配置成模拟输入,可以覆盖P0SEL的设置,也就是P0SEL可以不用设置。P0DIR用来配置IO输入输出方向的。

4. ZigBee协议栈中的实现代码

uint16 HalAdcRead (uint8 channel, uint8 resolution)
{
  int16  reading = 0;

#if (HAL_ADC == TRUE)
  uint8   i, resbits;
  uint8  adcChannel = 1;

  /*
   * If Analog input channel is AIN0..AIN7, make sure corresponing P0 I/O pin is enabled.  The code
   * does NOT disable the pin at the end of this function.  I think it is better to leave the pin
   * enabled because the results will be more accurate.  Because of the inherent capacitance on the
   * pin, it takes time for the voltage on the pin to charge up to its steady-state level.  If
   * HalAdcRead() has to turn on the pin for every conversion, the results may show a lower voltage
   * than actuality because the pin did not have time to fully charge.
   */
   //上面注释是提示通过P0口输入要注意配置相应的IO
   //同时在一次转换之后,尽量不要关闭IO的输入功能
   //因为每次转换的时候需要再次启用,这种转换需要一定的时间

  if (channel < 8)
  {
    for (i=0; i < channel; i++)
    {
      adcChannel <<= 1;
    }
  }

  /* Enable channel */
  //配置对应的通道
  ADCCFG |= adcChannel;

  /* Convert resolution to decimation rate */
  switch (resolution)
  {
    case HAL_ADC_RESOLUTION_8:
      resbits = HAL_ADC_DEC_064;
      break;
    case HAL_ADC_RESOLUTION_10:
      resbits = HAL_ADC_DEC_128;
      break;
    case HAL_ADC_RESOLUTION_12:
      resbits = HAL_ADC_DEC_256;
      break;
    case HAL_ADC_RESOLUTION_14:
    default:
      resbits = HAL_ADC_DEC_512;
      break;
  }
 /* Clear ADC interrupt flag */
  ADCIF = 0;
  ADCL = 0;
  ADCH = 0;
  /* writing to this register starts the extra conversion */
  ADCCON3 = channel | resbits | adcRef;

  /* Wait for the conversion to be done */
  while (!(ADCCON1 & HAL_ADC_EOC));

  /* Disable channel after done conversion */
  ADCCFG &= (adcChannel ^ 0xFF);

  /* Read the result */
  reading = (int16) (ADCL);
  reading |= (int16) (ADCH << 8);

  /* Treat small negative as 0 */
  if (reading < 0)
    reading = 0;

  switch (resolution)
  {
    case HAL_ADC_RESOLUTION_8:
      reading >>= 8;
      break;
    case HAL_ADC_RESOLUTION_10:
      reading >>= 6;
      break;
    case HAL_ADC_RESOLUTION_12:
      reading >>= 4;
      break;
    case HAL_ADC_RESOLUTION_14:
    default:
      reading >>= 2;
    break;
  }
#else
  // unused arguments
  (void) channel;
  (void) resolution;
#endif

  return ((uint16)reading);
}

上面的代码很简单,同时英文注释也很详细,这里就不赘述了。

5. 参考电压的问题

首先看看参考电压的作用,下面一段是来自百度知道:

参考电压
测量物体的长度要用卷尺,精确测量要用游标卡尺,同理,ADC 测量电压也要有标准电压做基准。
如八位并行比较型 ADC ,把参考电压均分为 256 层,就好像卷尺的刻度,输入的待测电压与哪一个分层相等,数值就知道了。

CC2530可选择于内部产生电压,AVDD5脚电压,应用于AIN7输入脚的外部电压,或应用于AIN6-AIN7输入的差动电压。内部参考电压是1.25V(这个不是很确定),AVDD5应该是3.3v。

6. 实验过程中遇到的问题

a. 参考电压配置错误导致得到的结果只有0和4095.


你可能感兴趣的:(物联网,zigbee,cc2530,adc)