AD7606B 使用总结报告

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    │ 寄存器地址  │ 任意值    │
│ (读) │            │          │
└──────┴────────────┴──────────┘

访问流程:

  1. /CS 上升沿时,如果接收到非零数据,进入 寄存器模式
  2. 在寄存器模式下,每 16 个 SCLK 处理一帧寄存器命令
  3. 写入 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 硬件层面

  1. SPI 模式必须匹配:AD7606B 要求 SPI_MODE_3 (CPOL=1, CPHA=1),时钟空闲为高电平。
  2. SPI 时钟频率上限:AD7606B 手册(表5)规定 VDRIVE > 2.7V 时最大 60 MHz、VDRIVE < 2.7V 时最大 40 MHz,本系统使用 12 MHz 留有充足裕量。
  3. CONVST 脉冲宽度:手册要求 ≥ 10ns,代码使用 1μs 确保可靠触发。
  4. BUSY 超时保护:代码设置 100μs 轮询超时,防止 GPIO 异常导致死循环。
  5. 去耦电容:AD7606B 每个电源引脚需靠近放置 0.1μF + 10μF 去耦电容。

8.2 软件层面

  1. 滤波窗口选择:窗口 8 是延迟和噪声抑制的折中,减小窗口响应快但噪声大,增大则相反。
  2. SPI 传输原子性read_all_channels() 使用一次 SPI_IOC_MESSAGE(1) 传输完成全部 16 字节,避免分段传输导致的数据错位。
  3. 共享内存保护 :所有写共享内存操作在 pthread_mutex_lock/g_shared->mutex 保护下进行。
  4. 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 电池管理系统的模拟量采集需求。

相关推荐
zhangfeng11333 小时前
htop命令根据实际Linux环境下的讲解,结合国家超算中心hpc
linux·运维·服务器
‎ദ്ദിᵔ.˛.ᵔ₎3 小时前
linux基础开发工具
linux
小六学编程3 小时前
Linux 下 gcc / g++ 编译过程详解:从编译到链接
linux·c/c++
许彰午3 小时前
在PowerBuilder里手写XML序列化——没有现成库的年代怎么拼报文
xml·linux·服务器
ReadVersion3 小时前
Ubuntu 22.04 设置时区
linux·运维·ubuntu
dawei.wang3 小时前
embedit报错
linux
赵民勇4 小时前
apt.conf.d配置详解
linux
2023自学中4 小时前
Linux虚拟机,VSCode + GDB 调试配置:launch.json 模板
linux·vscode·嵌入式
RisunJan4 小时前
Linux命令-ntsysv(集中管理系统的各种服务)
linux·运维·服务器