ADC 驱动学习博客)
最近在学习 i.MX6ULL 裸机开发写了一段 ADC 采集代码踩了不少引脚配置、ADC 校准的坑。本文结合代码搞懂 ADC 基础概念、逐次逼近原理、转换流程、分辨率。一、什么是 ADCADC 全称模数转换器Analog-to-Digital Converter。 现实世界里的信号大多是模拟信号连续变化的电压比如电位器分压、光敏电阻电压电压可以取区间内任意值。 但是单片机 / ARM 芯片只能识别数字信号0、1。ADC 的作用就是把连续变化的模拟电压转换成对应的离散数字量。简单一句话ADC 就是模拟电压 → 数字数值的转换器。对应我们代码读取电位器产生的模拟电压通过 ADC 转换得到数字值再换算成实际电压adc1_get_value()函数把原始采样值转为 0~3.3V。二、什么是逐次逼近法SAR ADCi.MX6ULL ADC 就是这个类型i.MX6ULL 内部 ADC 属于逐次逼近型 ADCSuccessive Approximation RegisterSAR ADC核心算法就是逐次逼近法。原理通俗理解 类似天平称重。要测一个未知重量从最重砝码开始尝试放上去如果太重就拿掉不重就保留依次换更小砝码不断比较直到所有砝码尝试完毕。放到 ADC 里面含义 输入电压变化大于约 0.806mVADC 输出的数字值才会变化电压变化小于这个值ADC 识别不出来输出数字量不变。重点区分 分辨率只代表最小可分辨电压不等于精度。精度包含偏移误差、增益误差这就是为什么 i.MX6ULL 需要 ADC 校准用来修正误差。举例五、代码整体小结本次裸机代码实现 i.MX6ULL ADC1 通道 1 单次采集。存在优化点当前代码是查询方式也可以改成 ADC 中断方式CPU 不用一直轮询等待转换结束。总结ADC 是嵌入式非常常用外设传感器电位器、光敏、热敏电阻几乎都要靠 ADC 把模拟信号交给 CPU 处理。理解 SAR 逐次逼近原理、分辨率概念看懂寄存器操作对后续 Linux 下 ADC 驱动学习打下基础。内部 DAC 生成一个参考电压比较器对比待测模拟电压和DAC 输出电压从最高位开始依次试探每一位如果 DAC 电压 待测电压 → 当前位保留为 1如果 DAC 电压 待测电压 → 当前位清 0逐位试探高位→低位全部位判断完成得到最终数字结果。我们代码读取的 12bit ADC 原始值就是逐次逼近算法输出的数字结果。三、ADC 转换完整过程结合我们 i.MX6ULL 代码整个 ADC 工作分为硬件初始化 → ADC 校准 → 启动单次转换 → 等待转换完成 → 读取结果 → 电压换算1. 引脚初始化配置 GPIO 引脚复用为 ADC 输入功能配置 PAD 电气属性上下拉、使能等IOMUXC_SetPinMux(IOMUXC_GPIO1_IO01_GPIO1_IO01, 0); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01, IOMUXC_SW_PAD_CTL_PAD_PKE(1));GPIO1_IO01 复用为 ADC 通道 1作为模拟电压输入脚。2. ADC 模块配置与校准i.MX6ULL 的 ADC 必须做校准内部模拟电路会有误差上电后执行校准消除偏移误差。校准完成后配置 ADC 时钟、分频、使能 ADC 模块。3. 启动 ADC 转换往HC[0]寄存器写入通道号触发一次 ADC 采样转换ADC1-HC[0] 1; //选择通道1启动转换4. 等待转换完成查询HS寄存器的转换完成标志位判断 ADC 是否转换结束while ((ADC1-HS (1 0)) 0); //等待转换完成标志置15. 读取原始采样结果转换完成从结果寄存完整流程总结return ADC1-R[0] 0xFFF; //取出低12位ADC结果6. 换算实际电压参考电压是 3.3V12bit ADC 范围 0~4095。 公式实际电压 原始值 / 4095 * 参考电压return adc1_get_origin_value() / 4095.0 * 3.3;完整流程总结引脚配置 → ADC 模块初始化 校准 → 写通道号启动转换 → 查询标志等待完成 → 读原始数字值 → 计算真实电压。四、ADC 分辨率含义分辨率ADC 能够分辨的最小输入电压变化量代表 ADC 识别微小电压变化的能力。一般用位数描述我们 i.MX6ULL ADC 是12 位 ADC。12bit输出数字范围0 ~ 2¹² - 1 0 ~ 4095一共 4096 个量化等级。参考电压 Vref3.3V最小可分辨电压LSB Vref / 2^N 3.3 / 4096 ≈0.806mV8bit ADC0~255同样 3.3V 下最小分辨电压≈12.9mV分辨能力比 12bit 差很多。位数越高分辨率越高能识别更小的电压变化。复用 GPIO 引脚作为模拟输入