AD7606B 使用总结报告
项目 : BCU 电池管理系统
平台 : Linux + ARM 嵌入式平台 (Forlinx)
日期 : 2026-06-04
文档作者: 基于代码分析整理
一、AD7606B 芯片概述
AD7606B 是 ADI(Analog Devices)公司推出的 8 通道、16 位、同步采样模数转换器(ADC),主要特性如下:
| 特性 | 规格 |
|---|---|
| 通道数 | 8 路同步采样 |
| 分辨率 | 16 bit |
| 输入范围 | ±10V / ±5V(本系统使用 ±10V) |
| 最大采样率 | 200 kSPS(每通道) |
| 接口 | SPI 串行 / 并行 |
| 数据输出模式 | 1线(DOUTA) / 2线(DOUTA+DOUTB) / 4线(DOUTA~DOUTD) |
| 供电 | AVCC 5V, VDRIVE 2.3~5.25V |
| 特性 | 内置模拟前端、二阶抗混叠滤波器、片上基准源 |
二、硬件接口设计
2.1 整体接线框图
┌──────────────────────┐ ┌─────────────────────┐
│ ARM Linux 主板 │ │ AD7606B │
│ (Forlinx) │ │ │
│ │ SPI │ │
│ SPI2 CLK ──────────┼──────────► SCLK │
│ SPI2 MOSI ─────────┼──────────► SDI (寄存器配置用) │
│ SPI2 MISO ─────────┼──────────► DOUTA (数据输出) │
│ SPI2 CS ───────────┼──────────► /CS │
│ │ GPIO │ │
│ GPIO0_B6 ──────────┼──────────► CONVST (转换启动) │
│ GPIO0_C6 ──────────┼──────────► BUSY (忙信号) │
│ │ 模拟 │ │
│ 待测信号源 ─────────┼──────────► V1~V8 (模拟输入) │
└──────────────────────┘ └─────────────────────┘
2.2 关键引脚说明
| 引脚 | 连接 | 功能描述 |
|---|---|---|
| CONVST | GPIO0_B6 (偏移 14) | 转换启动信号,上升沿触发采样,下降沿启动转换 |
| BUSY | GPIO0_C6 (偏移 22) | 忙信号输出,高电平表示正在转换,低电平表示转换完成 |
| SCLK | SPI2 CLK | 串行时钟,用于数据读出和寄存器访问 |
| DOUTA | SPI2 MISO | 串行数据输出(单线模式),输出 8 通道转换结果 |
| SDI | SPI2 MOSI | 串行数据输入,用于配置内部寄存器 |
| /CS | SPI2 CS | 片选信号 |
2.3 SPI 参数配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 设备节点 | /dev/spidev2.0 |
SPI2 总线第 0 个片选 |
| SPI 模式 | SPI_MODE_3 (CPOL=1, CPHA=1) | AD7606B 要求在 SCLK 下降沿锁存数据 |
| 时钟频率 | 12 MHz | 最大支持 60 MHz(VDRIVE > 2.7V)/ 40 MHz(VDRIVE < 2.7V) |
| 位宽 | 8 bit | 标准字节传输 |
| GPIO 芯片 | gpiochip0 | 控制 CONVST 和 BUSY |
三、软件架构设计
3.1 整体线程架构
本项目 ADC 采集运行在独立线程 adc_thread() 中,与主线程、GPIO 采集线程并行工作:
main()
├── attach_shared_memory() // 挂载共享内存 "/bcu_shared_data"
├── init_gpio() // 初始化 DI/DO GPIO
├── [线程] collect_thread() // 10ms 周期 DI 读取 + DO 写入
├── adc_spi_init() // SPI 初始化
├── adc_gpio_init() // ADC GPIO 初始化
├── adc_config_init() // ADC 寄存器配置
├── [线程] adc_thread() // 20kHz ADC 采集循环
└── 主循环等待 (SIGINT/SIGTERM 退出)
3.2 ADC 采集流程
adc_thread() 循环 (采样率 20kHz = 50μs/次)
│
├── 1. trigger_convst()
│ └── CONVST ↑ (1μs) → CONVST ↓ // 产生≥10ns的正脉冲
│
├── 2. wait_busy_low()
│ └── 轮询 BUSY 引脚,等待转换完成(超时100μs)
│
├── 3. read_all_channels()
│ └── SPI 连续传输 128 个 SCLK (16字节)
│ 读取 8 通道 × 16bit = 128bit
│
├── 4. MovingAvgFilter[8] 滑动平均
│ └── 窗口大小 = 8,去除噪声干扰
│
├── 5. 工程值转换 & 写入共享内存
│ ├── CH2~CH5: ADC→电压→电阻→NTC查表→温度 → 共享内存点604~607
│ └── CH6~CH8: ADC→电压→0.1V分辨率 → 共享内存点627~629
│
└── 6. 周期控制 (50μs补偿等待)
3.3 关键数据结构
c
// 滑动平均滤波器 (每个通道独立)
struct MovingAvgFilter {
int16_t buf[8]; // 环形缓冲区
int idx; // 当前写入位置
int32_t sum; // 累加和(增量更新,避免全量遍历)
int count; // 已采样点数
};
四、初始化配置详解
4.1 SPI 初始化 (adc_spi_init())
c
// 核心步骤:
open("/dev/spidev2.0", O_RDWR) // 1. 打开 SPI 设备
ioctl(SPI_IOC_WR_MODE, SPI_MODE_3) // 2. 设置模式 (CPOL=1, CPHA=1)
ioctl(SPI_IOC_WR_BITS_PER_WORD, 8) // 3. 设置字长 8bit
ioctl(SPI_IOC_WR_MAX_SPEED_HZ, 12000000) // 4. 设置时钟 12MHz
关键提示 :AD7606B 数据手册规定,SPI 时钟空闲为高电平(CPOL=1),数据在 SCLK 下降沿输出、上升沿采样,对应 SPI_MODE_3。
4.2 GPIO 初始化 (adc_gpio_init())
| 信号 | 方向 | 初始电平 | 说明 |
|---|---|---|---|
| CONVST (GPIO0_B6) | 输出 | 低 (0) | 空闲保持低,采集时发送正脉冲 |
| BUSY (GPIO0_C6) | 输入 | --- | 检测转换完成状态 |
4.3 CONFIG 寄存器配置 (adc_config_init())
AD7606B 上电默认值 CONFIG(0x02) = 0x08,即 DOUT_FORMAT4:3 = 01(2线串行输出模式)。
本系统将其修改为 1线模式:
写入序列(SPI 两帧 16bit,共 4 字节):
┌──────┬─────────┬──────────────────┐
│ 位域 │ 值 │ 含义 │
├──────┼─────────┼──────────────────┤
│[15] │ 0 │ 写操作 │
│[14:8]│ 0x02 │ CONFIG 寄存器地址 │
│[7:0] │ 0x00 │ DOUT_FORMAT=00 │
├──────┼─────────┼──────────────────┤
│[15:0]│ 0x0000 │ 退出寄存器模式 │
└──────┴─────────┴──────────────────┘
DOUT_FORMAT = 00→ 仅 DOUTA 一条数据线输出(单线模式)- 数据包格式:在
/CS低有效期间,连续 128 个 SCLK 依次读出 CH1→CH8 的 16bit 结果
五、数据采集与处理
5.1 采样时序
┌─────────┐
CONVST ─┘ └──────────────────────────── (≥10ns 正脉冲)
┌──────────────┐
BUSY ──────┘ └────────────────── (典型 ~4.15μs @ 200kSPS)
┌────...──┐
/CS ─────────────────────────────┘ └ (128 SCLK 读数据)
- 采样触发: 软件控制 CONVST 产生 ≥1μs 正脉冲(手册要求 ≥10ns)
- 转换等待: 轮询 BUSY 引脚直到变低(含 100μs 超时保护)
- 数据读出 :
/CS拉低后,发送 128 个 SCLK(空数据 0x00),同时从 MISO 读回 8×16bit
5.2 数据读取代码 (read_all_channels())
c
void read_all_channels(int16_t *ch_values) {
uint8_t tx[16] = {0}; // 发送全零(时钟用于移位输出)
uint8_t rx[16] = {0}; // 接收 16 字节
spi_transfer(tx, rx, 16); // 一个字传输
// 按大端序拼接:每 2 字节为一个通道的 16bit 有符号结果
for (int i = 0; i < 8; ++i) {
ch_values[i] = (int16_t)((rx[2*i] << 8) | rx[2*i+1]);
}
}
5.3 滑动平均滤波
为抑制工频干扰和随机噪声,每通道使用 窗口大小为 8 的滑动平均滤波器:
c
int16_t update(int16_t raw) {
sum -= buf[idx]; // 减去最旧值
buf[idx] = raw; // 存入新值
sum += raw; // 加上新值
idx = (idx + 1) % MA_WINDOW_SIZE; // 指针前移(环形缓冲)
if (count < MA_WINDOW_SIZE) count++;
return (int16_t)(sum / count); // 算术平均
}
| 参数 | 值 |
|---|---|
| 窗口大小 | 8 |
| 滤波延迟 | 4 个采样周期 = 200μs |
| 截止频率 | ~1.25 kHz (fs/16) |
| 计算开销 | O(1)增量更新,无循环遍历 |
5.4 通道分配与工程值转换
| 通道 | 点ID | 测量量 | 转换公式 | 精度 | 输出类型 |
|---|---|---|---|---|---|
| CH1 | --- | 未使用 | --- | --- | --- |
| CH2 | 604 | NTC温度 | V→R→NTC查表 | 1°C | int16 |
| CH3 | 605 | NTC温度 | 同上 | 1°C | int16 |
| CH4 | 606 | NTC温度 | 同上 | 1°C | int16 |
| CH5 | 607 | NTC温度 | 同上 | 1°C | int16 |
| CH6 | 627 | 电压 | ADC→V×10 | 0.1V | uint16 |
| CH7 | 628 | 电压 | 同上 | 0.1V | uint16 |
| CH8 | 629 | 电压 | 同上 | 0.1V | uint16 |
温度通道转换链路 (CH2~CH5)
ADC原始值 (int16, ±32768)
│
▼ voltage = adc_val × 10.0 / 32768.0
电压值 (float, V)
│ resistance = voltage × 10.0 / (5.0 - voltage)
▼ 备注: NTC分压电路 --- 10kΩ上拉电阻, 5V参考电压
电阻值 (float, kΩ)
│ temperature_fun_connector(resistance) // 二分查找 + 线性插值
▼
温度值 (int16, °C) 范围: -55 ~ +125°C
电压通道转换链路 (CH6~CH8)
ADC原始值 (int16, ±32768)
│
▼ voltage = adc_val × 10.0 / 32768.0
电压值 (float, V)
│ val = (uint16_t)(voltage × 10.0 + 0.5) // 四舍五入到0.1V
▼
电压值 (uint16, 精度0.1V)
NTC 查表算法
查表采用 二分查找定位 + 线性插值 的方法,在精度和速度之间取得平衡:
1. 二分查找确定电阻值所在区间 [index, index+1]
2. 线性插值: temp = table[index].temp + (table[index].res - R) / (table[index].res - table[index+1].res)
3. 限幅至 [-55, +125]°C
查找表包含 181 个标定点(-55°C ~ +125°C),覆盖 NTC 热敏电阻全温度范围。
六、AD7606B 寄存器操作
6.1 寄存器访问时序
AD7606B 的寄存器读写需要在 SPI 帧中嵌入地址/命令信息(16bit/帧):
写寄存器格式:
┌──────┬────────────┬──────────┐
│ [15] │ [14:8] │ [7:0] │
│ 0 │ 寄存器地址 │ 数据 │
│ (写) │ (0x02等) │ │
└──────┴────────────┴──────────┘
读寄存器格式:
┌──────┬────────────┬──────────┐
│ [15] │ [14:8] │ [7:0] │
│ 1 │ 寄存器地址 │ 任意值 │
│ (读) │ │ │
└──────┴────────────┴──────────┘
访问流程:
- 在
/CS上升沿时,如果接收到非零数据,进入 寄存器模式 - 在寄存器模式下,每 16 个 SCLK 处理一帧寄存器命令
- 写入
0x0000后退出寄存器模式,回到 ADC 转换模式
6.2 本系统配置的寄存器
| 寄存器 | 地址 | 默认值 | 设定值 | 含义 |
|---|---|---|---|---|
| CONFIG | 0x02 | 0x08 | 0x00 | DOUT_FORMAT=00 (1线串行输出) |
未配置的寄存器保持默认值:
- RANGE_CHx: 默认 0(±10V 输入范围)
- OS_RATIO: 默认 0(无过采样)
- STATUS_HEADER: 默认 1(包含状态头)
七、性能分析
7.1 采样率
| 项目 | 数值 |
|---|---|
| 目标采样率 | 20 kSPS(每通道) |
| 采样间隔 | 50 μs |
| BUSY 持续时间 | ~4.15 μs(典型值) |
| SPI 读取时间 | 128 × 83.3ns ≈ 10.7 μs(12MHz 时) |
| 单次转换总耗时 | ≈ 15 μs(含 CONVST 脉冲 + 等待 + SPI 读取) |
| CPU 占用余量 | 约 70%(50μs 中仅 15μs 忙碌) |
7.2 精度估算
| 参数 | 值 |
|---|---|
| ADC 分辨率 | 16 bit |
| 理论 LSB | 10V / 32768 ≈ 305 μV |
| 温度分辨率 (NTC) | 取决于 NTC 灵敏度,常温区 25°C 附近约为 0.1°C |
| 电压通道分辨率 | 0.1V(软件精度) |
7.3 滤波效果
- 滑动平均窗口 = 8,等效降低随机噪声 √8 ≈ 2.83 倍
- 相当于增加约 1.5 个有效位(ENOB)
八、关键注意事项与调试建议
8.1 硬件层面
- SPI 模式必须匹配:AD7606B 要求 SPI_MODE_3 (CPOL=1, CPHA=1),时钟空闲为高电平。
- SPI 时钟频率上限:AD7606B 手册(表5)规定 VDRIVE > 2.7V 时最大 60 MHz、VDRIVE < 2.7V 时最大 40 MHz,本系统使用 12 MHz 留有充足裕量。
- CONVST 脉冲宽度:手册要求 ≥ 10ns,代码使用 1μs 确保可靠触发。
- BUSY 超时保护:代码设置 100μs 轮询超时,防止 GPIO 异常导致死循环。
- 去耦电容:AD7606B 每个电源引脚需靠近放置 0.1μF + 10μF 去耦电容。
8.2 软件层面
- 滤波窗口选择:窗口 8 是延迟和噪声抑制的折中,减小窗口响应快但噪声大,增大则相反。
- SPI 传输原子性 :
read_all_channels()使用一次SPI_IOC_MESSAGE(1)传输完成全部 16 字节,避免分段传输导致的数据错位。 - 共享内存保护 :所有写共享内存操作在
pthread_mutex_lock/g_shared->mutex保护下进行。 - NTC 公式验证 :代码中使用的分压公式
resistance = voltage × 10.0 / (5.0 - voltage)假设 NTC 上端接 10kΩ 上拉至 5V,需确认实际硬件是否与此一致。
8.3 常见问题排查
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 读数恒为 0 或满量程 | SPI 通信异常 | 检查 SPI 模式、时钟、接线 |
| 读数跳变大 | 噪声干扰 | 增大滑动平均窗口、检查模拟前端滤波 |
| BUSY 超时 | CONVST 脉冲异常 | 用示波器检查 CONVST 和 BUSY 波形 |
| 温度偏差大 | NTC 参数不匹配 | 核对分压电阻值和参考电压是否与代码一致 |
| 寄存器配置不生效 | 未正确退出寄存器模式 | 确认最后发送了 0x0000 退出序列 |
九、代码文件索引
| 文件 | 功能 |
|---|---|
| Collect.cpp | ADC 主采集程序,含 SPI 驱动、GPIO 控制、数据处理 |
| NTCLookTable.h | NTC 查表函数声明 |
| NTCLookTable.c | NTC 电阻-温度对照表(181点)和插值查表算法实现 |
| bcu_shared.h | 共享内存数据结构定义 |
十、总结
本系统基于 AD7606B 实现了 8 通道同步模拟量采集,在 Linux 嵌入式平台上通过 SPI + GPIO 进行驱动。经过初始化配置(SPI_MODE_3 / 12MHz / 单线DOUT模式),以 20 kSPS 的采样率持续采集 8 路模拟信号,其中 4 路用于 NTC 温度测量(配合查表算法实现 -55~125°C 范围测温),3 路用于电压监测(0.1V 精度),1 路预留。
软件上采用 滑动平均滤波 (窗口=8)提升数据稳定性,通过 共享内存 将采集结果实时输出给其他进程(如数据库记录、IEC104 远动通信),整体架构清晰、实时性良好,满足 BMS 电池管理系统的模拟量采集需求。