简介:这份资源是面向STM32F103平台、针对AD7124高精度ADC芯片的完整驱动代码工程,适合正在调试该芯片却苦于缺少参考的嵌入式开发者与新手。作者基于Keil5环境,采用模拟SPI方式实现通信,测试代码聚焦6通道、双极性、全功率采样并启用外部参考电压,未堆砌冗余功能,工程已全部调通,可直接作为可靠起点。压缩包共215个文件,约6.18MB,包含35个c源文件、38个h头文件及大量编译中间产物(d、o、crf等),另有uvprojx工程文件、map映射文件、hex烧录文件与sct分散加载配置,覆盖从源码到可执行输出的完整链路。目前已有6215人学习下载,热度较高。读者可借此省去从零摸索寄存器时序与采样配置的时间,快速理解AD7124在STM32F103上的驱动框架与排错思路,降低调试门槛。1. 拿到一份「已全部调通」的 AD7124 驱动,先别急着烧录手上这份 AD7124 驱动代码,基于 STM32F103,标题写着「已全部调通」。做过高精度采集的人都知道,这句话含金量不低——AD7124 这颗 24 位 Σ-Δ ADC,寄存器多、模式多、时序讲究,SPI 读回来全是 0xFFFFFF 或者 0x000000 是常态。它解决的是小信号、高分辨率、多通道差分采集的场景,比如称重、热电偶、RTD、压力桥路。适合谁?适合已经能跑通 STM32 基础 SPI、但被 AD7124 的配置寄存器和校准流程卡住的嵌入式工程师。但「调通」是别人的板子调通,换到你的硬件上,第一件事不是烧录,而是先搞清楚这份代码的配置假设和你的电路差在哪。2. AD7124 驱动骨架拆解:SPI 时序、寄存器映射与状态机2.1 为什么 AD7124 不能当普通 SPI 从机用很多人第一反应是拿 STM32 的硬件 SPI 直接怼上去,结果读 ID 都读不对。AD7124 的 SPI 有几个硬性约束:CPOL=1、CPHA=1,也就是空闲时钟高电平、第二个边沿采样。STM32F103 的 SPI1 配成SPI_CPOL_High | SPI_CPHA_2Edge才对得上。另外它的通信寄存器是 8 位,但数据寄存器是 24 位,读写要按「先写通信寄存器选目标寄存器,再连续读/写 N 字节」的节奏走。如果你用 HAL 的HAL_SPI_TransmitReceive一次性发 4 字节,大概率错位。常见做法是封装两个底层函数:一个写通信寄存器,一个读写数据。我一般会把 CS 拉低、发通信字、再操作数据、最后拉高 CS 这一整套放在一个函数里,避免中间被中断打断导致帧错位。// AD7124 底层读写:通信寄存器 + 数据寄存器 // hspi: 已配置为 CPOL=1, CPHA=1, 软件 NSS // addr: 寄存器地址(0x00~0x3F), rw: 0写 1读, len: 数据字节数(1~3) uint8_t AD7124_ReadReg(SPI_HandleTypeDef *hspi, uint8_t addr, uint8_t *buf, uint8_t len) { uint8_t comm = (addr << 2) | 0x40; // bit7=0 写通信寄存器, bit6=1 读操作 uint8_t dummy = 0xFF; HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi, &comm, 1, 100); // 先写通信寄存器 for (uint8_t i = 0; i < len; i++) { HAL_SPI_TransmitReceive(hspi, &dummy, &buf[i], 1, 100); // 逐字节读 } HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_SET); return 0; }逻辑说明:通信寄存器 bit7 固定为 0(写通信寄存器),bit6 是读写标志,bit5~0 是寄存器地址。读操作时 bit6 置 1。参数len根据目标寄存器决定——状态寄存器 1 字节,配置寄存器 2 字节,数据寄存器 3 字节。注意每次操作都要完整拉 CS,不能中途松手。2.2 寄存器初始化顺序:别跳步,跳了就等着读全 0AD7124 上电后必须按固定顺序配置,顺序错了它不报错,只是默默给你垃圾数据。这份驱动的初始化流程大致是:复位 → 读 ID 确认通信 → 配置各通道 → 配置 ADC 控制寄存器 → 配置滤波器 → 使能通道 → 启动转换。复位有两种:硬件复位(拉 RESET 引脚)和软件复位(连续写 64 个 1)。代码里一般用软件复位,省一个 IO。复位后所有寄存器回默认值,此时读 ID 寄存器应该得到 0x14(AD7124-8)或 0x16(AD7124-4),这个值对不上,后面全白搭。// 软件复位 + ID 校验 void AD7124_Reset(SPI_HandleTypeDef *hspi) { uint8_t tx[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_RESET); for (int i = 0; i < 8; i++) { HAL_SPI_Transmit(hspi, tx, 8, 100); // 连续 64 个 1 } HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_SET); HAL_Delay(1); // 等内部振荡器稳定 } uint8_t AD7124_CheckID(SPI_HandleTypeDef *hspi) { uint8_t id = 0; AD7124_ReadReg(hspi, 0x05, &id, 1); // ID 寄存器地址 0x05 return id; // 期望 0x14 或 0x16 }参数说明:复位后至少延时 1ms 再通信,内部振荡器起振需要时间。ID 寄存器低 4 位是版本,高 4 位是型号,判断时用(id & 0xF0)更稳。2.3 通道与滤波器配置:决定你读到的是不是有效值AD7124 有 8 个配置寄存器(AD7124-8),每个通道可以绑定一个配置。配置寄存器里最关键的是增益、基准源选择、输入缓冲。滤波器寄存器决定输出数据率和建立时间。很多人读出来的值跳得厉害,八成是滤波器没配对——Sinc4 滤波在 50Hz/60Hz 工频抑制上表现好,但建立时间长;单周期滤波快,但噪声大。参数典型值影响增益1~128小信号必须放大,但放大后满量程缩小基准源内部 2.5V / 外部 REFIN内部基准温漂大,精密场合用外部滤波类型Sinc4 / 单周期Sinc4 抑工频,单周期快输出速率10SPS~19200SPS越低越稳,越高越跳建立时间与滤波和速率相关切换通道后要等建立完再读配置通道时,先写配置寄存器,再写通道寄存器把通道映射到配置,最后使能通道。顺序反了,通道使能时配置还没生效,读出来就是默认增益 1、内部基准,小信号直接淹在噪声里。3. 从零跑通采集:STM32F103 工程搭建与实测步骤3.1 工程文件组织与 CubeMX 关键配置拿到代码包,先别一股脑塞进现有工程。我一般会新建一个ad7124_driver分组,把驱动文件(ad7124.c/ad7124.h)和板级支持(ad7124_port.c)分开。驱动层不碰 HAL 具体外设,只依赖几个函数指针或宏,这样换 MCU 只改 port 层。CubeMX 里 SPI1 配置:Mode 选 Full-Duplex Master,Data Size 8 Bits,CPOL High,CPHA 2Edge,NSS 选 Software,Prescaler 先设 64(约 1.1MHz),AD7124 最高支持 5MHz,但 F103 走线长时降速更稳。GPIO 里把 CS 和 RESET 配成推挽输出,初始电平都拉高。// ad7124_port.h 里做硬件抽象 #define ADC_CS_PORT GPIOA #define ADC_CS_PIN GPIO_PIN_4 #define ADC_RESET_PORT GPIOA #define ADC_RESET_PIN GPIO_PIN_3 #define ADC_SPI_HANDLE hspi1这样驱动里只调AD7124_ReadReg(&ADC_SPI_HANDLE, ...),换板子只改这个头文件。3.2 单通道连续采集的完整调用链跑通的最小闭环是:初始化 → 配通道 0 → 启动连续转换 → 等 RDY 引脚或查状态寄存器 → 读数据 → 转电压。RDY 引脚接法看你的板子,没接就用状态寄存器的 RDY 位轮询。void AD7124_SetupChannel0(void) { uint8_t cfg[2] = {0x00, 0x00}; // 配置寄存器: 增益1, 内部基准, 缓冲开 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x19, cfg, 2); // CFG0 地址 0x19 uint8_t ch[2] = {0x01, 0x80}; // 通道0: 使能, 接 AIN0/AIN1 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x09, ch, 2); // CH0 地址 0x09 uint8_t filt[3] = {0x00, 0x00, 0x60}; // 滤波器: Sinc4, 输出速率约 10SPS AD7124_WriteReg(&ADC_SPI_HANDLE, 0x21, filt, 3); // FILT0 地址 0x21 uint8_t adc_ctrl[2] = {0x00, 0x0C}; // 连续转换模式, 内部基准使能 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x01, adc_ctrl, 2); // ADC_CTRL 地址 0x01 } int32_t AD7124_ReadData(void) { uint8_t raw[3] = {0}; uint8_t status = 0; do { AD7124_ReadReg(&ADC_SPI_HANDLE, 0x00, &status, 1); // 状态寄存器 } while (status & 0x80); // 等 RDY 位变低 AD7124_ReadReg(&ADC_SPI_HANDLE, 0x02, raw, 3); // 数据寄存器 0x02 int32_t code = ((int32_t)raw[0] << 16) | ((int32_t)raw[1] << 8) | raw[2]; if (code & 0x800000) code |= 0xFF000000; // 24 位补码转 32 位 return code; }逻辑说明:状态寄存器 bit7 是 RDY,低电平有效,所以while (status & 0x80)是等它变 0。数据寄存器是 24 位,读回来要拼成 int32 并做符号扩展。电压换算:V = code * VREF / (增益 * 2^23),内部基准 2.5V、增益 1 时,满量程约 ±2.5V。3.3 用已知电压验证:别信「能读数」,要信「读得准」跑通不代表读准。我一般会拿一个基准电压源或者分压后的电池电压做验证。比如用两节干电池分压到 1.0V 左右,接 AIN0/AIN1,读回来换算成电压,和万用表对比。偏差在几个 LSB 以内算正常,偏差几百 mV 就是配置错了。验证步骤:先短接 AIN0 和 AIN1,读出来应该接近 0(有几十个 LSB 的失调正常);再接入已知电压,看线性度。如果短接都读几百 mV,检查增益和基准配置;如果读数乱跳,检查滤波器和 SPI 速率。提示:AD7124 的模拟输入范围是±VREF/增益,差分输入时 AIN0 和 AIN1 都要在允许的共模范围内,超了读出来是满量程或负满量程,不是真实值。4. 避坑与排查:调 AD7124 最容易翻车的五个地方4.1 读回来全是 0xFFFFFF 或 0x000000现象:初始化后读数据寄存器,永远是满量程或零。原因:SPI 模式不对,或者通信寄存器写错导致根本没选中数据寄存器。解决:先用示波器看 CS、SCLK、MOSI 波形,确认 CPOL/CPHA;再单独读 ID 寄存器,ID 不对就先修通信,别往下走。4.2 读数跳得厉害,像随机数现象:电压值上下跳几百个 LSB。原因:滤波器输出速率设太高,或者基准源用了内部基准且没使能缓冲。解决:把输出速率降到 10SPS 或更低,滤波器选 Sinc4;基准改外部 REFIN,并在配置寄存器里打开基准缓冲。4.3 切换通道后第一笔数据是错的现象:多通道轮询时,刚切过去的通道读出来是上一个通道的值。原因:Σ-Δ ADC 切换通道后有建立时间,没等建立完就读。解决:切换通道后丢弃第一笔或前两笔数据,或者查状态寄存器的 RDY 位等它真正更新。4.4 校准后反而更不准现象:跑了内部零刻度校准和满刻度校准,结果偏差更大。原因:校准时的输入条件不对,零刻度校准要求输入短接,满刻度校准要求输入接近满量程。解决:校准前先把输入接到对应电平,校准完再切回正常测量;或者干脆用系统校准,在已知信号下算修正系数。4.5 长时间运行后数据漂移现象:跑几小时后读数慢慢偏。原因:内部基准温漂,或者芯片自热。解决:换外部基准,降低激励电流,PCB 上模拟部分远离发热源。AD7124 本身功耗不高,但配置成高增益、高速度时功耗上去了,自热会影响精度。5. 进阶:把这份驱动改成多通道轮询 + 软件滤波的稳定采集单通道跑通只是起点,实际项目多半是多通道轮询。AD7124 支持序列器模式,可以自动按顺序扫多个通道,但配置起来寄存器操作多,调试时容易乱。我一般先用软件轮询:手动切通道、等建立、读数据,逻辑清晰,出问题好定位。多通道的关键是维护一个通道-配置映射表,每个通道有自己的增益和滤波需求。比如通道 0 接称重传感器要增益 128,通道 1 接 RTD 要增益 16,那就配两个配置寄存器,通道寄存器分别指向它们。切换时先写通道寄存器,再等建立时间,再读。typedef struct { uint8_t ch_reg_val; // 通道寄存器值 uint8_t cfg_idx; // 绑定的配置索引 uint8_t settle_cnt; // 需要丢弃的样本数 } AD7124_ChannelMap; AD7124_ChannelMap ch_map[2] = { {0x01, 0, 2}, // 通道0, 配置0, 丢2笔 {0x02, 1, 2}, // 通道1, 配置1, 丢2笔 }; int32_t AD7124_ScanChannel(uint8_t idx) { AD7124_WriteReg(&ADC_SPI_HANDLE, 0x09, &ch_map[idx].ch_reg_val, 2); for (int i = 0; i < ch_map[idx].settle_cnt; i++) { AD7124_ReadData(); // 丢弃建立期样本 } return AD7124_ReadData(); }软件滤波方面,我习惯在驱动上层加一个滑动平均或中值滤波。AD7124 本身输出速率低的时候噪声已经很小,但工频干扰残留还是有的。滑动平均窗口取 8 或 16,对缓变信号效果好;如果信号有突变,中值滤波更合适。别在驱动层做滤波,放应用层,方便调参。验证方法:拿一个标准信号源,或者用高精度万用表对比,跑 24 小时看漂移。我一般会记录每小时的平均值和标准差,标准差突然变大就是有干扰进来了。从那以后我每次改滤波器参数,都强制先跑一遍短接和满量程两点验证,确认没翻车再上真实信号。希望帮到你。本文还有配套的精品资源,点击获取
简介:这份资源是面向STM32F103平台、针对AD7124高精度ADC芯片的完整驱动代码工程,适合正在调试该芯片却苦于缺少参考的嵌入式开发者与新手。作者基于Keil5环境,采用模拟SPI方式实现通信,测试代码聚焦6通道、双极性、全功率采样并启用外部参考电压,未堆砌冗余功能,工程已全部调通,可直接作为可靠起点。压缩包共215个文件,约6.18MB,包含35个c源文件、38个h头文件及大量编译中间产物(d、o、crf等),另有uvprojx工程文件、map映射文件、hex烧录文件与sct分散加载配置,覆盖从源码到可执行输出的完整链路。目前已有6215人学习下载,热度较高。读者可借此省去从零摸索寄存器时序与采样配置的时间,快速理解AD7124在STM32F103上的驱动框架与排错思路,降低调试门槛。1. 拿到一份「已全部调通」的 AD7124 驱动,先别急着烧录手上这份 AD7124 驱动代码,基于 STM32F103,标题写着「已全部调通」。做过高精度采集的人都知道,这句话含金量不低——AD7124 这颗 24 位 Σ-Δ ADC,寄存器多、模式多、时序讲究,SPI 读回来全是 0xFFFFFF 或者 0x000000 是常态。它解决的是小信号、高分辨率、多通道差分采集的场景,比如称重、热电偶、RTD、压力桥路。适合谁?适合已经能跑通 STM32 基础 SPI、但被 AD7124 的配置寄存器和校准流程卡住的嵌入式工程师。但「调通」是别人的板子调通,换到你的硬件上,第一件事不是烧录,而是先搞清楚这份代码的配置假设和你的电路差在哪。2. AD7124 驱动骨架拆解:SPI 时序、寄存器映射与状态机2.1 为什么 AD7124 不能当普通 SPI 从机用很多人第一反应是拿 STM32 的硬件 SPI 直接怼上去,结果读 ID 都读不对。AD7124 的 SPI 有几个硬性约束:CPOL=1、CPHA=1,也就是空闲时钟高电平、第二个边沿采样。STM32F103 的 SPI1 配成SPI_CPOL_High | SPI_CPHA_2Edge才对得上。另外它的通信寄存器是 8 位,但数据寄存器是 24 位,读写要按「先写通信寄存器选目标寄存器,再连续读/写 N 字节」的节奏走。如果你用 HAL 的HAL_SPI_TransmitReceive一次性发 4 字节,大概率错位。常见做法是封装两个底层函数:一个写通信寄存器,一个读写数据。我一般会把 CS 拉低、发通信字、再操作数据、最后拉高 CS 这一整套放在一个函数里,避免中间被中断打断导致帧错位。// AD7124 底层读写:通信寄存器 + 数据寄存器 // hspi: 已配置为 CPOL=1, CPHA=1, 软件 NSS // addr: 寄存器地址(0x00~0x3F), rw: 0写 1读, len: 数据字节数(1~3) uint8_t AD7124_ReadReg(SPI_HandleTypeDef *hspi, uint8_t addr, uint8_t *buf, uint8_t len) { uint8_t comm = (addr << 2) | 0x40; // bit7=0 写通信寄存器, bit6=1 读操作 uint8_t dummy = 0xFF; HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi, &comm, 1, 100); // 先写通信寄存器 for (uint8_t i = 0; i < len; i++) { HAL_SPI_TransmitReceive(hspi, &dummy, &buf[i], 1, 100); // 逐字节读 } HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_SET); return 0; }逻辑说明:通信寄存器 bit7 固定为 0(写通信寄存器),bit6 是读写标志,bit5~0 是寄存器地址。读操作时 bit6 置 1。参数len根据目标寄存器决定——状态寄存器 1 字节,配置寄存器 2 字节,数据寄存器 3 字节。注意每次操作都要完整拉 CS,不能中途松手。2.2 寄存器初始化顺序:别跳步,跳了就等着读全 0AD7124 上电后必须按固定顺序配置,顺序错了它不报错,只是默默给你垃圾数据。这份驱动的初始化流程大致是:复位 → 读 ID 确认通信 → 配置各通道 → 配置 ADC 控制寄存器 → 配置滤波器 → 使能通道 → 启动转换。复位有两种:硬件复位(拉 RESET 引脚)和软件复位(连续写 64 个 1)。代码里一般用软件复位,省一个 IO。复位后所有寄存器回默认值,此时读 ID 寄存器应该得到 0x14(AD7124-8)或 0x16(AD7124-4),这个值对不上,后面全白搭。// 软件复位 + ID 校验 void AD7124_Reset(SPI_HandleTypeDef *hspi) { uint8_t tx[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_RESET); for (int i = 0; i < 8; i++) { HAL_SPI_Transmit(hspi, tx, 8, 100); // 连续 64 个 1 } HAL_GPIO_WritePin(ADC_CS_PORT, ADC_CS_PIN, GPIO_PIN_SET); HAL_Delay(1); // 等内部振荡器稳定 } uint8_t AD7124_CheckID(SPI_HandleTypeDef *hspi) { uint8_t id = 0; AD7124_ReadReg(hspi, 0x05, &id, 1); // ID 寄存器地址 0x05 return id; // 期望 0x14 或 0x16 }参数说明:复位后至少延时 1ms 再通信,内部振荡器起振需要时间。ID 寄存器低 4 位是版本,高 4 位是型号,判断时用(id & 0xF0)更稳。2.3 通道与滤波器配置:决定你读到的是不是有效值AD7124 有 8 个配置寄存器(AD7124-8),每个通道可以绑定一个配置。配置寄存器里最关键的是增益、基准源选择、输入缓冲。滤波器寄存器决定输出数据率和建立时间。很多人读出来的值跳得厉害,八成是滤波器没配对——Sinc4 滤波在 50Hz/60Hz 工频抑制上表现好,但建立时间长;单周期滤波快,但噪声大。参数典型值影响增益1~128小信号必须放大,但放大后满量程缩小基准源内部 2.5V / 外部 REFIN内部基准温漂大,精密场合用外部滤波类型Sinc4 / 单周期Sinc4 抑工频,单周期快输出速率10SPS~19200SPS越低越稳,越高越跳建立时间与滤波和速率相关切换通道后要等建立完再读配置通道时,先写配置寄存器,再写通道寄存器把通道映射到配置,最后使能通道。顺序反了,通道使能时配置还没生效,读出来就是默认增益 1、内部基准,小信号直接淹在噪声里。3. 从零跑通采集:STM32F103 工程搭建与实测步骤3.1 工程文件组织与 CubeMX 关键配置拿到代码包,先别一股脑塞进现有工程。我一般会新建一个ad7124_driver分组,把驱动文件(ad7124.c/ad7124.h)和板级支持(ad7124_port.c)分开。驱动层不碰 HAL 具体外设,只依赖几个函数指针或宏,这样换 MCU 只改 port 层。CubeMX 里 SPI1 配置:Mode 选 Full-Duplex Master,Data Size 8 Bits,CPOL High,CPHA 2Edge,NSS 选 Software,Prescaler 先设 64(约 1.1MHz),AD7124 最高支持 5MHz,但 F103 走线长时降速更稳。GPIO 里把 CS 和 RESET 配成推挽输出,初始电平都拉高。// ad7124_port.h 里做硬件抽象 #define ADC_CS_PORT GPIOA #define ADC_CS_PIN GPIO_PIN_4 #define ADC_RESET_PORT GPIOA #define ADC_RESET_PIN GPIO_PIN_3 #define ADC_SPI_HANDLE hspi1这样驱动里只调AD7124_ReadReg(&ADC_SPI_HANDLE, ...),换板子只改这个头文件。3.2 单通道连续采集的完整调用链跑通的最小闭环是:初始化 → 配通道 0 → 启动连续转换 → 等 RDY 引脚或查状态寄存器 → 读数据 → 转电压。RDY 引脚接法看你的板子,没接就用状态寄存器的 RDY 位轮询。void AD7124_SetupChannel0(void) { uint8_t cfg[2] = {0x00, 0x00}; // 配置寄存器: 增益1, 内部基准, 缓冲开 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x19, cfg, 2); // CFG0 地址 0x19 uint8_t ch[2] = {0x01, 0x80}; // 通道0: 使能, 接 AIN0/AIN1 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x09, ch, 2); // CH0 地址 0x09 uint8_t filt[3] = {0x00, 0x00, 0x60}; // 滤波器: Sinc4, 输出速率约 10SPS AD7124_WriteReg(&ADC_SPI_HANDLE, 0x21, filt, 3); // FILT0 地址 0x21 uint8_t adc_ctrl[2] = {0x00, 0x0C}; // 连续转换模式, 内部基准使能 AD7124_WriteReg(&ADC_SPI_HANDLE, 0x01, adc_ctrl, 2); // ADC_CTRL 地址 0x01 } int32_t AD7124_ReadData(void) { uint8_t raw[3] = {0}; uint8_t status = 0; do { AD7124_ReadReg(&ADC_SPI_HANDLE, 0x00, &status, 1); // 状态寄存器 } while (status & 0x80); // 等 RDY 位变低 AD7124_ReadReg(&ADC_SPI_HANDLE, 0x02, raw, 3); // 数据寄存器 0x02 int32_t code = ((int32_t)raw[0] << 16) | ((int32_t)raw[1] << 8) | raw[2]; if (code & 0x800000) code |= 0xFF000000; // 24 位补码转 32 位 return code; }逻辑说明:状态寄存器 bit7 是 RDY,低电平有效,所以while (status & 0x80)是等它变 0。数据寄存器是 24 位,读回来要拼成 int32 并做符号扩展。电压换算:V = code * VREF / (增益 * 2^23),内部基准 2.5V、增益 1 时,满量程约 ±2.5V。3.3 用已知电压验证:别信「能读数」,要信「读得准」跑通不代表读准。我一般会拿一个基准电压源或者分压后的电池电压做验证。比如用两节干电池分压到 1.0V 左右,接 AIN0/AIN1,读回来换算成电压,和万用表对比。偏差在几个 LSB 以内算正常,偏差几百 mV 就是配置错了。验证步骤:先短接 AIN0 和 AIN1,读出来应该接近 0(有几十个 LSB 的失调正常);再接入已知电压,看线性度。如果短接都读几百 mV,检查增益和基准配置;如果读数乱跳,检查滤波器和 SPI 速率。提示:AD7124 的模拟输入范围是±VREF/增益,差分输入时 AIN0 和 AIN1 都要在允许的共模范围内,超了读出来是满量程或负满量程,不是真实值。4. 避坑与排查:调 AD7124 最容易翻车的五个地方4.1 读回来全是 0xFFFFFF 或 0x000000现象:初始化后读数据寄存器,永远是满量程或零。原因:SPI 模式不对,或者通信寄存器写错导致根本没选中数据寄存器。解决:先用示波器看 CS、SCLK、MOSI 波形,确认 CPOL/CPHA;再单独读 ID 寄存器,ID 不对就先修通信,别往下走。4.2 读数跳得厉害,像随机数现象:电压值上下跳几百个 LSB。原因:滤波器输出速率设太高,或者基准源用了内部基准且没使能缓冲。解决:把输出速率降到 10SPS 或更低,滤波器选 Sinc4;基准改外部 REFIN,并在配置寄存器里打开基准缓冲。4.3 切换通道后第一笔数据是错的现象:多通道轮询时,刚切过去的通道读出来是上一个通道的值。原因:Σ-Δ ADC 切换通道后有建立时间,没等建立完就读。解决:切换通道后丢弃第一笔或前两笔数据,或者查状态寄存器的 RDY 位等它真正更新。4.4 校准后反而更不准现象:跑了内部零刻度校准和满刻度校准,结果偏差更大。原因:校准时的输入条件不对,零刻度校准要求输入短接,满刻度校准要求输入接近满量程。解决:校准前先把输入接到对应电平,校准完再切回正常测量;或者干脆用系统校准,在已知信号下算修正系数。4.5 长时间运行后数据漂移现象:跑几小时后读数慢慢偏。原因:内部基准温漂,或者芯片自热。解决:换外部基准,降低激励电流,PCB 上模拟部分远离发热源。AD7124 本身功耗不高,但配置成高增益、高速度时功耗上去了,自热会影响精度。5. 进阶:把这份驱动改成多通道轮询 + 软件滤波的稳定采集单通道跑通只是起点,实际项目多半是多通道轮询。AD7124 支持序列器模式,可以自动按顺序扫多个通道,但配置起来寄存器操作多,调试时容易乱。我一般先用软件轮询:手动切通道、等建立、读数据,逻辑清晰,出问题好定位。多通道的关键是维护一个通道-配置映射表,每个通道有自己的增益和滤波需求。比如通道 0 接称重传感器要增益 128,通道 1 接 RTD 要增益 16,那就配两个配置寄存器,通道寄存器分别指向它们。切换时先写通道寄存器,再等建立时间,再读。typedef struct { uint8_t ch_reg_val; // 通道寄存器值 uint8_t cfg_idx; // 绑定的配置索引 uint8_t settle_cnt; // 需要丢弃的样本数 } AD7124_ChannelMap; AD7124_ChannelMap ch_map[2] = { {0x01, 0, 2}, // 通道0, 配置0, 丢2笔 {0x02, 1, 2}, // 通道1, 配置1, 丢2笔 }; int32_t AD7124_ScanChannel(uint8_t idx) { AD7124_WriteReg(&ADC_SPI_HANDLE, 0x09, &ch_map[idx].ch_reg_val, 2); for (int i = 0; i < ch_map[idx].settle_cnt; i++) { AD7124_ReadData(); // 丢弃建立期样本 } return AD7124_ReadData(); }软件滤波方面,我习惯在驱动上层加一个滑动平均或中值滤波。AD7124 本身输出速率低的时候噪声已经很小,但工频干扰残留还是有的。滑动平均窗口取 8 或 16,对缓变信号效果好;如果信号有突变,中值滤波更合适。别在驱动层做滤波,放应用层,方便调参。验证方法:拿一个标准信号源,或者用高精度万用表对比,跑 24 小时看漂移。我一般会记录每小时的平均值和标准差,标准差突然变大就是有干扰进来了。从那以后我每次改滤波器参数,都强制先跑一遍短接和满量程两点验证,确认没翻车再上真实信号。希望帮到你。本文还有配套的精品资源,点击获取