拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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做串行采集折腾了几天把时序和代码跑通后这篇文章就把整个方案、接线、代码和踩过的坑都写下来给正要碰这个芯片的人一个参考。如果你正用STM32F4F407、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用SPI1SCLK、MISO分别接到PA5和PA6MOSI不用AD7606只需要接收SCLK不需要输入数据。CS、BUSY、CONVST、RESET都从其他GPIO引出来不占SPI硬件片选。完整对应关系如下STM32F407引脚功能AD7606引脚备注PA5SPI1_SCKSCLK串行时钟输入PA6SPI1_MISODOUTA串行数据输出到MCUPC0GPIO输出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关闭过采样-GNDPARBYTE配合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串行读取的完整流程可以拆成这样几步给CONVST一个上升沿启动一次8通道同步转换。CONVST低电平脉宽至少25ns通常用GPIO拉高拉低就能满足。转换开始后BUSY引脚立即拉高表示芯片正在转换。这个高电平持续时间典型值为3.65us具体由转换时钟决定。BUSY拉低时表示转换完成8个通道的数据已经锁存到内部寄存器。这时把CS拉低开始在SCLK的驱动下读取数据。每来一个SCLK上升沿DOUTA上就稳定输出一位数据MSB在前。DOUTA会依次输出V1到V8这8个通道的16位数据一共需要128个SCLK。读完后把CS拉高一次完整采集结束。关键点在于CS拉低之后DOUTA上的第一位数据是在第一个SCLK边沿之前就准备好的SCLK只是负责把后续的位逐个推出来。也就是说AD7606的数据更新发生在SCLK的上升沿数据在下降沿时保持稳定。这种特性直接决定了SPI相位怎么选。3.2 SPI模式与时钟分频的选型计算SPI有四种模式区别在于时钟极性和相位。AD7606要求SPI主机在SCLK的下降沿采样MISO数据因为它的数据是在上升沿更新的。对照SPI的模式定义这正是CPOL0、CPHA1也就是SPI Mode 1。在CubeMX里对应设置是Clock PolarityLow空闲时SCK为低Clock Phase2 Edge数据在第二个边沿采样我第一次调试时图省事用了默认的Mode 0CPHA0结果读出来的数据总是觉得不对劲高三位和低三位乱套后来对着逻辑分析仪看了半天才发现是相位选错了。这个必须写在最前面。时钟频率方面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版本不重要重要的是这几个配置项RCCHSE选择Crystal/Ceramic Resonator保证系统主频168MHz。SPI1Mode选择Full-Duplex Master虽然AD7606不需要MOSI写数据但全双工模式下接收逻辑最简单收发一个指令就能同时产生SCLK并收到MISO数据。SPI1参数Baud Rate Prescaler设为4Clock Polarity设为LowClock Phase设为2 EdgeData Size设为8bitFirst Bit设为MSB First。GPIOPC0CS、PC2CONVST、PC3RESET设为OutputPC1BUSY设为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]对应V1adc[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也就是CPHA1。如果改了之后数据高低位顺序变了方向那就检查First Bit是不是MSB First。记住对于AD7606SPI Mode 1 MSB First是成套的组合缺一不可。5.3 DOUTA和DOUTB双线提速到底划不划算前面说过如果需要更高采样率可以用DOUTA加DOUTB双线读取64个SCLK就能完成8通道。DOUTA输出V1-V4DOUTB输出V5-V8。问题是STM32F407的SPI只有一个MISO把DOUTB接到另一个SPI的MISO两个SPI需要同时产生SCLK才能同步采样两个SPI必须配置成完全相同的时钟参数还要用同一个主频和同样的分频这在实际工程里不是不能做但有点折腾。另一种更简单的双线变通是DOUTA接SPI的MISODOUTB接一个普通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通道同步采集原理上都是同一套时序逻辑只是在数据处理和同步触发上再多花点功夫。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门