简介:基于STM32硬件SPI接口驱动AD7124模数转换芯片的完整源码包,面向有一定STM32基础、需要快速集成高精度ADC的嵌入式开发者,适用于工业数据采集、精密测量等多通道低噪声信号链场景。代码将底层SPI通信与AD7124寄存器读写封装为清晰模块,提供寄存器读取、写入及免检测读写等接口,便于理解硬件SPI时序、寄存器配置流程和驱动分层思路,可直接移植到Keil、IAR等工程中复用。压缩包约9KB,共7个文件,由4个头文件和3个C源文件组成,头文件集中定义寄存器映射与对外接口,C文件承担SPI初始化、通信收发和寄存器操作实现,代码体量小且结构精简。资源已有673人学习,适合用来对照学习STM32硬件SPI外设的驱动写法,也能作为AD7124多通道高精度采集方案的参考模板,帮助开发者缩短驱动调试与验证周期。
1. 用 STM32 硬件 SPI 驱动 AD7124:先弄懂它和普通 ADC 源码包差在哪
做称重仪表或者热电偶采集的人,大概率都下载过这类“基于 stm32 硬件 SPI 接口驱动 AD7124 程序源代码.zip”。AD7124 是 ADI 的 24 位 Σ-Δ 型模数转换芯片,自带 PGA 可编程增益,能接应变桥、热电阻、热电偶,比普通 16 位逐次逼近型 ADC 精度高一个量级,但代价是初始化配置非常敏感。你从压缩包里解出来的代码,往往最值钱的不是 main 里那几行读数据逻辑,而是寄存器初始化序列、复位时序和 DOUT/DRDY 就绪引脚的处理方式。我用硬件 SPI 而不是模拟 SPI 去驱动它,就是因为 AD7124 的 SPI 帧要求 CS 低电平期间连续传完命令字节和数据字节,模拟翻转一旦被中断打断,整帧数据就废了。这篇就按这个源码包的常见结构,从前到后拆清楚哪些能直接抄、哪些参数必须自己核对,以及我调这类板子时踩过的几个真坑。
2. STM32 硬件 SPI 接 AD7124:CubeMX 参数、上拉和片选方案
2.1 AD7124 引脚和供电:先弄清参考电压与上拉
AD7124 常见型号是 AD7124-4 和 AD7124-8,前者 4 组差分输入,后者 8 组差分输入,寄存器操作完全一样,只是通道数和芯片 ID 不同。驱动这块芯片,第一件事不是写代码,而是看供电和参考电压。AVDD 我一般接 3.3V 经过 LC 滤波后的电源,DVDD 也接 3.3V,模拟地数字地单点汇合,不要在芯片下方直接铺成一块大铜皮。REFIN1+ 和 REFIN1- 接外部基准,最常用的是 ADR4525 这类低噪声 2.5V 基准,REFIN 两端各放一个 0.1μF 陶瓷电容,靠近 REFCAP 引脚再加一个 1μF 电容。
DOUT/DRDY 是复用引脚,它既是 SPI 数据输出 MISO,又是转换完成标志。数据准备好时这个引脚会拉低,主机轮询到低电平就可以读数据寄存器。因为这个引脚在芯片上电初期可能是高阻态,我习惯在 PCB 上给它加一个 10kΩ 上拉到 3.3V,防止主控端误判。SDI、SCLK、CS 三个引脚不需要上拉,主控直接推挽输出就行。
接线表如下:
| STM32 引脚 | AD7124 引脚 | 说明 |
|---|---|---|
| SPI_SCK | SCLK | SPI 时钟 |
| SPI_MOSI | SDI | 主机发送,从机接收 |
| SPI_MISO | DOUT/DRDY | 数据输出,兼转换完成标志 |
| 任意 GPIO | CS | 片选,软件控制 |
| 3.3V | AVDD / DVDD | 供电 |
| GND | AGND / DGND | 共地 |
2.2 CubeMX 里 STM32 硬件 SPI 的 5 个关键参数
打开 STM32CubeMX 配置 SPI 外设时,我最常被问到的就是“为什么按网上配置还是读不出 ID”。其实 SPI 模式就五个参数:主机模式、全双工、8 位数据、MSB 在前、禁止硬件 CRC。时钟极性 CPOL 和相位 CPHA 最容易翻车,我的调试起点是 CPOL=Low、CPHA=1Edge,也就是 SPI Mode 0,SCLK 空闲为低,数据在第一个边沿采样。如果读 ID 失败,再切到 CPHA=2Edge 试一次,一次就能定位是相位问题还是复位问题。
时钟分频一开始不要设太快。STM32 的 SPI 外设时钟通常是 APB 总线时钟,我调试期先选 64 分频,让 SCLK 落在 1MHz 上下,等读写正常后再提到 8 分频。AD7124 手册标称 SCLK 上限很高,但实际板子上走线、容性负载都会影响高速时序,先慢后快是这类高精度 ADC 的通用调试顺序。NSS 引脚选软件管理,关闭硬件片选。CubeMX 配置片段如下:
hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; HAL_SPI_Init(&hspi1);这里有一个我反复跟人强调的点:不要一上来就开 SPI 的硬件 CRC。AD7124 本身支持 SPI CRC 校验,但那是芯片端使能选项,和 STM32 外设的 CRC 是两回事。初版代码先把两边 CRC 全部关掉,等数据通路稳定了再考虑开启,否则你会在排查 CRC 错误和排查时序错误之间来回浪费时间。
2.3 片选用 GPIO 还是硬件 NSS:这个开关别偷懒
网上很多 STM32 SPI 例程喜欢用硬件 NSS 片选,但驱动 AD7124 时我强烈建议改成普通 GPIO 软件片选。原因在于 AD7124 的每次访问都是一个完整帧:CS 拉低,发送命令字节,再发送或接收数据字节,最后 CS 拉高。STM32 硬件 NSS 在多字节传输时的行为不完全可控,尤其是帧与帧之间的拉高时机,稍有不慎就会把一次寄存器读写在中间拆成两段,芯片直接忽略整条命令。
GPIO 软件片选的初始化代码很简单:
GPIO_InitStruct.Pin = ADC_CS_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(ADC_CS_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = ADC_DRDY_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(ADC_DRDY_PORT, &GPIO_InitStruct); ADC_CS_HIGH();CS 默认拉高,每次操作前拉低,操作完成后拉高。注意 CS 拉高后到下一次拉低之间要留一点时间,也就是手册里的 t8 参数,别刚拉高就立刻进行下一次访问。这个延时在低速 SCLK 下可以忽略,但把 SCLK 提到 10MHz 以上后必须显式加几微秒等待。很多从 zip 里直接抄来的代码没有这个细节,批量生产时偶发读写失败,根源就在这里。
3. 寄存器读写底座:复位序列、读 ID 校验和 32 位数据拼装
3.1 用悬空读 ID 验证 SPI 通路的 5 行命令
拿到一个新的 AD7124 板子,我第一步不是配通道,而是复位然后读 ID 寄存器。这一步能同时验证 SPI 时序、引脚映射、供电是否正常,相当于整个驱动的地基。AD7124 的 ID 寄存器地址是 0x06,读回的 32 位数据低字节是芯片 ID,不同型号的值不一样,以手册 Device ID Table 为准。
如果读 ID 返回 0xFF,说明 SPI 上根本没读到数据,要么 MOSI/MISO 接反,要么时钟相位不对,要么芯片没复位成功。如果返回 0x00,先查 CS 是否一直没拉低,或者 AD7124 的 DVDD 没供上。如果读到的值看起来像 ID 但又不对,多半是寄存器地址命令字节写错了,注意读命令最高位必须是 1。
uint8_t ad7124_check_id(void) { uint32_t raw = ad7124_read_reg(0x06); /* 0x06 = ID 寄存器 */ return (uint8_t)(raw & 0xFF); }这段代码逻辑上只有一个动作:发读命令,读 4 字节,取最低字节。但它背后的含义是整条 SPI 通路已经打通。我会在初始化函数里这样用:如果读 ID 回来不是预期值,直接 return,不继续配置后面的寄存器,免得在一堆假数据里找问题。
3.2 通用寄存器读写函数:命令字节与字节序
AD7124 的 SPI 访问分两步。第一步通过通信寄存器发一个 8 位命令字节,指定接下来要访问哪个寄存器、是读还是写。第二步才是真正的数据交换,寄存器数据都是 32 位,MSB 在前。命令字节的 bit7 是读写标志,1 为读,0 为写,bit6 到 bit0 是寄存器地址。所以写寄存器就是把命令字节和数据字节放在同一个 CS 低电平窗口内发出去。
读写函数的 HAL 实现如下:
uint8_t ad7124_make_cmd(uint8_t reg, uint8_t rw) { return (uint8_t)((rw ? 0x80 : 0x00) | (reg & 0x7F)); } void ad7124_write_reg(uint8_t reg, uint32_t val) { uint8_t cmd = ad7124_make_cmd(reg, 0); uint8_t buf[4]; buf[0] = (uint8_t)((val >> 24) & 0xFF); buf[1] = (uint8_t)((val >> 16) & 0xFF); buf[2] = (uint8_t)((val >> 8) & 0xFF); buf[3] = (uint8_t)(val & 0xFF); ADC_CS_LOW(); HAL_SPI_Transmit(&hspi1, &cmd, 1, 10); HAL_SPI_Transmit(&hspi1, buf, 4, 10); ADC_CS_HIGH(); } uint32_t ad7124_read_reg(uint8_t reg) { uint8_t cmd = ad7124_make_cmd(reg, 1); uint8_t buf[4] = {0}; ADC_CS_LOW(); HAL_SPI_Transmit(&hspi1, &cmd, 1, 10); HAL_SPI_Receive(&hspi1, buf, 4, 10); ADC_CS_HIGH(); return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; }这里有个 SPI 全双工的特点需要记住:读操作时,STM32 发命令字节的同时 MISO 上也会收到字节,那个字节是无效数据,丢掉即可。真正读数据时主机必须一直提供 SCLK,所以HAL_SPI_Receive底层其实也在发送,只是发送的内容我们不在乎。我也见过有人为了省事把读命令和读数据放在两个 CS 窗口里,结果读出来永远是 0,因为 AD7124 的命令字节只对当前这次 CS 低电平窗口有效,CS 一拉高,刚才指定的寄存器就失效了。
3.3 复位序列:上电后的第一件事
AD7124 的复位有两种常见做法:一种是向复位寄存器写数据,另一种是手册里的长帧复位序列。我实际项目里用的是后者,稳定且不需要查寄存器具体值:CS 拉低,连续发送 64 个 0xFF,然后 CS 拉高。芯片收到一长串连续 1 后自动复位,所有寄存器恢复默认值。
void ad7124_reset(void) { uint8_t ff = 0xFF; int i; ADC_CS_LOW(); for (i = 0; i < 64; i++) { HAL_SPI_Transmit(&hspi1, &ff, 1, 10); } ADC_CS_HIGH(); HAL_Delay(10); }这个复位序列最容易被忽略的是 CS 保持问题。有些人会把 CS 拉低、发一个字节、拉高,再拉低、发下一个字节,这样发满 64 个 0xFF,芯片是永远收不到完整复位序列的。CS 必须在整个复位序列期间保持低电平。复位完成后要延时至少 10ms,等待芯片内部上电复位完成,再开始读 ID。10ms 这个值我一般只增不减,电源启动慢的板子甚至要 50ms。
另一个细节:复位之后再读 ID,如果还是 0xFF,不要急着怀疑芯片坏了。先用示波器或逻辑分析仪抓一下 SCLK、MOSI、CS 三根线,确认波形确实发出去了,再检查 MISO 上有没有波形。我遇到过 SCLK 和 MOSI 都正常但 MISO 始终为高的板子,最后发现是 DOUT/DRDY 引脚虚焊,重新拖焊后立刻读到正确 ID。这种硬件问题靠改代码是解决不了的,尽早抓波形比反复调软件省时间。
4. AD7124 初始化:转换模式、通道使能、PGA 与滤波字怎么配
4.1 转换模式选连续还是单次,先关掉内部校准
AD7124 的 ADC 控制寄存器里有一个 Mode 字段,决定芯片工作在连续转换还是单次转换。连续转换模式下芯片不停采样,DOUT/DRDY 每次转换完成都会拉低,适合称重这种需要持续输出数据的场景。单次转换模式是写一次开始指令转一次,适合低功耗设备,转完就睡。我第一版驱动通常先用连续模式跑通,因为逻辑简单,等数据稳定后再按功耗需求切单次。
这里有一个新手很容易犯的错误:芯片出厂默认状态可能带着内部校准使能位,或者上一手代码把校准模式写进了寄存器。校准模式不是普通转换模式,它的输出不是测量结果,而是校准系数。如果发现读到的数据像噪声一样乱跳,先回头读一遍 ADC 控制寄存器,确认 Mode 字段真的是连续转换或单次转换,而不是校准。
uint32_t ad7124_adc_ctrl_value(uint32_t mode, uint32_t power) { uint32_t reg = 0; /* Mode 字段:0=连续转换,1=单次转换 */ reg |= (mode & 0x7) << 0; /* Power 字段:0=低功耗,1=中等功耗,2=全功耗 */ reg |= (power & 0x3) << 4; return reg; }注意我这里刻意没有把所有字段的位号写满,因为 AD7124 手册不同版本的位号描述有细节差异,直接从网上抄一个整字魔法数最容易翻车。正确做法是打开手册 ADC Control Register 一节,把 Mode、Power Mode、时钟源这几个字段按你的板子填好,再拼成整字写入。全功耗模式响应最快,但功耗也最高;电池供电设备就用低功耗模式,代价是输出数据速率上限降低。
4.2 通道寄存器与配置寄存器:AINP/AINN 和 SETUP 的对应关系
AD7124 的初始化流程里最容易绕晕的是通道寄存器、配置寄存器、滤波寄存器三者之间的关系。通道寄存器 0x09 到 0x18 负责选输入引脚和使能通道,配置寄存器 0x19 到 0x20 负责设置 PGA 增益、基准、单双极性,滤波寄存器 0x21 到 0x28 负责设置输出数据速率和滤波器类型。一个通道必须指定它使用哪个配置组,也就是 SETUP 字段。我习惯把通道 0 绑到 SETUP 0,通道 1 绑到 SETUP 1,一一对应,方便排查。
/* CH0:AIN0 接正端,AIN1 接负端,使能,绑定 SETUP 0 */ ad7124_write_reg(0x09, 0x00000083);这个 0x00000083 是怎么来的:最低位 1 表示通道使能,高位的 AINP 和 AINN 字段分别选了 AIN0 和 AIN1,中间 SETUP 字段是 0。不同输入引脚的组合对应不同数值,我强烈建议打开手册 Channel Register 表格按位填写,不要直接套我这个数。因为 AINP 编码从 0 到 15,AINN 也一样,稍微写错一位,采到的就不是你想接的那根引脚。
配置组里的 PGA 增益是 AD7124 的精髓。增益从 1 到 128 分档,每档对应不同编码,配置寄存器里 PGA 字段写 000 到 111。增益越高,能测的信号越微弱,但噪声也被放大,等效到输入端的噪声并不是一直改善的。热电偶信号通常只有几十微伏,必须开 64 或 128 倍增益;称重桥路输出几十毫伏,开 8 到 32 倍就够。我用 128 倍增益时遇到过电源纹波直接体现在输出里的问题,后来把 AVDD 换成低噪声 LDO 才解决。
4.3 输出数据速率与 SINC 滤波:25 SPS 与 128 倍 PGA 的搭配
滤波寄存器里最核心的是滤波字 FS 和 SINC 滤波器类型。AD7124 内置 SINC3 和 SINC4 两种数字滤波器,SINC4 对带外干扰抑制更好,SINC3 建立时间更快。对高精度测量,我默认用 SINC3,输出数据速率设在 25 SPS。这个速率下 50Hz 工频干扰能获得较好的抑制,尤其配合 128 倍 PGA 时,噪声指标比高速率模式好很多。如果只是测缓慢变化的温度,甚至可以降到 9.375 SPS。
滤波字和输出数据速率的关系受主时钟频率影响,同一滤波字在不同时钟下对应不同速率。网上很多源码包里的滤波寄存器整数,比如 0x060180,是基于 614.4kHz 主时钟、SINC3、25 SPS 算出来的。你如果换了外部晶振,或者芯片工作在内部时钟模式但时钟频率不同,这个值就不能直接用。我一般会先把主时钟确认清楚,再按手册公式算一遍滤波字,而不是盲目信任源码里的魔法数。
/* 滤波寄存器:0x06 段选 SINC3,0x0180 是滤波字,614.4kHz 下约 25SPS */ ad7124_write_reg(0x21, 0x060180);这段代码能跑,但它依赖一个前提:你的主时钟确实是 614.4kHz,且滤波器配置字段的位号和手册一致。验证方法很简单,配置完滤波寄存器后回读一次,确认写入值一致,再看实际输出数据速率是否符合预期。如果两个板子一个用内部时钟一个用外部时钟,同样的初始化序列会导致完全不同的输出速率,这属于硬件设计层面就要定好的事,改软件救不回来。
4.4 读取转换结果:轮询 DRDY 还是外部中断
数据准备好后,DOUT/DRDY 引脚拉低。读取方式两种:轮询或外部中断。我在第一版驱动里永远用轮询,因为逻辑简单,不依赖中断优先级配置,排查问题容易。主循环里等待 DRDY 变低,然后读数据寄存器,读完后 DOUT/DRDY 会自动回高。如果长时间等不到拉低,大概率是通道没使能或者转换模式配错了。
int32_t ad7124_read_result(void) { uint32_t raw; while (ADC_DRDY_READ() != GPIO_PIN_RESET) { /* 等待转换完成,可加超时保护 */ } raw = ad7124_read_reg(0x03); /* 0x03 = DATA 寄存器 */ raw >>= 8; /* 高 24 位是转换结果 */ if (raw & 0x800000) { raw |= 0xFF000000; /* 24 位有符号数扩展为 32 位 */ } return (int32_t)raw; }这段代码里有两个关键点。第一,温度寄存器读回的是 32 位,但有效转换结果只占高 24 位,低 8 位是状态或保留位,必须先右移 8 位。第二,AD7124 的转换结果是二进制补码格式,24 位有符号数的最高位是符号位,右移后需要手动扩展到 32 位,否则负数会变成一个很大的正数。如果发现零输入时读数飘在 0 附近但温度负向变化时读数变成 0xFFFFFF,基本就是符号扩展没做。
数据读取也可以换外部中断方式:把 DOUT/DRDY 接到 STM32 的 EXTI 引脚,下降沿触发中断,在中断服务函数里读数据。这种方式响应快,CPU 不用死等,但要注意中断服务函数里不能做耗时的寄存器回读验证,否则会影响 SPI 时序。我更推荐用 DMA 配合方式,后面单独说。等轮询方式完全跑通后,再优化成中断或 DMA,这样每一步出问题都知道改了什么。
5. 硬件 SPI 驱动 AD7124 的 5 个避坑记录:从读 ID 失败到噪声超标
5.1 读 ID 永远返回 0xFF:先查极性再查复位
现象是新建工程后,调用ad7124_check_id()返回值永远是 0xFF,根本不是我预期的型号 ID。这个坑我进了两次,第一次是 SPI 时钟相位配置错,第二次是复位序列 CS 时序不对。原因是 AD7124 的 MISO 在空闲时是高电平,读不到有效数据时 MISO 一直保持高,拼出来的 32 位数据自然全是 1。解决方法是先抓 SCLK 和 MISO 波形,确认 MISO 上有没有数据翻转;然后把 CubeMX 里的 CLKPhase 从 1Edge 改成 2Edge 再试一次;最后检查复位时 CS 是不是在整个 64 字节期间保持低。这三步做完,ID 基本就出来了。
5.2 数据始终为 0:通道没使能或 AINP/AINN 选错
现象是 ID 读正常,配置也写了,但读回来的数据一直是 0 附近纹丝不动。第一次遇到时我怀疑芯片坏了,换了一片还是 0,最后才发现通道寄存器里使能位没写。AD7124 的通道默认是禁用的,你配置了 SETUP 和滤波器还不够,必须先把对应通道的 EN 位置 1,并且 AINP、AINN 要选到你实际接线的引脚。解决的方法是回读通道寄存器,确认写进去的值和预期一致;再确认你配的通道号和后面读数据时使能的通道是同一个,别配了 CH0 去读 CH1 的数据。这种问题最好在初始化后加一个寄存器回读校验函数,所有关键寄存器写进去后立即读出来比对。
5.3 硬件片选导致的偶发读写失败:换成 GPIO 软件片选
现象是程序运行几分钟或几小时后,突然出现一次读数错误,复位后恢复正常。查了很久,SPI 波形和电源都正常,最后定位到 STM32 硬件 NSS 自动片选上。硬件 NSS 在 SPI 模块认为传输完成时会自动拉高 CS,但这个时机和 AD7124 期望的帧边界不匹配,尤其是 DMA 模式或多字节传输时有细微差别。解决方式很简单:CubeMX 里 NSS 选 Software,CS 用普通 GPIO 手动拉低拉高,确保命令字节和数据字节在同一个 CS 低窗口中。这是个架构层面的选择,不建议为了节省一个 GPIO 去用硬件 NSS。
5.4 读数据字节错位:CS 拉高太快或命令帧被截断
现象是能读到数据,但数值完全不对,连续读两次结果完全不一样,像是对齐出了问题。原因是 CS 在最后一次 SPI 传输完成后立刻拉高,而芯片内部还在把最后一位数据移入移位寄存器,你提前结束帧,最后一次传输的数据丢失了。解决方法是 CS 拉高前加一个极短延时,等 SPI 总线完全空闲;或者用HAL_SPI_TransmitReceive一次完成命令字节发送和数据接收,避免中间有额外延时。这类问题在 SCLK 高时特别明显,把 SCLK 降到 1MHz 再试,如果正常了,就说明是时序裕量不够。
5.5 128 倍增益时噪声大得离谱:供电和退耦先背锅
现象是 PGA 增益开到 64 或 128 时,输出噪声峰峰值达到几十微伏,完全达不到手册标称水平。最开始我怀疑是芯片质量问题,后来用示波器量 AVDD,发现有高频纹波,RC 滤波没起作用。原因是高增益下输入信号只有微伏级别,电源上任何纹波都会被放大。解决方法是把 AVDD 的 LC 滤波改为低噪声 LDO 供电,REFIN 引脚加去耦电容,并且 ADC 模拟地和数字地在芯片下方以单点连接。另一个容易被忽略的因素是 SCLK 信号串扰到模拟输入线上,SPI 线尽量远离 AIN 走线,必要时 AIN 周围加地保护。这个坑解决后噪声从几十微伏降到 1 微伏以内,属于整个驱动里收益最大的一次排查。
6. 验证 AD7124 链路:用短路输入和内部基准检查噪声与增益
6.1 短路输入的噪声峰峰值,是一切精度的前提
驱动跑通后先别急着接传感器,把 AIN0 和 AIN1 直接短接,连续采样 100 次,计算最大值和最小值的差,这个差值就是当前配置下的本底噪声峰峰值。如果这个值远大于手册上的典型值,后面的传感器标定都没意义。短接输入测试还能验证符号扩展代码有没有问题:理想情况下短接输入读数应该是 0 附近,如果读到满量程,说明双极性配置或基准选择写错了。
int32_t sample[100]; uint32_t i; int32_t vmax = -0x7FFFFFFF; int32_t vmin = 0x7FFFFFFF; for (i = 0; i < 100; i++) { sample[i] = ad7124_read_result(); if (sample[i] > vmax) vmax = sample[i]; if (sample[i] < vmin) vmin = sample[i]; } printf("p-p: %d LSB\r\n", (int)(vmax - vmin));这个测试里增益和滤波字都已经配置成你最终应用的参数。如果增益 1 时噪声几个 LSB,增益 128 时噪声几十个 LSB,是正常现象;但增益 1 时噪声上千 LSB,先回头查供电和布板。看到输出峰峰值符合预期后,再做满量程校准才有意义。
6.2 内部基准验证增益,校准寄存器写入顺序不能乱
AD7124 内置基准电压,但外部基准更稳。为了验证增益配置正确,我常把基准选择临时切到内部基准,然后在输入端接入一个从基准电阻分压得到的已知电压,计算换算结果。电压换算公式很简单:输入电压等于转换结果除以 2 的 23 次方,再乘以 PGA 增益分压后的满量程电压。比如 2.5V 基准、PGA 增益 1 时,满量程是 2.5V,一个 LSB 约等于 0.3 微伏。
真正做系统校准时,寄存器操作顺序不能乱:先把 ADC 控制寄存器设为内部零刻度校准模式,等待 DOUT/DRDY 拉低表示校准完成,再设为内部满量程校准模式,再等待完成。如果温度变化大或者换增益档位,我喜欢在每次换量程后重新校准一次。校准结果会写入偏移寄存器和增益寄存器,回读确认写入成功再开始正常转换。我自己的习惯是把校准封装成一个独立函数,放到量程切换的公共流程里,这样不会漏。希望帮到你。
本文还有配套的精品资源,点击获取