☰
AD7190 24位ADC驱动开发实战:从SPI时序到量产校准
2026/10/16 14:37:44 网站建设 项目流程

简介:这份AD7190驱动程序压缩包面向嵌入式硬件开发者与传感器接口设计人员,针对高精度数据采集场景,提供与24位Σ-Δ型ADC AD7190通信所需的底层驱动支持。AD7190具备低功耗、多通道差分输入、内置可编程增益放大器与数字滤波器等特性,常用于工业与医疗领域的温度、压力、电流监测,本驱动帮助开发者快速完成初始化配置、SPI数据读取、中断与错误处理等关键环节。资源共21个文件,约57KB,以C源码与头文件为核心,辅以编译生成的obj、lst、map、hex等中间与烧录文件,以及Keil工程相关配置,结构紧凑便于直接集成到嵌入式工程。目前已有700余人学习下载,适合需要缩短AD7190调试周期、参考SPI时序与寄存器配置思路的开发者借鉴使用。

1. AD7190 驱动程序.zip:从裸机到量产,一个 24 位 ADC 的驱动到底要写什么

如果你手头正捏着一份 AD7190 驱动程序.zip,大概率不是想研究它的寄存器手册有多厚,而是想尽快让这颗 24 位 Σ-Δ 型 ADC 在自己的板子上把数读出来。这颗芯片在精密称重、压力变送、热电偶测温里出现频率极高,原因很直接:内置 PGA、内置基准缓冲、可选斩波、RMS 噪声低到能分辨微伏级信号。但它的驱动也是出了名的“玄学”——SPI 时序差半个周期,读出来全是 0xFFFFFF;配置寄存器写错一位,转换结果直接跳成噪声。这份驱动包真正要解决的,是把“能读到数”推进到“读得稳、读得准、能过 EMI 和温漂测试”。适合谁看?适合已经能点亮 STM32 或同类 MCU 的 SPI、但被 AD7190 的连续转换模式和状态机绕晕的嵌入式工程师。下面按我实际调通的顺序,把驱动拆开讲。

2. 先搞懂 AD7190 的通信骨架:SPI 模式、时序和寄存器映射

2.1 为什么 AD7190 的 SPI 不能照搬 Flash 的配置

很多新手翻车的第一步,是把 AD7190 当成普通 SPI Flash 来配:CPOL=0、CPHA=0、随便找个 1 MHz 时钟就开读。AD7190 的 SPI 接口对空闲电平和采样边沿有明确要求,手册里写的是 SCLK 空闲高电平、数据在 SCLK 下降沿被主机采样。也就是说,MCU 侧通常要配成 CPOL=1、CPHA=1 或者 CPOL=1、CPHA=0,具体取决于你用的是硬件 SPI 还是软件模拟。我一般会先用软件 SPI 把时序跑通,确认读到的 ID 寄存器是 0x0X(低四位固定),再切硬件 SPI 提速。

另一个容易被忽略的点是:AD7190 的每次寄存器访问都是“通信寄存器打头”。你不能直接读数据寄存器,必须先写通信寄存器,告诉它下一步是读还是写、操作哪个寄存器、是单次还是连续。这个机制决定了驱动里必须有一个状态机,而不是简单的 read_reg/write_reg 两个函数。

2.2 通信寄存器的位定义与驱动里的状态机

通信寄存器 8 位,实际用到的就几位:WEN(写使能)、R/W(读写)、RS2~RS0(寄存器地址)。写 0x08 表示下一步写配置寄存器,写 0x58 表示下一步连续读数据寄存器。驱动里我习惯用一个枚举把常用操作固化下来:

/* AD7190 通信寄存器命令字,按实际使用场景预定义 */ typedef enum { AD7190_CMD_WRITE_CONFIG = 0x08, /* 写配置寄存器 */ AD7190_CMD_READ_CONFIG = 0x10, /* 读配置寄存器 */ AD7190_CMD_WRITE_MODE = 0x09, /* 写模式寄存器 */ AD7190_CMD_READ_MODE = 0x11, /* 读模式寄存器 */ AD7190_CMD_READ_DATA = 0x58, /* 连续读数据寄存器 */ AD7190_CMD_READ_STATUS = 0x40, /* 读状态寄存器 */ AD7190_CMD_RESET = 0xFF /* 复位,连续写 40 个 1 */ } ad7190_cmd_t;

这段枚举的价值在于:它把“通信寄存器 + 后续操作”绑成一个原子命令,调用方不用每次去翻位表。参数上唯一要留意的是 RESET 命令,它不是写一次就生效,而是要求 SCLK 连续打 40 个 1,少一个都可能复位不干净。我见过有人只发 8 个 1 就往下走,结果配置寄存器写不进去,查了一下午。

2.3 复位、读 ID、写配置的最小验证流程

拿到一份 AD7190 驱动程序.zip,我建议先别急着跑连续转换,按下面三步做最小验证:

第一步,硬复位。拉低 RESET 引脚至少 100 ns,或者用软件发 40 个 1。第二步,读状态寄存器,确认 RDY 位和 ERR 位正常。第三步,写配置寄存器,把增益、极性、斩波、基准选择一次性配好,再回读比对。

/* 最小验证:复位后回读配置寄存器,确认写入生效 */ uint8_t ad7190_min_probe(void) { uint8_t cfg[3] = {0x00, 0x00, 0x10}; /* 示例:增益 1,双极性,内部基准 */ ad7190_write_reg(AD7190_CMD_WRITE_CONFIG, cfg, 3); uint8_t rd[3] = {0}; ad7190_read_reg(AD7190_CMD_READ_CONFIG, rd, 3); /* 逐字节比对,任何一位不一致都说明时序或命令字有问题 */ if (rd[0] != cfg[0] || rd[1] != cfg[1] || rd[2] != cfg[2]) { return 1; /* 配置回读失败 */ } return 0; }

逻辑说明:写配置和读配置都走通信寄存器打头,写的时候 WEN=1,读的时候 WEN=0。参数上,配置寄存器 24 位里,高 8 位决定斩波和时钟源,中间 8 位决定增益和极性,低 8 位决定基准和缓冲。回读比对是最便宜的后悔药,能在 10 秒内告诉你 SPI 到底通没通。

3. 把连续转换跑起来:模式寄存器、RDY 引脚和采样节拍

3.1 连续转换模式与单次转换模式怎么选

AD7190 的模式寄存器决定它怎么干活。单次转换模式适合低功耗轮询场景,每次转换完自动进空闲,你读一次数据它就停;连续转换模式适合高速采集,转换完立刻开始下一次,RDY 引脚会周期性拉低告诉你数据好了。我一般这样选:采样率低于 10 SPS 用单次,省电且逻辑简单;高于 10 SPS 用连续,避免每次重新启动的建立时间。

模式寄存器里还有一个关键位:时钟源选择。用内部 4.92 MHz 时钟最省事,但如果你板子上有温漂要求,外部晶振更稳。另外,斩波使能位会影响有效分辨率和建立时间,称重场景通常开斩波,因为要压 1/f 噪声。

3.2 RDY 引脚的两种接法和中断配置

RDY 是开漏输出,低电平表示数据就绪。接法有两种:上拉到 MCU 的 GPIO 做轮询,或者直接接外部中断引脚做边沿触发。轮询简单但占 CPU,中断高效但要注意消抖——AD7190 在连续模式下 RDY 会周期性翻转,如果中断里读数据太慢,下一次转换完成时你还在处理上一次,就会丢数。

/* RDY 中断回调:读 24 位数据并存入环形缓冲 */ void HAL_GPIO_EXTI_Callback(uint16_t pin) { if (pin != AD7190_RDY_PIN) return; uint8_t buf[3] = {0}; ad7190_read_reg(AD7190_CMD_READ_DATA, buf, 3); /* 拼成 24 位有符号数,注意 AD7190 是二进制补码输出 */ int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (raw & 0x800000) { raw |= 0xFF000000; /* 符号扩展 */ } ringbuf_push(&adc_ring, raw); }

逻辑说明:读数据寄存器必须用连续读命令 0x58,读 3 个字节。参数上,符号扩展不能省,否则负电压读出来会变成接近满量程的正数。环形缓冲的大小取决于你的采样率和上层处理速度,我一般留 64 个样本,够上层做一次滑动平均。

3.3 采样率、滤波器和建立时间的三角关系

AD7190 的输出数据率由模式寄存器的 FS 字决定,公式大致是 f_out = 4.92 MHz / (1024 × FS)。FS 越小,采样越慢,但噪声越低。这里有个血泪经验:改变 FS 之后,必须等至少一个完整的建立周期再读数据,否则第一次读到的可能是旧值或未稳定的值。建立时间通常是 1/FS 的若干倍,具体看斩波是否开启。

参数典型值影响
FS 字1~1023决定输出速率,越小越慢越稳
斩波使能开/关开则噪声低但建立时间长
增益1~128增益越高,有效分辨率越低
基准内部/外部外部基准温漂更小

这张表我一般贴在调试笔记第一页,改任何一个参数前先看另外三个会不会被连带影响。

4. 驱动里的避坑与排查:那些让读数跳成噪声的细节

4.1 现象:读出来全是 0xFFFFFF 或 0x000000

原因:SPI 时序相位不对,或者通信寄存器命令字写错。AD7190 在 SCLK 空闲高电平时采样,如果你配成 CPOL=0,数据线在错误边沿被采样,读回来就是全 1 或全 0。解决:用示波器看 SCLK 和 DIN 的相位关系,确认数据在下降沿稳定。没有示波器就先用软件 SPI 把时钟降到 100 kHz,逐位翻转验证。

4.2 现象:配置寄存器回读正确,但数据寄存器一直不更新

原因:模式寄存器没进连续转换,或者 RDY 引脚没接对。AD7190 上电默认是空闲模式,你不写模式寄存器它不会自己开始转换。解决:写模式寄存器时把 MD2~MD0 设成连续转换对应的值,然后确认 RDY 引脚在 100 ms 内有一次拉低。如果 RDY 一直高,检查是不是被外部上拉电阻拉太死,或者引脚配置成了推挽输出。

4.3 现象:读数周期性跳动,幅度远超噪声预期

原因:基准电压不稳,或者模拟输入端有共模干扰。AD7190 的基准输入对电源纹波很敏感,如果你用内部基准,检查 AVDD 的退耦电容是不是离引脚太远。解决:在 REFIN 引脚旁边放 0.1 μF 和 10 μF 并联,模拟输入加 RC 滤波,截止频率设在采样率的 1/10 以下。

4.4 现象:切换增益后第一组数据明显偏大或偏小

原因:PGA 建立时间不够。增益越高,内部 PGA 的建立越慢,如果你切完增益立刻读,拿到的是未稳定的值。解决:切增益后丢弃前 3 个样本,或者等 RDY 连续拉低 3 次再开始记录。这个坑在多点称重校准里特别常见,表现为校准点之间线性度很差。

4.5 现象:低采样率下读数缓慢漂移

原因:斩波使能后,内部会周期性交换输入极性来抵消失调,但如果你的输入滤波电容太大,交换瞬间的电荷注入会导致漂移。解决:减小输入滤波电容,或者在斩波模式下把采样率再降一档,给内部节点足够的恢复时间。

5. 从能读到能用:校准、温漂补偿和量产验证的实操技巧

驱动跑通只是第一步,真正让 AD7190 在量产里站住脚,靠的是校准和验证。我一般把校准分成三步:零点校准、满量程校准、温漂抽检。

零点校准最简单:短接模拟输入,读 100 个样本取平均,把这个值存进 MCU 的 Flash 作为 offset。满量程校准需要一个已知的基准源,比如高精度电阻分压出来的电压,读 100 个样本取平均,算出增益系数。这两个系数在每次上电时加载,能消掉大部分芯片间的个体差异。

温漂补偿稍微麻烦一点。AD7190 内部基准的温漂典型值是几个 ppm/°C,如果你做的是 0.01% 精度的称重,这个漂移不能忽略。我的做法是在恒温箱里跑三个温度点:25°C、40°C、60°C,每个温度点记录零点读数和满量程读数,拟合出一条一阶线性补偿曲线。代码里用一个简单的查表加插值就能实现:

/* 温漂补偿:根据当前温度插值出零点和增益修正系数 */ typedef struct { float temp; float offset; float gain; } cal_point_t; static const cal_point_t cal_table[3] = { {25.0f, 0.0f, 1.0000f}, {40.0f, -12.5f, 0.9998f}, {60.0f, -30.2f, 0.9995f} }; float ad7190_compensate(float raw, float temp) { /* 简化版线性插值,实际项目建议用二分查找定位区间 */ if (temp <= cal_table[0].temp) { return (raw - cal_table[0].offset) * cal_table[0].gain; } if (temp >= cal_table[2].temp) { return (raw - cal_table[2].offset) * cal_table[2].gain; } for (int i = 0; i < 2; i++) { if (temp >= cal_table[i].temp && temp < cal_table[i + 1].temp) { float ratio = (temp - cal_table[i].temp) / (cal_table[i + 1].temp - cal_table[i].temp); float off = cal_table[i].offset + ratio * (cal_table[i + 1].offset - cal_table[i].offset); float gain = cal_table[i].gain + ratio * (cal_table[i + 1].gain - cal_table[i].gain); return (raw - off) * gain; } } return raw; }

这段代码的关键参数是 cal_table 里的三个温度点和对应的 offset、gain。offset 单位是 ADC 码值,gain 是无量纲系数。实际产线里,我会把每个模块的校准值单独写进它的 Flash,而不是用同一张表,因为芯片间的失调差异远大于温漂。

量产验证阶段,我习惯做两件事:一是连续跑 24 小时,每 10 分钟记录一次零点和满量程读数,看有没有阶跃或缓慢漂移;二是做一次电源波动测试,把 AVDD 在 ±5% 范围内扫一遍,确认读数变化在允许误差内。这两步能筛掉大部分焊接不良和退耦电容选型错误的问题。

最后说一个我自己的习惯:每次改完驱动,先不接真实传感器,用信号源给一个 1 mV 的直流信号,看读数的峰峰值。如果峰峰值超过数据手册里对应采样率的 RMS 噪声的 6 倍,说明驱动里还有时序或配置问题,别急着往下做算法。这个习惯帮我省过至少三次“以为是算法问题、其实是驱动没配对”的返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询