
简介针对STM32F407与TI ADS124S08的24位ADC驱动资源包面向需要高精度模拟量采集的嵌入式开发者可广泛应用于工业自动化、医疗检测与传感信号调理等场景。ADS124S08本身具备24位分辨率、内置可编程增益放大器和内部参考电压能够直接处理毫伏级小信号再配合STM32F407的浮点运算和外设接口可搭建完整的数据采集前端。压缩包共268个文件约16.44MB以C源文件、头文件、标准外设库和Keil工程文件为主体包含可直接编译的工程配置及编译输出文件还有PDF、TXT等辅助文档目录结构清晰便于从底层驱动到应用示例对照学习。目前已有1007人学习下载驱动代码和参考工程覆盖ADC初始化、通道选择、数据读取与处理等关键环节能帮助开发者快速完成高精度转换功能集成尤其适合对ADS124S08驱动不熟悉的开发者参考与二次开发。1. ads124s08驱动的起点24位模拟量怎么变成数字量一个标着“24位模拟量”的ads124s08驱动最让stm32f407工程师头疼的往往不是SPI硬件本身而是上电后忘了从RDATAC连续读模式里退出来写进去的寄存器全部无效。ADS124S08是TI的24位Δ-Σ ADC内置PGA和2.048V基准把现场传感器的模拟量经过调制器和数字滤波器后变成24位二进制补码从SPI串行读出。标题里的“ADS90数字量”说的就是这串数字输出它跟PLC场景里常说的开关量不是一回事开关量只有0和1这里的数字量是一整个有符号整数范围从-8388608到8388607。这块芯片适合4/8通道、增益可配、采样率不超过4 kSPS的采集场景比如应变桥、热电偶、称重和电池电压监测。做驱动的人真正要解决的只是三件事SPI时序对得上、寄存器写进去、数据读回来按电压公式还原。下文按这个顺序把从stm32f407接线到能稳定出数的完整路径拆开讲。2. ADS124S08与stm32f407的SPI握手模式、引脚与时序2.1 Δ-Σ架构决定的数据流ADC输出是数字量不是开关量ADS124S08内部先由调制器把模拟输入变成高码率比特流再由数字滤波器抽取成低速率的24位结果。这个“抽取”过程意味着转换结果不是瞬时电压而是过去一段时间窗口的平均值芯片因此天然有了抗混叠能力。代价是每次转换完成时间比SAR型ADC长得多数据从DRDY引脚的下落沿通知你“新的一帧准备好了”。很多第一次从ADS1115这类芯片转过来的工程师会习惯性在读取前先发一条“读转换结果”命令。ADS124S08上电默认进入的是RDATAC连续读模式此时不能执行RREG/WREG之外的命令想配置寄存器必须先发SDATAC退出。反过来有人一上来就发RDATA读数据发现读回来的字节全是0xFF多半也是这个原因。这个顺序问题是整套驱动里最容易被忽略的启动条件。2.2 MODECN决定SPI模式模式1还是模式3先量电平再写代码ADS124S08的数据手册里有一个专门管SPI模式的引脚MODECN。MODECN拉低时芯片工作在SPI模式1即CPOL0、CPHA1SCLK空闲为低数据在第二个边沿被采样MODECN拉高时芯片工作在SPI模式3即CPOL1、CPHA1SCLK空闲为高。两个模式只是极性不同采样沿都是第二个边沿所以MISO上的数据建立时间要求差不多。上电第一步拿万用表量MODECN引脚电平再对应配置stm32f407的SPI。原理图里这个脚常通过10kΩ电阻接GND或VDD也有板子直接悬空悬空时电平不确定是通信不稳定的典型来源。写代码时把这一项单独做成宏换板子时只改宏不碰初始化函数/* 0: MODECN0, SPI模式1(CPOL0,CPHA1) */ /* 1: MODECN1, SPI模式3(CPOL1,CPHA1) */ #define ADS124S08_SPI_MODE_1 1uSCLK频率也在这里一起定。ADS124S08的SCLK上限取决于数据手册给出的电气参数我一般把F407这边的SPI时钟压在4 MHz以下留给走线电容和电平转换余量。SPI2挂在APB1总线上主频168MHz时APB1是84MHz用32分频得到2.625 MHz稳妥够用。2.3 F407引脚分配SPI2还是SPI3避开片选与中断冲突stm32f407的SPI1挂在APB2上速度上限比SPI2/SPI3高但SPI1引脚与很多板载外设复用留给ADC的位置往往不好。常见做法是把ADS124S08放到SPI2或SPI3上用软件NSS控制片选DRDY接一个支持外部中断下降沿的GPIO。我的一块自制板上用的是SPI2引脚分配如下F407引脚功能ADS124S08引脚说明PB13AF5/SPI2_SCKSCLK时钟极性由MODECN定PB14AF5/SPI2_MISODOUT数据输出芯片推挽输出PB15AF5/SPI2_MOSIDINF407写寄存器用PB12GPIO输出CS每帧操作前拉低帧结束拉高PA1GPIO下降沿中断DRDY开漏输出板子上必须带上拉电阻注意DRDY是开漏结构没有上拉时即使ADC正常转换F407也永远等不到下降沿。这是硬件上最隐蔽的坑原理图评审时一定要确认这颗电阻存在。CS不要交给SPI外设的硬件NSS管理ADS124S08的每个命令、每次数据读取都是一个独立的片选帧帧内字节数各不相同用GPIO手动拉放最可靠。3. stm32f407侧接线与SPI2初始化最小可运行配置3.1 电源与基准AVDD、DVDD、VREF和输入滤波的硬规则ADS124S08的数字电源和模拟电源是分开的DVDD负责接口电平AVDD负责内部模拟电路。这两路电源的电压可以不同但去耦都要做到位每个电源引脚就近放一个100nF陶瓷电容再在电源入口放10µF钽电容或瓷片电容。模拟输入引脚附近不要走数字信号线尤其是SCLK这类沿很陡的信号串扰进去会直接体现在低几位跳动上。参考电压决定满量程。用内部2.048V基准时REFP和REFPN之间建议并一颗1µF低ESR电容噪声敏感的场合换成外部基准芯片把REFMUX寄存器切到外部基准。初次调试不接传感器时把模拟输入直接短接到AVSS这时读出的码值应当接近0这是判断硬件通路是否干净的最快办法。3.2 用HAL库配置SPI28位、MSB first、模式1下面这段初始化代码基于STM32CubeMX生成的工程手写调整了几个关键参数。ADS124S08的SPI帧是8字节整数倍所有寄存器、命令、数据都按字节传输确认数据位宽为8位即可。void MX_SPI2_Init(void) { GPIO_InitTypeDef gpio {0}; SPI_InitTypeDef spi {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_SPI2_CLK_ENABLE(); /* PB13SCK, PB14MISO, PB15MOSI, 全部复用为AF5 */ gpio.Pin GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; gpio.Mode GPIO_MODE_AF_PP; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, gpio); /* CS用普通GPIO手动控制不交给SPI硬件NSS */ gpio.Pin GPIO_PIN_12; gpio.Mode GPIO_MODE_OUTPUT_PP; gpio.Pull GPIO_PULLUP; gpio.Speed GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOB, gpio); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); spi.Instance SPI2; spi.Init.Mode SPI_MODE_MASTER; spi.Init.Direction SPI_DIRECTION_2LINES; spi.Init.DataSize SPI_DATASIZE_8BIT; spi.Init.CLKPhase SPI_PHASE_2EDGE; /* CPHA1, 第二边沿采样 */ spi.Init.CLKPolarity SPI_POLARITY_LOW; /* CPOL0, 对应MODECN0 */ spi.Init.NSS SPI_NSS_SOFT; spi.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_32; /* 84MHz/322.625MHz */ spi.Init.FirstBit SPI_FIRSTBIT_MSB; spi.Init.TIMode SPI_TIMODE_DISABLE; spi.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(spi); }代码里CLKPolarity和CLKPhase这一对参数要跟MODECN电平严格对应。上面写的CPOL0对应MODECN拉低如果量到MODECN为高只把SPI_POLARITY_LOW改成SPI_POLARITY_HIGH芯片会切到真正匹配的模式。注释里也标了APB1频率84MHz除以32得到2.625MHz这个频率对大多数ADS124S08应用都留有余量。SCLK上的信号完整性如果很差先降低分频系数不要急着改输入滤波电路。3.3 最小回环自检先证明F407的SPI通路是好的ADS124S08还没焊上去之前可以先把SPI2的MOSI和MISO用一根短导线短接做一次自发自收测试。F407的SPI在全双工模式下发送一个字节的同时收到对端返回的字节把MOSI短到MISO后发什么就应收到什么。测试代码不需要驱动芯片只验证GPIO复用、时钟配置和SPI外设本身是否正常。uint8_t spi2_loopback_test(void) { uint8_t tx 0xA5; uint8_t rx 0; HAL_SPI_TransmitReceive(hspi2, tx, rx, 1, 100); return (tx rx) ? 0 : 1; }短接导线要尽量短直接插在排针上就行。返回0说明SPI2通路正常这时再去查ADS124S08电源和DRDY返回1则先查时钟树里SPI2是否被使能、GPIO是否复用到了AF5。这个自检能省掉大量“为什么读回全FF”的排查时间。4. ads124s08驱动实现寄存器读写、初始化序列与24位数据解析4.1 命令宏和字节读写原语先写好ADS124S08的命令集非常规整读寄存器、写寄存器、读数据、复位各是一个单字节命令。驱动底层只要封装一个SPI收发函数上层所有操作都从这个函数展开禁止在业务代码里到处直接调用HAL库。#define ADS124S08_CMD_RREG 0x20u /* 读寄存器后续字节为寄存器地址 */ #define ADS124S08_CMD_WREG 0x40u /* 写寄存器后续字节为寄存器地址 */ #define ADS124S08_CMD_RDATA 0x12u /* 读一次转换结果24位 */ #define ADS124S08_CMD_RDATAC 0x14u /* 连续读模式上电默认 */ #define ADS124S08_CMD_SDATAC 0x16u /* 退出连续读 */ #define ADS124S08_CMD_RESET 0x06u /* 复位 */ static uint8_t ads124s08_spi_byte(uint8_t tx) { uint8_t rx 0; HAL_SPI_TransmitReceive(hspi2, tx, rx, 1, HAL_MAX_DELAY); return rx; }ads124s08_spi_byte每次只收发一个字节牺牲一点效率保逻辑清晰。所有命令、寄存器写值、数据字节都走这个函数MISO上收到的返回字节就是上一次发送期间芯片输出的内容。RREG读寄存器时第二个字节是“后续要读的字节数减1”这个减1的规则源自TI的SPI协议写0表示读1个字节写2表示读3个字节初学时最容易漏。4.2 初始化序列SDATAC、WREG、回读校验上电或复位后ADS124S08会默认进入RDATAC连续读模式。此时执行RREG之外的命令会被忽略所以初始化第一步永远是退出连续读模式再写寄存器。下面是完整的初始化流程void ads124s08_init(void) { uint8_t chk 0; /* 复位芯片之后等待内部上电稳定 */ ADS124S08_CS_L(); ads124s08_spi_byte(ADS124S08_CMD_RESET); ADS124S08_CS_H(); HAL_Delay(2); /* 退出RDATAC允许写配置寄存器 */ ADS124S08_CS_L(); ads124s08_spi_byte(ADS124S08_CMD_SDATAC); ADS124S08_CS_H(); /* INPMUX0x0A正输入AIN0负输入AVSS单端模式 */ ads124s08_wreg(0x01, 0x0A); /* PGA0x30增益1倍数据速率保持默认低4位查手册数据速率表 */ ads124s08_wreg(0x02, 0x30); /* 回读校验确认SPI写真的写进去了 */ chk ads124s08_rreg(0x01); if (chk ! 0x0A) { /* 回读失败先查CS波形再查SPI模式 */ } }INPMUX寄存器的高4位选正输入低4位选负输入0x0A只是AIN0对AVSS这一种接法。如果板子上信号接的是AIN3高位改成3如果做差分测量低位改成另一个通道编号。PGA寄存器的高3位是增益001代表1倍低4位是数据速率代码不同代码对应的SPS值要查数据手册里的速率表不同增益下最大速率也不一样不建议靠记忆硬填。这里把CS每一帧都拉高拉低是因为ADS124S08的RREG和WREG都以CS下降沿为起始条件。回读校验这步看起来多余但对排查硬件问题非常有用写进去再读出来不一致基本可以确定是SPI模式、CS时序或MISO通路三者之一出了问题。4.3 读24位数据DRDY下降沿触发与二进制补码处理转换完成后DRDY引脚会产生一个下降沿。读取数据时先等DRDY变低再拉低CS发送RDATA命令随后连续收3个字节就是当前的24位转换码。读完后DRDY自动回高等待下一次转换。uint32_t ads124s08_read_single(void) { uint32_t raw 0; /* 等待DRDY拉低表示新数据已就绪 */ while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) ! GPIO_PIN_RESET) { /* 这里建议加超时计数避免死等 */ } ADS124S08_CS_L(); ads124s08_spi_byte(ADS124S08_CMD_RDATA); raw | (uint32_t)ads124s08_spi_byte(0xFF) 16; raw | (uint32_t)ads124s08_spi_byte(0xFF) 8; raw | (uint32_t)ads124s08_spi_byte(0xFF); ADS124S08_CS_H(); return raw; }发送RDATA后芯片从DOUT引脚依次移出最高字节、中间字节、最低字节。读数据时MOSI上发的0xFF是空指令只是为了产生SCLK时钟芯片并不关心MOSI内容。等待DRDY的地方要加超时常见写法是配一个SysTick计数器超过数据速率对应周期数就报错退出避免SPI卡死在死循环里。需要注意RDATA命令在RDATAC退出后才能使用。如果坚持用连续读模式就不要发RDATA而是每检测到一次DRDY下降沿直接读3个字节省掉命令字节但此时任何配置寄存器的写入都会被芯片拒绝。4.4 把原始码换算成实际电压单端与差分的差别24位数据是有符号二进制补码满量程对应0x7FFFFF负满量程对应0x800000。换算成电压前先做符号扩展再用满量程值归一化。stm32f407自带FPU单精度float足够完成这个计算没必要用double。float ads124s08_raw_to_volt(uint32_t raw, float vref, float pga_gain) { /* 24位补码转有符号整数 */ int32_t s (int32_t)(raw 8) 8; /* 单端输入电压 码值/2^23 * 参考电压 / 增益 */ /* 差分输入时满量程是±VREF要先乘以2再除以增益 */ return ((float)s / 8388608.0f) * vref / pga_gain; }符号扩展那行是驱动里最容易写错的地方raw 8把24位数据挪到32位整数的最高字节 8用算术右移把符号位填满。若直接用浮点除法算0x800000会被当成8388608而不是-8388608电压值就会差一个满量程。单端输入时电压范围从0到VREF对应码值0到0x7FFFFF差分输入时范围是-VREF到VREF公式里的vref要换成2倍参考电压这一点在硬件设计阶段就要想清楚软件改起来容易硬件接线反了就只能飞线。5. 用DRDY波形和内部温度传感器做整链自检5.1 温度传感器读出的数字量怎么验证SPI和基准配置完增益和输入通道后第一件事不是接传感器而是读内部温度传感器。ADS124S08内部有一个温度传感器切换INPMUX把负输入端选到内部温度传感器通道读回的数据就是当前结温对应的码值。这个码值即使有误差也一定在某个合理区间内不会因为外部接线而改变。/* 切换到内部温度传感器通道后执行一次转换 */ ads124s08_wreg(0x01, 0x20 | 0x0B); /* 正端内部温度传感器, 负端AVSS */ ads124s08_wreg(0x02, 0x30); /* 增益1倍不变 */ uint32_t t_raw ads124s08_read_single();读回来的码值如果在预期温度范围内说明SPI通信、寄存器写入、参考电压、DRDY中断整条链路都是通的问题只可能出在外部输入信号上。这一步把“芯片问题”和“电路问题”一刀切开比拿示波器逐脚量效率高得多。5.2 两个必看的波形DRDY下降沿与SCLK空闲电平温度传感器读数正常后再看两处波形确认时序余量。第一处是DRDY下降沿后、发起RDATA命令之前的间隔间隔太短说明主循环调度太慢数据可能被下一次转换覆盖第二处是SCLK空闲电平用示波器DC耦合看空闲时应是低电平与MODECN设定一致。现象优先查什么处理方式RREG回读全0xFFCS时序和SPI模式量SCLK空闲电平核对MODECNDRDY一直为高开漏上拉电阻确认DRDY引脚有上拉读数固定为0START引脚/参考电压量START电平和VREF引脚步电压数值偏移很大INPMUX寄存器RREG回读0x01与写值比对低几位乱跳输入滤波/电源去耦输入引脚加RCAVDD去耦加强5.3 用温度传感器代外部信号做最终验证比较稳妥的收尾动作是把内部温度传感器换算结果跟热成像仪或板载NTC对比误差在几摄氏度内即可。这一步能同时验证参考电压和增益配置。外部信号接入前先在软件里把ads124s08_raw_to_volt的输出打印到串口用手触摸输入走线观察电压变化方向确认极性正确后再接传感器避免接反导致芯片输入超过共模范围。本文还有配套的精品资源点击获取