news 2026/9/9 23:43:44

STM32F407 SPI读取AD7606 8通道同步采样ADC实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F407 SPI读取AD7606 8通道同步采样ADC实战指南

简介:面向STM32嵌入式开发者的AD7606串行采集工程,基于Cortex-M4内核的STM32F4系列,重点演示如何配置SPI总线参数,与十六位高精度模数转换器完成通信,实现多通道模拟电压信号的采集、解析与换算,适合工业控制、数据采集系统、测试测量等场景的中高级开发者参考。工程压缩包共181个文件,以C语言源文件、头文件、编译中间文件及工程配置文件为主,并附有可直接烧录的编译产物,整体大小仅4.35MB,目录结构清晰,便于导入开发环境学习或二次修改。目前已有2279人学习与下载,是理解硬件抽象层库中SPI外设驱动及AD7606控制时序的典型范例。资源涵盖时钟极性与相位设置、采样率配置、通道选择与数据读取等完整实现,并包含解析后电压结果的计算与校准思路;初学者可在现有工程上调整通道、采样率与参考电压,快速迁移至其他模拟量采集项目。 最近在调一个多通道同步采样项目,需要在STM32F407上用SPI读取AD7606的8通道16位数据。AD7606这个ADC在工业控制、电力监控里很常见,最大特点是8通道同步采样,所有通道在同一瞬间被锁存,而不是像多路模拟开关那样逐个轮询。为了省GPIO,我放弃了并行总线,直接用SPI做串行采集,折腾了几天把时序和代码跑通后,这篇文章就把整个方案、接线、代码和踩过的坑都写下来,给正要碰这个芯片的人一个参考。如果你正用STM32F4(F407、F401都适用,以下以F407为例)接AD7606,不管是做三相电采集、振动监测还是多路传感器同步采样,这篇都值得看完,尤其是SPI相位选择和CS控制这两块,网上不少例程其实没讲透。

1. AD7606串行采集方案:先搞清楚你到底在用什么芯片

1.1 AD7606的核心特性

AD7606是ADI推出的8通道、16位同步采样ADC,单5V供电却支持真正的双极性模拟输入,输入范围可以通过RANGE引脚在±5V和±10V之间切换。这个特性意味着前端不需要再加正负电源供电的调理电路,直接就能接互感器次级、电流采样电阻或者振动传感器输出,对硬件设计非常友好。

芯片内部还集成了2.5V基准源、钳位保护和数字滤波(过采样)功能,最大吞吐率200kSPS。工业现场常见的工频信号、电机电流、音频信号,它都能覆盖。最关键的是“同步采样”这四个字:8个通道共享同一个采样时刻,通道间的相位差只由前端运放引入,这比用多路开关逐通道切换的方案在相位一致性和实时性上强太多了。

1.2 并行、串行、字节接口怎么选

AD7606的接口不是只有串行一种,它总共支持三种模式:16位并行接口、串行接口、并行字节接口。接口模式由PAR、SER、BYTE三个引脚的电平组合决定,硬件上有个固定逻辑,不能软件配置。

  • 并行接口:8个通道的数据同时出现在DB0-DB15上,用一片74LVC245之类的缓冲器接MCU,读取速度最快,但至少要占16个IO口。
  • 串行接口:数据通过DOUTA(或者DOUTA加DOUTB两根线)逐位输出,只需占用SCLK、MISO、CS三根信号线,IO占用最少。
  • 并行字节接口:并行接口的一种变体,高字节和低字节分两次读取,速度居中,但IO占用没有本质降低。

在实际项目中,我选择串行模式的核心原因就是MCU引脚太紧张。STM32F407虽然IO够多,但一个系统里还要挂通讯、显示、按键、调试口,把16个IO都砸给ADC不现实。串行模式下,除了三根SPI线,再加上BUSY、CONVST、RESET三个控制脚,总共6个GPIO就能搞定8通道同步采集,这个性价比相当高。

2. 硬件接线与原理图要点

2.1 STM32F407和AD7606的引脚级连接

我的方案里,SPI用SPI1,SCLK、MISO分别接到PA5和PA6,MOSI不用(AD7606只需要接收SCLK,不需要输入数据)。CS、BUSY、CONVST、RESET都从其他GPIO引出来,不占SPI硬件片选。完整对应关系如下:

STM32F407引脚功能AD7606引脚备注
PA5SPI1_SCKSCLK串行时钟输入
PA6SPI1_MISODOUTA串行数据输出到MCU
PC0GPIO输出CS片选,低电平有效
PC1GPIO输入BUSY转换忙指示,下降沿表示转换完成
PC2GPIO输出CONVST_A + CONVST_B两脚并在一起,统一触发
PC3GPIO输出RESET上电复位脉冲
-3.3VVIO接口电平,与MCU电平一致
-5VAVCC模拟电源
-3.3VREF_SELECT高电平选内部2.5V基准
-GND / 3.3VRANGE接GND为±5V,接VIO为±10V
-GNDOS0、OS1、OS2过采样配置,接GND关闭过采样
-GNDPAR,BYTE配合SER置高,选择串行16位模式
-3.3VSER置高,选择串行接口

这里有个隐藏点:AD7606的8通道同步采样需要CONVST_A和CONVST_B同时触发。如果只接了CONVST_A,那只有V1-V4这4个通道会被触发,V5-V8不工作。很多初次接触的人在这里栽过跟头,原理图上一定要把两个CONVST引脚并联到同一个GPIO上。

还要注意RANGE引脚的选择。它决定了模拟输入满量程,接低电平是±5V,接高电平是±10V。这个需要根据你的信号大小提前定下来,因为它不仅影响量程,还直接影响分辨率:同样的16位,在±5V量程下1个LSB约0.15mV,在±10V量程下约0.3mV。能选小量程就不选大量程,这是提高测量精度的最简单手段。

2.2 电源、基准、去耦电容别草草了事

AD7606是一个模拟前端芯片,电源处理如果太随意,后面代码写得再漂亮也白搭。我建议AVCC每个电源引脚旁边都放一个0.1uF陶瓷电容,再加一个10uF的钽电容做整体储能。VIO虽然只是接口逻辑电源,也要加去耦,因为它直接决定了DOUTA输出电平的稳定度。

基准部分,REF_SELECT接高电平使用内部2.5V基准,这个方案最简单。但要注意,REFCAP_A/B和REFCAP_C/D这几个引脚必须接10uF电容到GND,而且电容要尽量靠近引脚。这个电容一旦漏贴或者用得太小,采出来的数据会出现明显的漂移和噪声,排查起来很头疼。

PCB布局上,模拟输入走线要远离SCLK和数字信号线,最好用地线隔离。ADI的参考设计里,模拟地和数字地是单点连接的,AD7606芯片底部的地焊盘也要处理好,不能悬空。我做过一次改版,把AD7606放到板边、输入端用排针直接接互感器,结果数据很干净;另一版布局时SCLK走线绕过了输入端子附近,噪声明显偏大,后来调整走线才解决。只能说,这类混合信号芯片,布局的优先级比画线美观高得多。

3. 时序分析:决定成败的关键时钟关系

3.1 从CONVST到BUSY到SCLK的完整读取流程

AD7606串行读取的完整流程可以拆成这样几步:

  1. 给CONVST一个上升沿,启动一次8通道同步转换。CONVST低电平脉宽至少25ns,通常用GPIO拉高拉低就能满足。
  2. 转换开始后BUSY引脚立即拉高,表示芯片正在转换。这个高电平持续时间典型值为3.65us,具体由转换时钟决定。
  3. BUSY拉低时,表示转换完成,8个通道的数据已经锁存到内部寄存器。
  4. 这时把CS拉低,开始在SCLK的驱动下读取数据。每来一个SCLK上升沿,DOUTA上就稳定输出一位数据,MSB在前。
  5. DOUTA会依次输出V1到V8这8个通道的16位数据,一共需要128个SCLK。读完后把CS拉高,一次完整采集结束。

关键点在于,CS拉低之后DOUTA上的第一位数据是在第一个SCLK边沿之前就准备好的,SCLK只是负责把后续的位逐个推出来。也就是说,AD7606的数据更新发生在SCLK的上升沿,数据在下降沿时保持稳定。这种特性直接决定了SPI相位怎么选。

3.2 SPI模式与时钟分频的选型计算

SPI有四种模式,区别在于时钟极性和相位。AD7606要求SPI主机在SCLK的下降沿采样MISO数据,因为它的数据是在上升沿更新的。对照SPI的模式定义,这正是CPOL=0、CPHA=1,也就是SPI Mode 1。

在CubeMX里对应设置是:

  • Clock Polarity:Low(空闲时SCK为低)
  • Clock Phase:2 Edge(数据在第二个边沿采样)

我第一次调试时图省事用了默认的Mode 0(CPHA=0),结果读出来的数据总是觉得不对劲,高三位和低三位乱套,后来对着逻辑分析仪看了半天,才发现是相位选错了。这个必须写在最前面。

时钟频率方面,AD7606的SCLK上限是25MHz。STM32F407的SPI1挂在APB2上,主频168MHz时APB2是84MHz,预分频4就是21MHz,刚好压在25MHz以内。预分频2是42MHz,超限了,不能选。使用21MHz时,128个SCLK的读取时间约6.1us,加上3.65us转换时间,单次采集周期约10us,等效采样率能到100kSPS左右,对大多数应用足够了。

如果确实需要更快,可以上DOUTA和DOUTB双线模式,64个SCLK就能读完全部8通道。但这个方案需要SPI同时接收两根MISO线上不同步的数据,或者用第二个SPI,工程复杂度高,后面章节会细说。

3.3 为什么AD7606采集要用软件片选,而不是硬件NSS

这里值得单独说。SPI通信里片选分硬件NSS和软件GPIO两种,AD7606强烈建议用软件片选。

原因是AD7606一次完整的读取需要128个连续的SCLK脉冲,整个读取过程CS必须一直保持低电平。STM32F4的硬件NSS在标准SPI模式下,是跟着每一次数据帧走的。如果配置成8位数据帧,硬件NSS很难以一个连续的低电平覆盖16个字节的传输;就算用软件控制NSS输出,也要小心翼翼配置NSS脉冲模式,稍有不慎就会在字节边界出现额外的片选毛刺,AD7606会把CS的每次拉高当成一帧结束,数据直接错乱。

用GPIO模拟CS就完全没有这个问题。代码里先把CS拉低,然后连续收发16个字节,最后再把CS拉高,整个128个SCLK完全连续,与SPI外设的数据帧长度无关。这个操作看似简单,但在实际调试中能避免一大半的时序问题。

4. CubeMX配置与代码实现

4.1 CubeMX初始化要点

工程初始化我用的是STM32CubeMX,版本不重要,重要的是这几个配置项:

  1. RCC:HSE选择Crystal/Ceramic Resonator,保证系统主频168MHz。
  2. SPI1:Mode选择Full-Duplex Master,虽然AD7606不需要MOSI写数据,但全双工模式下接收逻辑最简单,收发一个指令就能同时产生SCLK并收到MISO数据。
  3. SPI1参数:Baud Rate Prescaler设为4,Clock Polarity设为Low,Clock Phase设为2 Edge,Data Size设为8bit,First Bit设为MSB First。
  4. GPIO:PC0(CS)、PC2(CONVST)、PC3(RESET)设为Output;PC1(BUSY)设为Input。

这里有个小细节:如果你用的是国产F4系列或者换了具体型号,第一次在Keil里打开工程可能会提示找不到器件,原因是MDK的Device Pack没装全。在Pack Installer里找到STM32F4xx_DFP装好,然后重新选一次芯片型号,编译就不会报错了。这个和AD7606没关系,但确实是新手经常卡住的地方。

4.2 AD7606驱动代码:触发、等待、读取、解析

下面的代码可以直接放到工程里用,我保留了最核心的部分,省略了错误处理宏。

#define AD7606_CS_LOW() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) #define AD7606_CS_HIGH() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) #define AD7606_CONVST_LOW() HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_RESET) #define AD7606_CONVST_HIGH() HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_SET) #define AD7606_RESET_LOW() HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET) #define AD7606_RESET_HIGH() HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET) void AD7606_Reset(void) { AD7606_RESET_HIGH(); delay_us(1); AD7606_RESET_LOW(); } void AD7606_StartConv(void) { AD7606_CONVST_LOW(); delay_us(1); AD7606_CONVST_HIGH(); // 上升沿触发转换 delay_us(1); AD7606_CONVST_LOW(); } int AD7606_ReadAllChannels(int16_t *values) { uint8_t rx[16]; uint8_t dummy[16] = {0}; uint32_t timeout = 10000; AD7606_StartConv(); // 等待BUSY变低,表示转换完成 while (HAL_GPIO_ReadPin(BUSY_GPIO_Port, BUSY_Pin) == GPIO_PIN_SET) { if (--timeout == 0) { return -1; // 超时 } } AD7606_CS_LOW(); // 收发16字节,产生128个SCLK,同时从DOUTA读回8通道数据 HAL_SPI_TransmitReceive(&hspi1, dummy, rx, 16, 100); AD7606_CS_HIGH(); // 解析:每个通道16位,MSB在前,二进制补码 for (int i = 0; i < 8; i++) { uint16_t raw = ((uint16_t)rx[i * 2] << 8) | rx[i * 2 + 1]; values[i] = (int16_t)raw; } return 0; }

使用示例:

int16_t adc[8]; if (AD7606_ReadAllChannels(adc) == 0) { // adc[0]对应V1,adc[1]对应V2,以此类推 float v1_mv = adc[0] * 5000.0f / 32768.0f; // RANGE接GND时为±5V量程 }

BUSY等待为什么要加超时?因为如果AD7606没正常工作或者引脚没连好,BUSY一直为高,没有超时的话程序会死等在那里,整块板子就“假死”了。实测里最常见的现象就是CS、SCLK没接对,BUSY信号悬空刚好读回高电平,导致程序卡死在等待循环里。加个超时,至少能确定问题出在哪一步。

4.3 连续采集与DMA提速方向

单次读取满足了基本功能,但如果要做FFT或者波形分析,就需要连续不断采样。最常见的做法是把读取放到定时器中断里:定时器触发一次,AD7606_ReadAllChannels执行一次,结果存入环形缓冲区。定时器频率就是采样率,比如10kHz。

更高效的做法是用DMA。把SPI接收改成DMA方式后,CS拉低、启动DMA、DMA传输完成中断里拉高CS和解析数据,整个读取过程不占用CPU。实测F407在21MHz SPI下,DMA方式读取128位数据只需6us左右,CPU占用率极低。注意DMA模式下,CS拉低的时机要在DMA启动之前,而且CS拉高的时机必须在DMA传输完成中断里,不能放在主循环里,否则两次采集之间会产生不确定的时间缝隙。

过采样功能也可以通过OS引脚打开,OS0、OS1、OS2组合可以选择2倍、4倍、8倍等过采样率,内部相当于做了数字滤波,能有效抑制宽带噪声。但要注意过采样会降低有效采样率,具体倍率和采样率的取舍,需要按手册表格来定。

5. 常见问题与排查实录

5.1 数据全是0x00、0xFFFF或者乱跳

这是问到最多的问题。数据全是0x00,通常是MISO没通,可能是DOUTA没接到PA6,或者PA6的复用功能没配好。数据全是0xFFFF,说明时钟没正常到达AD7606,先量一下PA5和AD7606 SCLK引脚之间是否导通,再看CubeMX里SPI有没有使能。乱跳则首先怀疑BUSY等待没做对,数据在读之前根本没转换完成就拉低CS了。

排查时我习惯用逻辑分析仪抓SCLK、CS、BUSY、DOUTA四根线。CS拉低后DOUTA应该在第一个SCLK边沿前就已经出现最高位,如果看到DOUTA在整个CS低电平期间都没有变化,问题基本出在AD7606侧,比如SER引脚没接高、芯片处于并行模式,或者芯片压根没退出复位状态。

5.2 高位和低位错位,像数据整体移了一位

这种症状我遇到过一次,现象是读出的16位数据里,把某个通道的真实值左移或右移了一位,而且低几位出现奇怪的0或1。这基本可以断定是SPI相位不对。AD7606要在下降沿采样,如果配置成了Mode 0(上升沿采样),第一位可能采到了MSB刚出现的跳变状态,导致整帧数据错位。

解决办法:把Clock Phase改成2 Edge,也就是CPHA=1。如果改了之后数据高低位顺序变了方向,那就检查First Bit是不是MSB First。记住,对于AD7606,SPI Mode 1 + MSB First是成套的组合,缺一不可。

5.3 DOUTA和DOUTB双线提速到底划不划算

前面说过,如果需要更高采样率,可以用DOUTA加DOUTB双线读取,64个SCLK就能完成8通道。DOUTA输出V1-V4,DOUTB输出V5-V8。问题是STM32F407的SPI只有一个MISO,把DOUTB接到另一个SPI的MISO,两个SPI需要同时产生SCLK才能同步采样,两个SPI必须配置成完全相同的时钟参数,还要用同一个主频和同样的分频,这在实际工程里不是不能做,但有点折腾。

另一种更简单的双线变通是:DOUTA接SPI的MISO,DOUTB接一个普通GPIO,然后用软件模拟的方式在SCLK下降沿同时读取GPIO和SPI数据寄存器,本质是半软件半硬件。实测这个方案能提速,但代码复杂度高,而且容易因为时序抖动导致采样不稳定。如果单片机引脚确实不够,还是老老实实128个SCLK单线读;如果对速度有硬指标,干脆改用并行接口或者换带两个SPI的大容量型号,更稳妥。

5.4 顺带聊聊:SPI和I2C为什么在这个场景没得选

从热搜词里看到很多人在对比SPI和I2C,这里说下AD7606相关的一个结论:AD7606根本不支持I2C,它只有并行总线和SPI-like的串行接口。这背后的原因是性能,I2C的时钟最高也就几兆赫,而且有应答位和地址帧,数据吞吐率远不如SPI,做8通道16位高速同步采样根本不够用。SPI是全双工、无地址开销、时钟可以跑到几十兆赫,跟AD7606这种需要持续移出大量数据的ADC是绝配。I2C更适合接温湿度传感器、EEPROM这类低速小数据量的设备。选型的时候,看到“同步采样、200kSPS、16位”这些关键词,不要花时间去想I2C,直接SPI或者并行。

我在实际项目中踩过最大的坑,其实是“以为AD7606和普通SPI Flash一样,随便配置个SPI模式就能读”。AD7606严格说是个SPI-like接口,不是标准SPI从机,它不响应任何命令,也不回读寄存器,只是被动地把数据一位一位推出来。搞清楚这个本质后,后续的时序配置、CS控制和代码逻辑就都顺理成章了。这个理解比任何一个现成例程都重要,建议你在自己项目里也带着这个思路去读数据手册。后面如果想继续扩展,可以试试用定时器触发DMA读取做连续采样,或者用两片AD7606做16通道同步采集,原理上都是同一套时序逻辑,只是在数据处理和同步触发上再多花点功夫。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 23:43:27

用15个Claude智能体重构研发流程:多Agent协作实战指南

"一个人要干一整个公司的活"这话换在五年前我是打死不信的&#xff0c;直到我认真跟这个由YC掌门人带火的开源玩法死磕了两周&#xff0c;用一整套Claude智能体矩阵把原本至少需要七八个人的研发流程硬生生扛了下来。这篇文章不聊虚的&#xff0c;就讲15个硬核Agent怎…

作者头像 李华
网站建设 2026/9/9 23:42:35

IB网卡安全驱动与虚拟化流程详解:从驱动安装到SR-IOV性能验证

IB 网卡这东西&#xff0c;插进服务器以后如果不装驱动&#xff0c;那就是一块昂贵的废铁&#xff1b;装好了驱动但没规划好虚拟化流程&#xff0c;到了生产环境又会变成一块“定时炸弹”。我在 HPC 集群和数据中心运维这块折腾了多年&#xff0c;InfiniBand 网卡&#xff08;以…

作者头像 李华
网站建设 2026/9/9 23:39:49

分布式事务实战:解冻支付场景下的TCC、幂等与最终一致性设计

先讲一个我凌晨两点被电话叫醒的案子。监控群里连续刷出十几条资金流水不平的告警&#xff0c;客服那边也炸了锅&#xff0c;有用户说订单取消了但钱一直没回来&#xff0c;另一拨人却反馈钱退了但订单还卡在支付中不敢动。两个方向上看起来完全相反的问题&#xff0c;最后都指…

作者头像 李华
网站建设 2026/9/9 23:39:39

STM32 IAP实战:YMODEM协议Bootloader设计与跳转卡死排查

简介&#xff1a;面向STM32嵌入式开发者的IAP Bootloader实践资料&#xff0c;基于YModem协议实现串口在线升级方案&#xff0c;完整覆盖bootloader启动、数据接收、CRC校验、Flash写入及跳转APP的关键流程。压缩包共475个文件&#xff0c;以C语言源码、头文件、编译生成的.o/.…

作者头像 李华