十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F407驱动ADS124S08 24位ADC:从SPI配置到数据采集

STM32F407驱动ADS124S08 24位ADC:从SPI配置到数据采集 简介面向STM32F407与ADS124S08的24位ADC驱动及工程资源适合需要高精度模拟量采集的嵌入式开发者。ADS124S08是TI的低功耗Σ-Δ型ADC具备24位分辨率、内置PGA和参考电压可处理小信号此处驱动代码覆盖配置、初始化与数据读取流程可帮助快速接入STM32F407的SPI/GPIO外设。压缩包共268个文件约16.44MB以C源文件、h头文件、o/crf等编译中间文件为主同时提供uvprojx工程配置、PDF说明及txt文档内部还包括stm32f4系列标准库的RCC、ADC、TIM、CAN等外设驱动文件便于理解时钟、转换与通信的协同配置和二次开发。描述中提到的ADS124/ADS90系列也可作为选型参考整体面向工业自动化、医疗仪器等需要精密测量的场景。目前已有1007人学习可作为工程上集成24位ADC测量功能的实用起点。1. 把 ADS124S08 接到 stm32f407先想清楚 24 位模拟量要什么拿到ADS124S08.zip这类压缩包时目标通常很直接在 stm32f407 上把 24 位模拟量采集跑通同时让板上和它并列的 ADS90 数字量通道不影响 ADC 精度。ADS124S08 是 TI 的 24 位 ΔΣ ADC8 个模拟输入、集成 PGA、内部基准但要注意它没有内部振荡器必须由外部提供 CLKIN 时钟这一个条件就卡掉不少从 ADS1256 移植过来的例程。这篇顺着硬件接线、SPI 初始化、寄存器配置、数据读取、校准和排错往下写所有代码基于 STM32F407 标准外设库HAL 库用户对照引脚和寄存器改即可。2. ADS124S08 硬件接线与 SPI 初始化CLKIN 时钟和 MCO 输出是关键2.1 ADS124S08 引脚分配与电源去耦ADS124S08 的引脚不算复杂但每一路都有讲究。它和 ADS124S06 的区别是模拟输入数量S08 有 8 个输入可以组成 4 组差分或 8 路单端。和更常见的 ADS1256 比它的亮点是低噪声 PGA 最高到 128 倍内部基准温漂更小但代价就是外部时钟必须自己给。芯片手册给的 CLKIN 范围是 256kHz 到 16MHz典型推荐值是 2.048MHz 或 4.096MHz数据速率直接跟这个时钟挂钩所以不要随便拿一个 8MHz 晶振怼上去。引脚功能接法说明CLKIN外部时钟输入2.048MHz 有源晶振或 STM32F407 PA8 MCO 输出SCLKSPI 时钟接 STM32F407 SPI1 的 SCKPB3DIN / DOUTSPI 数据接 PB5MOSI/ PB4MISOCS片选接 PD7软件控制低有效DRDY数据就绪接 PE4下降沿表示转换结果可读RESET复位接 PE5低电平复位START启动转换接 PE6上升沿启动也可以软件命令控制电源去耦不是能省则省的部分。AVDD 和 DVDD 之间用磁珠隔开AVDD 对地放一个 10uF 钽电容并联 0.1uF 陶瓷电容REF 引脚附近的 100nF 电容要尽量靠近芯片引脚。24 位分辨率下基准引脚上的 1mV 波动经过 2.048V 基准折算就是约 4000 个 LSB不用怀疑这类跳码多半是去耦和地线布局造成的。2.2 STM32F407 的 CLKINMCO 输出怎么配我一般建议优先用 2.048MHz 有源晶振直接喂 CLKIN这是最稳的做法不占用主控资源。如果板子已经画完、没给晶振留位置可以用 STM32F407 的 MCO1PA8输出时钟。PA8 可选 HSE、HSI、LSE 或 PLL 时钟典型配置是用 8MHz HSE 四分之一分频输出 2MHz虽然和 2.048MHz 差 2.3%但 ADC 的 SINC 滤波器和数据速率是按 CLK 比例折算的2MHz 同样能正常出数只是滤波器的陷波频率整体偏移了百分之二点几对工频 50Hz 的抑制效果会略差。// 开启 GPIOA 时钟并使能 PA8 复用功能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin GPIO_Pin_8; gpio.GPIO_Mode GPIO_Mode_AF; gpio.GPIO_OType GPIO_OType_PushPull; gpio.GPIO_Speed GPIO_Speed_100MHz; gpio.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, gpio); GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF0); // MCO1 输出 8MHz HSE 的 4 分频即 2MHz 到 PA8 RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_4);逻辑说明MCO1 的复用功能编号是 AF0不配置这一句 PA8 输出不了时钟。RCC_MCO1Config 的第一个参数选时钟源第二个参数是分频系数第三个参数控制 MCO2这里不需要。PA8 输出的驱动能力和 CLKIN 输入阻抗足够匹配不需要额外加驱动芯片。调试时先拿示波器确认 PA8 有 2MHz 方波再往后查 SPI。2.3 SPI1 初始化与寄存器读写基础ADS124S08 的 SPI 时序按 Mode 1 处理即 CPOL0、CPHA1SCLK 空闲为低、数据在下降沿被主机采样。也有部分例程用 Mode 3 能跑通但最稳妥的是先把 Mode 1 调通。SPI 速率不要一上来就拉满先配置到 2.156MHz 左右等通信稳定后再降预分频值提高速度。GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); SPI_InitTypeDef spi; spi.SPI_Direction SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode SPI_Mode_Master; spi.SPI_DataSize SPI_DataSize_8b; spi.SPI_CPOL SPI_CPOL_Low; spi.SPI_CPHA SPI_CPHA_1Edge; spi.SPI_NSS SPI_NSS_Soft; spi.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_16; spi.SPI_FirstBit SPI_FirstBit_MSB; SPI_Init(SPI1, spi); SPI_Cmd(SPI1, ENABLE);逻辑说明SPI_CPHA_1Edge 在标准库里指的是第一个边沿采样配合 CPOL_Low 就是 Mode 1。SPI_BaudRatePrescaler_16 在 APB2 为 84MHz 时得到 5.25MHz对 ADS124S08 来说偏高稳妥起见可以先改成 32得到约 2.6MHz。CS 引脚用普通 GPIO 手动控制不要开 SPI 的硬件 NSS否则多字节事务时片选时序会出问题。底层的字节收发函数很简单uint8_t ADS124S08_WriteByte(uint8_t byte) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET); SPI_I2S_SendData(SPI1, byte); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET); return SPI_I2S_ReceiveData(SPI1); }ADS124S08 的所有操作都是发命令码、再收发数据写寄存器用 WREG读寄存器用 RREG。注意每次读写都要重新拉低 CS并且命令结束后拉高 CS。3. ADS124S08 寄存器配置与 24 位数据读取实现3.1 初始化序列复位、输入选择、PGA 与数据速率上电后先给 RESET 引脚一个低脉冲然后发 SDATAC 命令退出连续模式再逐个写配置寄存器。芯片默认是连续转换模式如果上来直接发 RDATA 去读会因为时序错乱拿到无意义数据所以初始化顺序最好不要颠倒。#define REG_SYSCTRL 0x00 #define REG_INPMUX 0x01 #define REG_PGA 0x03 #define REG_DATARATE 0x04 // 发送单字节命令 void ADS124S08_WriteCmd(uint8_t cmd) { ADS124S08_CS_Low(); ADS124S08_WriteByte(cmd); ADS124S08_CS_High(); } // 写单个寄存器地址和值分开传 void ADS124S08_WriteReg(uint8_t addr, uint8_t value) { ADS124S08_CS_Low(); ADS124S08_WriteByte(0x40 | (addr 0x0F)); ADS124S08_WriteByte(0x00); ADS124S08_WriteByte(value); ADS124S08_CS_High(); }WREG 命令格式是0x40 | 寄存器地址第二个字节写要操作的寄存器数量减 1第三个字节才开始写数据。这样设计是为了允许一次连续写多个寄存器但对单寄存器写入反而容易漏掉第二字节。初始化调用示例// RESET 引脚低脉冲 GPIO_ResetBits(GPIOE, GPIO_Pin_5); delay_ms(2); GPIO_SetBits(GPIOE, GPIO_Pin_5); delay_ms(50); ADS124S08_WriteCmd(0x16); // SDATAC退出连续读取模式 ADS124S08_WriteReg(REG_SYSCTRL, 0x01); // 选择内部 2.048V 基准 ADS124S08_WriteReg(REG_INPMUX, 0x01); // 差分输入IN0 正端IN1 负端 ADS124S08_WriteReg(REG_PGA, 0x00); // PGA 增益 x1 ADS124S08_WriteCmd(0x08); // START启动转换逻辑说明REG_INPMUX 写 0x01 时高 4 位选择 AINP 为 IN0低 4 位选择 AINN 为 IN1这是最常用的差分接法。如果用单端输入负端接法要查手册里的通道编码表不同芯片版本对 AINN 接到 AVSS 的编码定义不完全一样不要凭感觉猜。PGA 寄存器低 3 位控制增益0x00 是 1 倍0x01 是 2 倍0x02 是 4 倍后面依次翻倍到 128 倍但增益超过 64 倍时输入等效噪声会明显上升一般应变片场景才用高增益。DATARATE 寄存器尽量保持复位默认值先验证通路确认能稳定出数后再按手册的速率表调整。上来就改速率如果寄存器地址或编码写错表现往往不是完全无数据而是采样率变成奇怪的值排查起来更费劲。3.2 读取转换结果RDATA 命令与符号扩展转换完成时 DRDY 引脚会拉低主机检测到低电平后发 RDATA 命令读出 3 个字节的转换结果。如果没有开 CRC 校验数据格式是 24 位二进制补码最高位是符号位负输入时读出的是负数。int32_t ADS124S08_ReadRaw(void) { uint8_t buf[4] {0}; uint32_t code 0; while (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) SET); // 等待 DRDY 变低 ADS124S08_CS_Low(); buf[0] ADS124S08_WriteByte(0x12); // RDATA 命令 buf[1] ADS124S08_WriteByte(0x00); // 读回转换结果高位 buf[2] ADS124S08_WriteByte(0x00); // 中位 buf[3] ADS124S08_WriteByte(0x00); // 低位 ADS124S08_CS_High(); code ((uint32_t)buf[1] 16) | ((uint32_t)buf[2] 8) | buf[3]; if (code 0x800000) { code | 0xFF000000; // 24 位补码扩展为 32 位有符号数 } return (int32_t)code; }逻辑说明RDATA 命令发出后芯片从 DOUT 引脚依次送出高、中、低 3 个字节所以后面要跟 3 个空的 SPI 读周期。buf[0]保存的是命令本身的回显不是数据。符号扩展那行代码是针对负电压输入时转换值最高位为 1 的情况如果不做这一步负输入会读出巨大的正数换算出的电压完全不对。等待 DRDY 用的是轮询方式实际项目里应该改成外部中断在中断里置标志位主循环读到标志后再去发 RDATA这样不会阻塞其他任务。3.3 电压换算公式与数字量通道共存拿到有符号的原始码后电压换算公式是电压值 (V) 原始码 / 2^23 * VREF / PGA这里的 VREF 是 2.048VPGA 是当前设定的增益。比如 PGA1、原始码为 1677721 时电压约等于 0.4096V。特别注意这个公式只在差分输入和双极性格式下成立如果配置成单极性格式分母变成 2^24 而不是 2^23。压缩包名里同时出现的 ADS90 数字量指的是同一块板子上还带开关量输入输出通道。这类数字量通道处理起来比 ADC 简单STM32F407 的 GPIO 直接读电平或输出即可但真正要小心的是数字量通道动作时对模拟采集的干扰。开关量输出驱动继电器或接触器时线圈断电瞬间产生的反电动势会通过地线窜入模拟前端表现为 ADC 某几个通道跳码。常见做法是数字量输出用光耦或达林顿管隔离模拟地和数字地单点连接ADC 供电不要和继电器电源共用同一个 DC-DC。4. 让采样值稳下来PGA 增益、基准与数字滤波设置4.1 参考电压与 PGA 的误差控制内部基准虽然方便但它不是万能的。ADS124S08 内部 2.048V 基准的初始精度在数据手册里不是特别高对绝对电压精度要求高的场合建议用外部基准芯片比如 REF5025 这类低噪声基准给 REF 引脚提供 2.5V然后把 System Control 寄存器里的基准选择位切到外部。PGA 增益的设置直接决定你能采集的信号范围。增益为 1 时满量程输入范围是 -2.048V 到 2.048V增益为 8 时变成 -256mV 到 256mV。很多初次用的人以为 PGA 增益大了分辨率就高其实 24 位的有效分辨率受噪声限制增益增大后输入端的阻抗和失调电压影响会更明显。我的习惯是先看传感器输出幅值让信号在满量程的 50% 到 90% 之间再去选增益而不是无脑拉到最大。输入共模电压同样要检查。ADS124S08 的 PGA 输入级对共模范围有约束PGA 使能时输入引脚的绝对电压不能太靠近电源轨否则线性度会恶化。前端加一个简单 RC 抗混叠滤波器电阻取几百欧到 1k 欧电容取 1nF 到 10nF既可以抑制带外噪声也能防止 ESD 脉冲打到引脚上。4.2 SINC 滤波器类型与数据速率选择ADS124S08 内部是 ΔΣ 调制器加数字滤波器滤波器类型和数据速率都在 DATARATE 寄存器里配。常见的选择是 SINC3 或 SINC4两者对带外噪声的抑制特性不同。SINC3 的建立时间短适合多路切换扫描SINC4 对高频噪声的滚降更陡但建立时间更长。如果你的应用固定采集一路信号、不怎么切换通道优先选 SINC4。滤波器类型建立时间带外抑制适合场景SINC3较短一般多通道轮询、快速响应SINC4较长更好单通道高精度、低频噪声抑制数据速率不是任意设置的它是 CLKIN 频率除以一个分频系数得到的。CLKIN 用 2.048MHz 时典型速率从几 SPS 到数千 SPS。速率越高噪声越大这是 ΔΣ ADC 的普遍规律。对电池供电的仪表类应用25SPS 到 100SPS 区间通常性价比最高对电力录波或振动监测才需要上 1000SPS 以上。调试时先看 CLKIN 频率和 DATARATE 寄存器实际设置是否一致用示波器量 DRDY 的周期就是当前实际采样率这是最直接的验证手段。4.3 系统校准供电和基准误差怎么补芯片上电默认状态不能保证零点和增益都精准尤其是温度变化后PGA 的失调会漂移。ADS124S08 支持系统校准命令在完成寄存器配置、开始正常转换之前依次发零点校准和增益校准命令。// 系统零点校准 ADS124S08_WriteCmd(0x18); // 等待校准完成 while (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) SET); delay_ms(10); // 系统增益校准 ADS124S08_WriteCmd(0x1A); while (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) SET);逻辑说明系统零点校准要求校准前把模拟输入端短接到 GND芯片会把这个状态下的输出码记录为校准值。增益校准要求输入端加一个已知的满量程参考电压校准过程会修正增益误差。两个校准命令执行期间 DRDY 会保持高电平校准完成后自动拉低所以代码里等待 DRDY 恢复低电平再继续。如果输入端不能提供精确的参考电压就不要做增益校准只做零点校准否则校准出来的增益误差反而比原来更大。校准代码放在初始化完成之后、正式读取数据之前每次上电执行一次。如果环境温度变化超过 20 度建议重新校准。要注意校准只在当前 PGA 增益下有效切换 PGA 增益后需要重新校准。5. 开关量动作时的跳码、DRDY 卡死与 RDATACDMA 连续采样5.1 DRDY 一直高电平的快速定位DRDY 引脚一直不拉低先查三处。第一是 CLKIN 有没有波形这是最常见的问题MCO 配置错了或引脚复用没设对PA8 没有输出时钟ADC 内部数字逻辑完全不工作。第二是 RESET 引脚是否被拉低有些工程师把 RESET 悬空芯片复位后处于未知状态DRDY 自然不动。第三是检查 SPI 的 CPOL/CPHA 是不是被改成了别的模式通信不上时芯片不会进入正常转换流程。如果 DRDY 有脉冲但读出来的数据是固定的 0xFFFFFF 或 0x000000把示波器探头放到 MISO 引脚上看数据波形。MISO 在 DRDY 拉低后、主机发 RDATA 命令时应该在第一个 SCLK 下降沿后开始输出数据。没有数据出来重点查 CS 片选时序和 SPI 速率。5.2 数字量输出通道造成的模拟量跳码和标题里 ADS90 数字量通道在同一块板上调试时最容易碰到继电器一动作、ADC 就跳码的现象。这不是 ADS124S08 本身的问题而是干扰耦合路径没切断。先确认数字量输出电路用的是独立电源继电器线圈两端必须并续流二极管否则关断瞬间的反电动势会让地电位整体抖一下。其次检查 PCB 布局模拟输入走线和数字量输出走线不要平行中间隔开至少一倍线宽。软件侧可以做的补救是数字量动作后延迟几个采样周期再读 ADC因为干扰是瞬态的数字滤波器需要几个周期才能把异常值滤掉。5.3 连续采样模式与 DMA 收数轮询方式读 ADC 在低速时够用但采样率超过 500SPS 后主循环频繁等待 DRDY 会占用大量 CPU。改成 RDATAC 连续模式和 SPI DMA 是比较合理的升级方案。初始化时发 RDATAC 命令代替手动 RDATA芯片会每个转换周期自动把数据推送到 DOUT主机只需要持续提供 SCLK 就能读到结果。// 伪代码SPI2 DMA 循环接收配置 SPI_Cmd(SPI2, DISABLE); SPI2-RXCRCR 0; SPI2-TXCRCR 0; DMA_InitTypeDef dma; dma.DMA_Channel DMA_Channel_0; // SPI2 RX 映射到 DMA1 通道 0 dma.DMA_PeripheralBaseAddr (uint32_t)SPI2-DR; dma.DMA_MemoryBaseAddr (uint32_t)adc_buf; dma.DMA_DIR DMA_DIR_PeripheralSRC; dma.DMA_BufferSize 6; // 3 字节数据 * 2 组组成乒乓缓冲 dma.DMA_PeripheralInc DMA_PeripheralInc_Disable; dma.DMA_MemoryInc DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize DMA_PeripheralDataSize_Byte; dma.DMA_MemoryDataSize DMA_MemoryDataSize_Byte; dma.DMA_Mode DMA_Mode_Circular; DMA_Init(DMA1_Stream0, dma); SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_RX, ENABLE); SPI_Cmd(SPI2, ENABLE);逻辑说明RDATAC 模式下 SPI 主机的时钟可以由定时器触发也可以靠 DMA 循环请求持续产生 SCLK。代码里用 6 字节乒乓缓冲每 3 个字节组成一组转换结果DMA 循环写入后通过比较当前地址判断哪一组是新的。要注意发送方向必须同时给 MOSI 发送数据SPI 是全双工协议接收数据必须有发送才能产生时钟最简单的方法是 DMA 的 TX 端也启动循环发送 0x00。连续模式下不要频繁拉高 CSCS 只在配置寄存器时拉高去终止连续模式否则数据流会被打断。最后留一个小技巧如果 SINC3 在 50Hz 工频附近残留噪声而你的采样率正好是工频的整数倍此时滤波器陷波点被搬移工频抑制能力会下降。把数据速率改到非工频整数倍或者切 SINC4效果往往比加大滤波电容更明显。验证办法是把输入端短接到地连续读 1000 个原始码算标准方差对比改动前后的噪声 LSB 数据哪个配置标准差小就用哪个。本文还有配套的精品资源点击获取
返回列表