IC:

概述

本章描述12位逐次逼近寄存器(SAR)型模数转换器(ADC)的使用方法,ADC转换结果存储在结果寄存器中,支持按需读取。

ADC的相关参数如下:

  • 分辨率:12

  • ENOB:10

  • 采样频率:31.25 kHz ~ 250 kHz,建议值为 166.67 kHz(默认)

  • 采样电容:2.4 pF ~ 2.93 pF

  • 参考电压:固定,不可外供

  • 内部阻抗:500 kΩ左右

  • FIFO:64 * 16

  • 通道切换列表长度:1 ~ 16

  • 通道参数如下表所示:

通道

通道号

引脚

输入电压(V)

常规通道

CH0~CH6

PB13~PB19

0 ~ 3.3

电池测量通道

CH7

BAT_MEAS

0 ~ 5

备注

ADC多通道采样分时复用同一个ADC采样电路。上述采样频率是针对单个通道的参数,当通道切换列表中设置多个不同的通道时,对单个通道的采样频率会同比成倍降低。

ADC采样模式

ADC仅支持 连续采样模式。该模式下,ADC不间断地按序对通道列表的通道进行采样,开关均可控,适合短时间内对电压连续采样。

ADC支持 多通道采样,用户可以配置 通道切换列表 ,参数包括 采样通道数量采样通道切换顺序

ADC采样顺序为:每当触发信号产生,ADC会对通道列表中的所有通道按序进行采样。

使用ADC连续采样模式的步骤如下:

  1. 启用ADC模块的时钟与功能

    RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);
    RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
    
  2. 根据Pinmux映射表配置ADC引脚复用

    例如:调用以下函数来使用ADC0通道。

    Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID
    PAD_InputCtrl(ADC_CH0_PIN, DISABLE);
    PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
    PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
    

    备注

    BAT_MEAS 引脚为专用引脚,不需要执行该步骤。

  3. 设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样

    ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct);
    ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE; // 设置采样模式为连续采样
    
  4. 如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数

    例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。

    ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度
    ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号
    ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号
    ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
    
  5. 初始化ADC,并启用ADC

    ADC_Init(ADC_InitTypeDef *ADC_InitStruct);
    ADC_Cmd(ENABLE);
    
  6. 通过轮询模式或中断模式读取ADC采样数据

    • 轮询模式:

      ADC_ReceiveBuf(u16 *pBuf, u32 len);
      
    • 中断模式:

      ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, ENABLE);
      InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE);
      InterruptEn(ADC_IRQ, INT_PRI_MIDDLE);
      ADC_AutoCSwCmd(ENABLE);
      

    其中, ADCIrqHandle 的定义为:

    u32 ADCIrqHandle(void *para)
    {
       (void *)para;
       u32 status = ADC_GetISR();
    
       if (status & ADC_BIT_IT_FIFO_FULL_STS) {
          while (ADC_Readable()) {
             u32 sample_value = ADC_Read(); // 读出采样值
             if (sample_cnt ++ > MAX_SAMPLE_CNT) { // 读到足够多的采样值
                ADC_AutoCSwCmd(DISABLE);
                ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, DISABLE);
                InterruptDis(ADC_IRQ);
                break;
             }
          }
       }
    
       ADC_INTClearPendingBits(status);
       return 0;
    }
    

备注

采样结果由4位通道号和12位采样值组成。用户可以分别通过以下宏获取:

  • ADC_GET_CH_NUM_GLOBAL(sample_data):获取4位通道号

  • ADC_GET_DATA_GLOBAL(sample_data):获取12位采样值

ADC校准

ADC电压校准

  • 为了改善ADC输入/输出特性的线性度,将在工厂阶段对芯片进行ADC非线性校准。通过非线性校准,可以减小ADC的增益误差与偏移误差。

  • ADC校准采用5点曲线拟合法,按照最小方差原则计算得到校准参数A/B/C。校准完成后,每颗芯片将获得专属参数A/B/C,并将其存储于 OTP 中。

  • 在得到ADC数值采样之后,按下列公式计算当前电压(单位:mV),其中参数 \(x\) 为ADC采样值:

    \[\begin{split}\begin{aligned} y &= ax^2 + bx + c \\ &= \frac{A}{2^{26}}x^2 + \frac{B}{2^{15}}x + \frac{C}{2^{6}} \end{aligned}\end{split}\]
  • 常规通道与电池测量通道的校对参数不同,用户可分别通过以下API获取校准电压:

    • ADC_GetVoltage(u32 chan_data):获取常规电压

    • ADC_GetVBATVoltage(u32 vbat_data):获取电池电压

ADC内部电阻校准

  • 不同芯片的ADC内部电阻 R 存在差异,此差异直接影响测量精度:

    ../../_images/adc_internal_r.svg

    ADC 内部电阻

    • 理想电压:\(V_{理想} = \frac{V_{cc} \times R_{2}}{R_{1} + R_{2}}\)

    • 实际电压:\(V_{实际} = \frac{V_{cc} \times R_{2}//R}{R_{1} + R_{2}//R}\)

    • 电压关系:由于内部电阻分压效应,\(V_{实际} < V_{理想}\)

    • 误差规律:阻值比 \(\frac{R_{1} \times R_{2}}{R}\) 越大,实际电压与理想电压偏差越大

  • 用户可直接通过 ADC_GetInterR() 获取内部电阻

ADC数字比较器

ADC包含数字比较器,如果指定通道的采样数值在设置的范围内,会产生对应中断,用户可以在中断处理程序中进行特定的操作,如读取当前电压等。

数字比较器在ADC的所有采样模式下都可以工作。

数字比较器支持以下 比较模式

  • 小于低阈值

  • 大于高阈值

  • 大于等于低阈值 且 小于等于高阈值

  • 小于低阈值 或 大于高阈值

备注

低阈值和高阈值的取值范围为 0 ~ 4095 ,建议低阈值不要超过高阈值。

以连续采样模式为例,如果要使用ADC数字比较器,请按照以下步骤操作:

  1. 启用ADC模块的时钟与功能,同上。

  2. 根据Pinmux映射表配置ADC引脚复用,同上。

  3. 指定通道并设置比较器的低阈值、高阈值和比较模式。

    例如:调用以下函数来设置ADC0通道的比较模式,当采样值大于等于2000且小于等于3000时会有中断产生。

    ADC_SetComp(ADC_CH0, 3000, 2000, ADC_COMP_WITHIN_THL_AND_THH);
    InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE);
    InterruptEn(ADC_IRQ, INT_PRI_MIDDLE);
    

    其中, ADCIrqHandle 的定义如下:

    u32 ADCIrqHandle(void *para)
    {
       (void)para;
       u32 status = ADC_GetISR();
       u32 value;
       if (status & ADC_BIT_IT_COMP_ALL_STS) {
          printf("ISR:0x%x, Comp status:0x%x\n", status, ADC->ADC_COMP_STS); // ADC在指定通道的采样值落在设置范围内
          while (ADC_Readable() == 0);
          value = ADC_Read();
       }
       ADC_INTClearPendingBits(status);
       return 0;
    }
    
  4. 设置默认参数,并修改ADC工作模式,同上。

  5. 如有需要,修改 ADC_InitStruct 结构体,调整通道列表及其他参数,同上。

  6. 初始化ADC,并启用ADC,同上。

  7. 建议通过轮询模式读取ADC采样数据。

ADC常见问题排查

采样电压偏移

现象

采样电压偏移

原因

  • 校准参数不适用

  • 输入阻抗不匹配

解决方法

  • 重新校准

  • 调整输入阻抗,使得信号源内阻远小于ADC输入阻抗

备注

  • 如果条件满足,可以考虑将应用电路一起校准。

  • 参考硬件设计手册,获取ADC内部阻抗值。

通道间串扰

现象

通道间串扰

原因

  • 输入阻抗不匹配,输入源驱动能力差

  • 采样率太高

解决方法

  • 降低信号源内阻

  • 降低采样率

采样电压干扰

现象

采样电压干扰,信噪比低

原因

PCB布局不合理

解决方法

  • 检查PCB布局,如是否临近开关电源、高速信号等

  • 如果接受软件滤波,可以进行多点采样值平均