ARM嵌入式 --- ADC
·
一、ADC 基础概念
核心重点
- ADC 本质:连续的模拟信号→离散的数字信号的转换,是嵌入式系统采集外部传感器(温度、电压、电流)的核心接口。
- 两大核心特性:
- 量程:ADC 能采集的电压范围(如 IMX6ULL 是 0~3.3V)。
- 分辨率:数字量的精度(如 12 位 = 2^12 = 4096 级,最小分辨电压 = 3.3V/4095 ≈ 0.8mV)。
- 常见类型:逐次逼近型(IMX6ULL 采用)、Σ-Δ 型(高精度测量)、流水线型(高速采集)。
二、逐次逼近型 ADC
核心原理
逐次逼近型 ADC 核心是 “二分查找”:
- ADC 内部有 DAC(数模转换器)和比较器。
- 从最高位(MSB)到最低位(LSB)依次试探:
- 若 DAC 输出 < 输入电压 → 保留该位。
- 若 DAC 输出 > 输入电压 → 清零该位。
- 经过 n 次试探(n 为分辨率),得到最终数字量。
关键流程
初始化 → 校准 → 启动转换 → 等待完成 → 读取结果。
关键概念解析
2.1 量程
- 定义:ADC 输入电压的有效范围,IMX6ULL ADC 单极性输入为 0~3.3V。
- 注意:输入电压不能超过量程,否则会导致数据饱和(全为 0xFFF)或损坏芯片。
2.2 分辨率
- 定义:ADC 能分辨的最小电压变化,公式:最小分辨电压=满量程数字值量程=212−13.3V≈0.806mV
- IMX6ULL 支持:8/10/12 位分辨率,12 位为最高精度,博客重点讲解 12 位配置。
2.3 精度
- 区别:精度 ≠ 分辨率!精度包含误差(偏移误差、增益误差、噪声误差)。
- 校准作用:IMX6ULL 的 ADC 内置自校准功能,能消除偏移 / 增益误差,提升精度(博客代码核心实现校准)。
2.4 实际应用选择指南
| 应用场景 | 分辨率选择 | 关键要求 |
|---|---|---|
| 普通电压采集(电池电压) | 12 位 | 满足精度,配置简单 |
| 高精度传感器(温湿度) | 12 位 + 校准 | 需多次采样取平均 |
| 高速数据采集 | 10/8 位 | 降低转换时间,提升采样率 |
三、IMX6ULL 中的 ADC 模块
3.1 硬件配置
(1)引脚复用
IMX6ULL 的 ADC 引脚需配置为ADC 功能(而非 GPIO),以 ADC1_IN1 为例:
- 引脚:
GPIO1_IO01→ 复用为ADC1_IN1(ALT1 功能)。 - 配置函数:
IOMUXC_SetPinMux/IOMUXC_SetPinConfig(与你现有 I2C 代码风格一致)。
(2)时钟配置
- IMX6ULL ADC 时钟源来自 peripheral clock(默认 66MHz)。
- 时钟分频:通过
CFG寄存器配置,推荐分频系数 8(时钟 8.25MHz,符合 ADC 时钟要求)。
3.2 关键寄存器配置(核心)
| 寄存器名称 | 位定义 | 功能 | 实战配置 |
|---|---|---|---|
| 控制寄存器(ADCx_HC0) | AIEN(bit7) | 转换完成中断使能 | 0 = 禁用中断(查询模式) |
| ADCH(bit[4:0]) | 采样通道选择 | 0b00001 = 选择 ADC1_IN1 通道 | |
| 状态寄存器(ADCx_HS) | COCO0(bit0) | 通道 0 转换完成标志 | 等待该位为 1,确认转换结束 |
| 数据寄存器(ADCx_R0) | CDATA(bit[11:0]) | 12 位 ADC 转换结果存储 | 仅读取低 12 位,屏蔽高位无效数据 |
| 配置寄存器(ADCx_CFG) | MODE(bit[4:2]) | ADC 分辨率选择 | 0b010 = 12 位分辨率 |
| ADICLK(bit[6:5]) | ADC 时钟源选择 | 0b11 = 异步时钟源 | |
| CLK_DIV(bit[1:0]) | 输入时钟分频系数 | 0b11 = 8 分频(适配 ADC 时钟要求) | |
| 通用控制寄存器(ADCx_GC) | CAL(bit7) | ADC 自校准启动 | 1 = 启动内部自校准流程 |
| ASYNC_CLK_EN(bit6) | 异步时钟使能 | 1 = 使能 ADC 异步时钟 | |
| SW_START(bit0) | 软件触发转换 | 1 = 软件启动 ADC 转换 | |
| 通用状态寄存器(ADCx_GS) | CALF(bit1) | 自校准失败标志 | 0 = 校准成功;失败时写 1 清零标志 |
四、ADC驱动代码实现
4.1 ADC 初始化函数 adc_init
功能:引脚配置 → 寄存器配置 → ADC 自校准
int adc_init(ADC_Type * base)
{
// 1. 配置引脚为 ADC 功能
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO01_GPIO1_IO01, 1);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01, 0x10b0);
// 2. 关闭通道0,防止配置时误触发转换
base->HC[0] &= ~(1 << 0);
// 3. 配置分辨率+时钟分频:12位 + 8分频
base->CFG = (0x2 << 2) | (0x3 << 0);
// 4. 选择软件触发转换
base->GC = (0x01 << 0);
// 5. 清除校准失败标志
base->GS |= (0x01 << 1);
// 6. 启动自校准
base->GC |= (0x01 << 7);
// 7. 等待校准完成
while(base->GC & (1 << 7));
// 8. 判断校准是否成功
if(base->GS & (1 << 1))
return -1;
return 0;
}
引脚配置
GPIO1_IO01配置为 ALT1 → 复用为ADC1_IN1通道0x10b0为 ADC 输入推荐电气配置HC [0] 关闭通道先清空通道使能位,保证配置安全。
CFG 寄存器配置
bit4~bit2 = 0x2→ 12 位分辨率bit1~bit0 = 0x3→ 8 分频时钟GC 寄存器配置
bit0 = 1→ 软件触发转换bit7 = 1→ 启动 ADC 自校准GS 状态寄存器
bit1为校准失败标志- 校准后若为 1 → 初始化失败
4.2 ADC 读取函数 adc_read
功能:启动转换 → 等待完成 → 读取 12 位结果
unsigned short adc_read(ADC_Type * base)
{
unsigned short adc_value = 0;
// 1. 选择ADC通道(0x1f为内部通道,可改为外部通道)
base->HC[0] |= (0x1f << 0);
// 2. 启动转换
base->HC[0] = (0x1 << 0);
// 3. 等待转换完成标志
while(!(base->HS & (1 << 0)));
// 4. 读取低12位有效数据
adc_value = base->R[0] & 0xfff;
return adc_value;
}
HC [0] 通道选择
0x1f:内部温度传感器通道若使用外部ADC1_IN1,改为0x01启动转换向
HC[0]的 bit0 写 1 → 软件启动转换HS 状态寄存器
bit0 = 1表示 转换完成循环等待直到该位置 1R [0] 结果寄存器只取低 12 位有效数据 →
0xfff屏蔽高位结果范围:0 ~ 4095
4.3 main.c函数
int main(void)
{
// 定义变量存储ADC原始数据
unsigned short data = 0;
// ==================== 1. 系统基础资源初始化 ====================
system_irq_init(); // 初始化中断控制器
clk_init(); // 初始化系统时钟
led_init(); // LED初始化(可选,用于状态指示)
beep_init(); // 蜂鸣器初始化(可选)
key_irq_init(gpio1_io18_handler); // 按键中断初始化
gpt1_init(); // 定时器初始化
uart_init(UART1); // 串口初始化(用于打印结果)
i2c_init(I2C1); // I2C初始化(根据需求可选)
// ==================== 2. ADC初始化 ====================
int flag = adc_init(ADC1);
// ==================== 3. 循环采样、打印电压 ====================
while(1)
{
// 若ADC初始化成功,才执行采样
if(!flag)
{
// 读取ADC原始数据(0~4095)
data = adc_read(ADC1);
// 计算公式:实际电压 = 原始数据 * 330 / 4095
// 330 = 3.3V * 100,用于保留两位小数
unsigned int adc_value = data * 330 / (4096 - 1);
// 串口打印:原始数据 + 实际电压(保留两位小数)
printf("data = 0x%x value = %d.%02d\r\n", data, adc_value / 100, adc_value % 100);
// 每隔3秒采样一次
delay_ms(3000);
}
}
return 0;
}

运行结果:程序下载到开发板后,串口助手会输出传感器的实时电压约为 3.3V
五、学习总结
ADC 配置完整思路流程
- 引脚配置:将 GPIO1_IO01 复用为 ADC 功能,并配置电气属性。
- 关闭通道:清空 HC [0] 启动位,防止配置时误触发转换。
- 核心参数配置:通过 CFG 寄存器设置 12 位分辨率 + 8 分频时钟。
- 触发模式配置:通过 GC 寄存器配置为软件触发转换。
- 校准准备:清空 GS 寄存器的校准失败标志位。
- 启动自校准:置位 GC 寄存器校准位,启动 ADC 内部校准。
- 等待校准完成:循环等待校准位硬件自动清零。
- 校准结果判断:检查校准失败标志,判断初始化是否成功。
- 通道选择:读取时配置 HC [0] 选择 ADC 采集通道。
- 启动转换:软件置位启动位,开始 AD 转换。
- 等待完成:查询 HS 寄存器状态,等待转换结束。
- 读取结果:从 R [0] 寄存器读取低 12 位有效采样数据。
ADC 配置先引脚、再时钟分辨率、必须校准,采集时选通道、软启动、等完成、读数据,核心就是寄存器的正确配置与状态判断。
ADC 学习重点总结
- 核心原理:ADC 完成模拟电压到数字量的转换,i.MX6ULL 采用 12 位逐次逼近型结构。
- 关键步骤:引脚复用 → 寄存器配置 → 自动校准 → 软件触发 → 结果读取。
- 寄存器核心:CFG(分辨率 / 时钟)、GC(触发 / 校准)、HC [0](通道 / 启动)、HS(完成标志)、R [0](数据)。
- 必备操作:ADC 必须执行自校准才能保证采集精度。
- 采集流程:选择通道 → 启动转换 → 等待完成 → 读取有效数据。
- 实战要点:12 位 ADC 结果范围 0~4095,对应 0~3.3V 电压,可通过公式换算实际电压。
更多推荐


所有评论(0)