尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32驱动ADS8688:多通道高精度ADC工业采集实战解析

STM32驱动ADS8688:多通道高精度ADC工业采集实战解析 简介面向STM32微控制器的ADS8688模数转换芯片驱动代码包重点解决八通道十六位高速采集与串行外设接口通信的整合问题。代码采用C语言实现覆盖串行接口初始化、片选控制、内部寄存器配置、通道切换、启动转换及结果读取等关键环节兼容硬件抽象层与低层库两种开发方式也方便在裸机工程中直接调用。资源包共包含两个文件即源程序文件与头文件压缩后整体大小约3KB代码量精炼、接口划分清晰适合有一定嵌入式基础的中高级开发者快速移植到数据采集项目。已有五千五百七十七人学习下载说明该驱动方案受到较多工程师关注和验证。压缩包内附带的底层驱动涵盖串行时钟极性与相位设置、多通道轮询采样、转换完成标志判断等实用细节配合芯片手册可以更快掌握ADS8688的寄存器读写流程有效减少高速模拟量采集模块的调试时间。 做工业采集项目时我最常被问到的一类问题就是“多通道、高精度ADC到底怎么选”如果预算没有紧张到必须用国产替代ADS8688基本是闭眼入的方案之一。这颗芯片是TI的16位、8通道、500kSPS逐次逼近型ADC内置可编程增益放大器和4.096V基准单5V供电就能直接采集±10.24V的工业信号连前端调理运放都省了。这篇文章我就把自己在STM32上驱动ADS8688的完整过程整理出来包括硬件连接、SPI时序、寄存器配置和代码实现以及调试时踩过的几个典型的坑。想抄作业的可以直接看第三节的代码想搞懂原理的建议从头读。1. 项目背景与整体设计思路1.1 ADS8688核心特性梳理先说清楚这颗芯片到底解决了什么问题。我们平时测工业现场信号比如压力变送器的4-20mA采样电阻上的电压、伺服驱动器的模拟量输出、或者PLC的0-10V控制信号量程经常是±10V、±5V这个级别。普通STM32内置ADC输入范围只有0-3.3V而且12位分辨率在弱信号场景下明显不够用。以往的做法是先用运放做电平平移和衰减再进MCU的ADC电路复杂不说温漂和噪声指标也很难控制。ADS8688把前端信号链几乎全部集成进去了。它的输入范围可以通过寄存器配置支持±10.24V、±5.12V、±2.56V、±1.024V、0-10.24V、0-5.12V、0-2.56V共7种量程输入阻抗高达1MΩ直接并联在信号源上基本不影响原电路内部基准不用外挂省了一路参考电压的布局空间。而且8个通道全部是单端输入多路采集时不需要外部多路开关一颗芯片搞定。1.2 方案选型SPI接口和单电源供电是关键很多新手第一次看到ADS8688的供电要求会被吓到——AVDD是5V但DVDD可以接1.8V到5V。这说明它的数字接口电平是灵活可配的和3.3V的STM32直接相连完全没问题。接口方面用的是标准SPI最高时钟频率手册标注得很高实际工程中我习惯控制在10MHz以内留足时序余量。选它而不是ADS1256这类Δ-Σ型ADC主要看应用场景。ADS1256是24位精度但采样率到了高位数时只有几十SPS而且需要外部基准、输入范围也需要自己调。ADS8688是SAR型ADC没有流水线延迟500kSPS的采样率在电机控制、电力监控、振动采集这类需要一定实时性的场景里明显更合适。16位分辨率配合可编程增益应对绝大多数工业信号已经足够了。1.3 适合谁来参考这篇内容适合有几类人阅读第一类是在做数据采集卡、PLC模拟量模块、工业变送器校准设备的人需要稳定可靠的多通道ADC方案第二类是学校实验室做仪表类课题的学生STM32加ADS8688是比较经典的组合第三类是纯粹想搞清楚SPI从设备怎么驱动的入门者可以先拿这颗芯片练手寄存器不算复杂时序也有代表性。2. 硬件连接与接口设计要点2.1 ADS8688与STM32引脚连接ADS8688的封装是TSSOP-24引脚不算密手工焊接有点基础就能搞定。我常用的接法如下STM32引脚ADS8688引脚说明PA5 / SPI1_SCKSCLKSPI时钟PA6 / SPI1_MISOSDO从机数据输出接单片机MISOPA7 / SPI1_MOSISDI从机数据输入接单片机MOSIPA4 / GPIOCS片选信号软件控制PB0 / GPIORST硬件复位低有效—AVDD接5V—DVDD接3.3V—REFIO/REFCAP基准引脚按手册接旁路电容这里有个容易犯的错SDO和SDI不要接反。ADS8688作为SPI从机SDO是它的输出必须连到STM32的MISOSDI是输入连到MOSI。我第一次画板时把这两个信号对调了结果读回来的数据全是0xFF排查了半天。2.2 电源与去耦细节AVDD建议用独立的5V LDO供电不要直接从电机驱动板或开关电源上拉否则转换结果底噪会明显增大。我实测过AVDD纹波从50mV降到10mV之后读取到的数据跳动范围能从±12个LSB降到±3个LSB以内。去耦电容在AVDD引脚附近放一个10μF钽电容加一个0.1μF陶瓷电容并联REFCAP基准输出电容用2.2μF以上的X7R陶瓷电容这个值不能太小否则基准建立时间不够上电后前几次转换结果会偏。数字部分DVDD接3.3V和STM32同一路电源即可。ADS8688内部有电平转换电路所以不用额外加电平转换芯片。如果系统里还有其它3.3V外设建议在DVDD入口处也加一颗0.1μF去耦。2.3 SPI模式与接线注意事项ADS8688支持的是SPI Mode 1也就是CPOL0、CPHA1数据在时钟上升沿准备、下降沿采样。我见过不少人在HAL库配置里把模式搞反配成了Mode 0读回来的数据偶尔正确偶尔错乱。原因就是采样沿和芯片输出时序对不上。下面这段是标准库的SPI配置片段SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode SPI_Mode_Master; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA SPI_CPHA_2Edge; // 模式1 SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_8;接线方面注意SPI信号线尽量短尤其是SCLK不要在线上串太大的电阻。如果SCLK频率超过5MHz串接的RC滤波电容会直接把时钟沿变缓导致数据采样错位。3. STM32驱动代码实现3.1 驱动代码整体结构ADS8688的驱动我习惯拆成三个层次底层是SPI读写中间层是寄存器配置上层是通道读取和数据处理。这样的好处是换MCU平台时只改底层上面的业务逻辑不用动。ADS8688的命令帧是16位由8位命令/地址和8位数据组成。写寄存器时SPI连续发送两个字节第一个字节是寄存器地址加读写标志第二个字节是要写入的数据。读转换结果时需要先发送读命令然后在后续的时钟周期内接收数据输出。具体细节以数据手册的时序图为准。3.2 驱动代码完整实现下面是完整的驱动头文件主要暴露初始化和读通道接口// ads8688.h #ifndef __ADS8688_H #define __ADS8688_H #include stm32f1xx_hal.h // ADC输入范围定义对应数据手册范围寄存器 typedef enum { ADS8688_RANGE_PM_10_24V 0x00, ADS8688_RANGE_PM_5_12V 0x01, ADS8688_RANGE_PM_2_56V 0x02, ADS8688_RANGE_PM_1_024V 0x03, ADS8688_RANGE_0_10_24V 0x05, ADS8688_RANGE_0_5_12V 0x06, ADS8688_RANGE_0_2_56V 0x07 } ADS8688_Range; uint8_t ADS8688_Init(SPI_HandleTypeDef *hspi); void ADS8688_SetRange(ADS8688_Range range); int16_t ADS8688_ReadChannel(uint8_t channel); float ADS8688_ReadVoltage(uint8_t channel); #endif驱动源文件的重点在初始化函数。上电后必须给RST引脚一个低脉冲然后等待至少100μs让内部基准稳定再写配置寄存器。这一步不能省直接上电就读数据经常能读到0x0000或者0xFFFF这种异常值。// ads8688.c #include ads8688.h #include gpio.h static SPI_HandleTypeDef *ads8688_spi; static ADS8688_Range current_range; static void ADS8688_WriteReg(uint8_t reg, uint8_t data) { uint8_t tx[2]; tx[0] reg; tx[1] data; HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(ads8688_spi, tx, 2, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); } uint8_t ADS8688_Init(SPI_HandleTypeDef *hspi) { ads8688_spi hspi; // 硬件复位 HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET); HAL_Delay(10); // 配置输入范围为默认±10.24V ADS8688_WriteReg(0x0A, 0x00); ADS8688_WriteReg(0x0B, 0x00); current_range ADS8688_RANGE_PM_10_24V; return 0; }读通道函数需要注意一点ADS8688的读时序是命令帧和结果帧连续完成CS在整个过程中一直保持低电平。连续两次SPI传输之间不要释放CS否则芯片会认为是一次新的命令读出来的数据就错位了。我建议把两字节命令和两字节读取放在同一个CS低电平区间内#define ADS8688_CMD_READ 0x20 // 读转换结果命令具体按手册定义 int16_t ADS8688_ReadChannel(uint8_t channel) { uint8_t tx[2]; uint8_t rx[2] {0, 0}; uint16_t raw 0; if (channel 7) channel 7; // 命令帧读命令 通道地址 tx[0] ADS8688_CMD_READ | ((channel 0x07) 1); tx[1] 0x00; HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(ads8688_spi, tx, 2, 100); // 紧跟着读取16位转换结果期间CS保持低电平 HAL_SPI_Receive(ads8688_spi, rx, 2, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); raw ((uint16_t)rx[0] 8) | rx[1]; // 16位ADC双极性模式符号扩展 return (int16_t)raw; }如果觉得SPI配置成8位模式收发两个字节太繁琐也可以把SPI数据宽度直接设成16位。但实际上8位模式的兼容性更好而且很多STM32型号在16位模式下DMA传输时字节序容易搞混8位模式反而省心。3.3 数据换算与量程选择ADS8688输出的是二进制补码格式。以±10.24V量程为例满量程对应0x7FFF负满量程对应0x8000。换算成真实电压的公式是float ADS8688_ReadVoltage(uint8_t channel) { int16_t raw ADS8688_ReadChannel(channel); float full_scale 10.24f; // 根据设置的量程修改 return (float)raw * full_scale / 32768.0f; }这里有个容易踩的坑很多新手会直接用raw乘以量程再除以65536这等于把双极性数据当成单极性处理算出来的电压值整个偏移了半个量程。16位ADC的补码范围是-32768到32767正负满量程分别对应正负最大值所以分母必须是32768而不是65536。量程选择上如果没有特殊需求我一般建议选±10.24V。信号幅度接近满量程时量化误差占的比例最小。如果实际信号最大只有1V那就配置成±1.024V量程把精度用足。比如测一个0-1V的传感器输出用±10.24V量程时1V只占约9.7%的满量程有效分辨率不到12位换到±1.024V量程后同样一个信号能用到98%的满量程实际有效位数接近16位。4. 调试中的典型问题与排查技巧4.1 常见问题速查我在几个项目里从零调试ADS8688把遇到的典型问题整理成了表格现象可能原因处理方法MISO一直无输出读回0xFF或0x00SDO接错、SPI模式配置错误检查接线确认SPI配置为Mode 1只有第一个通道读数正确其它通道不对通道选择命令未生效寄存器配置被覆盖每次读通道前重新发送通道选择命令电压读数整体偏大或偏小量程寄存器配置与实际信号不匹配核对当前量程修改换算公式中的满量程值数据跳动超过±5个LSB电源纹波大、基准电容太小、信号源内阻过高改善AVDD去耦增加REFCAP电容输入端加RC滤波上电后第一次读数始终是0没有正确复位芯片或者命令帧超时初始化时增加硬件复位检查CS时序等待时间采样率提上去后偶尔丢帧SPI时钟过快或CS时序不满足要求降低SPI分频使用DMA时注意CS释放时机4.2 排错思路与实测心得如果你遇到MISO完全没有输出的情况别急着怀疑芯片坏了。先用逻辑分析仪或示波器抓CS、SCLK、SDI三根线确认初始化代码有没有真正执行到SPI发送。很多情况下是STM32的SPI时钟没有使能或者GPIO复用功能没配置对。我就有一次忘了在CubeMX里勾选SPI1的MISO引脚复用结果代码跑得欢数据线上一片死寂。另外建议把所有ADC通道都接地先读一遍原始数据看能不能稳定在读到一个接近0x0000的固定值。这能快速判断SPI链路和芯片基本功能是否正常。再给某个通道接一个精准的10V电压源对照换算出来的电压值误差应该在±10mV以内。如果偏差较大优先检查量程寄存器是不是真的写进去了——可以用SPI回读寄存器内容确认。自动扫描模式我也提一句。ADS8688支持配置自动扫描序列把8个通道全部加进序列后一次读取命令就能循环输出所有通道结果。这个模式配合DMA用很香能够让MCU在采集期间去处理其它任务。但初始化时的序列配置寄存器一定要按手册设置清楚少配一个通道或顺序配错读回来的数据就不是你预期的通道顺序。我在某个项目里需要用500kSPS采样率连续采集4个通道用自动扫描加DMA双缓冲之后MCU的负载率从原来的86%骤降到23%效果非常明显。最后再给一个小建议ADS8688的手册里关于寄存器位的描述表格要仔细看不同版本的数据手册对某些保留位的说明可能不一样。写驱动的时候把寄存器地址用宏定义单独放在一个头文件里加上注释说明对应手册页码过几个月回头看代码时能省不少时间。本文还有配套的精品资源点击获取
返回列表