尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

树莓派DAQ HAT堆叠扩展:8层64路模拟采集实战指南

树莓派DAQ HAT堆叠扩展:8层64路模拟采集实战指南 树莓派上跑数据采集最烦的不是写代码而是硬件通道死活不够用。我手头这块DAQ HAT算是把这事儿解决得比较彻底——单块板卡提供8路模拟输入关键是支持I2C地址跳线最多可以叠八层直接扩到64路单端采样。这一篇就跟你聊聊这块板子的完整使用心得从硬件设计思路、堆叠原理、驱动配置到实际采数过程中的坑一次说清楚。适合正在做工业监测、环境数据记录、实验室自动化这类项目的人参考哪怕是刚接触树莓派和DAQ的新手照着操作也能跑起来。1. 这块DAQ HAT到底解决什么问题1.1 树莓派做数据采集的尴尬处境树莓派的GPIO引脚听起来挺多40根针脚但真正能用来做模拟量采集的通道几乎为零。它原生只有数字输入输出外加I2C、SPI、UART这类数字通信接口。如果你要采集温度传感器输出的0到5V模拟电压、压力变送器送来的4到20mA电流信号或者应变片电桥这种微弱差分信号树莓派自己是完全没法直接读的。以前的做法是外接一块USB数据采集卡或者用Arduino当从机先把模拟量转成数字量再通过串口丢给树莓派。这两条路都能走但各有各的难受USB DAQ体积大、要拖线、供电还容易出问题Arduino方案精度一般采样率也上不去而且软件上还要维护两套固件和协议。后来出现了HAT这个标准全称是Hardware Attached on Top就是树莓派官方定义的扩展板规范。HAT板子直接插在树莓派的40针GPIO排针上尺寸和树莓派主板对齐叠上去像三明治一样。这种形态天然适合做数据采集电源、I2C、SPI全部通过排针直连不占USB口也不用外接电源拧上铜柱就固定住了。不过市面上大多数树莓派DAQ HAT都只有一个固定地址插一块就占死整个I2C总线想扩通道只能换更大通道数的板子灵活性很差。1.2 八层堆叠能带来什么这块DAQ HAT设计上把地址做成了可配置的通过板上的跳线电阻或者拨码开关可以在I2C地址空间里选择多个不同的地址。你叠一块它占用的是0x48再叠一块跳线改成0x49再叠第三块、第四块一直到八块每块都能被树莓派独立识别。这样一套下来的通道数就是8乘以8等于64路单端模拟输入。64路意味着什么我举个例子。你在做一个温室大棚的环境监测系统需要采集八个区域的温湿度、土壤水分、光照强度和二氧化碳浓度每类传感器四路这也就是32路。用传统USB方案可能得买两到三张采集卡还要配USB Hub软件上要分别管理多个设备用这块HAT的方案四块叠起来就够了整机就是树莓派加四层扩展板放一个防水盒里干净利落。再比如说设备状态监测给生产线上的六台电机各配一个振动传感器和一个电流互感器需要12路同步采集那两块HAT叠起来刚好机柜里占的空间很小。当然堆叠也不是无限的I2C总线的地址数量、电容负载、总线上拉强度都是约束条件。目前官方设计验证过的是八层也就是64路这对绝大多数中小型采集项目来说已经非常充裕了。而且整条I2C总线工作频率在100kHz标准模式下也能轻松覆盖常见传感器的采样需求。2. 硬件设计与选型思路2.1 核心ADC芯片与精度要做数据采集模拟信号转数字信号这块是关键。这块HAT选用的ADC是16位的逐次逼近型芯片单端输入支持8通道差分输入支持4通道。16位的分辨率意味着什么拿0到5V量程来算理论最小分辨率是5除以2的16次方也就是大约76微伏。这个精度放在工业传感器信号采集里面已经非常能打了常见的4到20mA电流环信号经过250欧取样电阻变成1到5V76微伏的噪声底完全不会影响读数。芯片内部还集成了可编程增益放大器增益档位可以从1倍到8倍甚至更高。这个功能特别实用因为不同类型的传感器输出范围差很多热电偶的输出只有几毫伏到几十毫伏如果直接进ADC就浪费了分辨率把增益调到8倍或者16倍就能把这些微弱信号放大到接近满量程采出来的数据才够看。板子上还有基准电压源温漂系数做得比较低长时间运行的时候读数漂移不会太离谱。我实际对比过这块板子和我之前用的一块12位USB采集卡同样的传感器、同样的供电环境12位卡采出来的数据波动有十几毫伏换到这块HAT之后波动降到了两三个毫伏以内。这不是玄学是有效位数的差距实打实反映在噪声性能上。2.2 模拟前端与信号调理ADC精读再高前端不干净也是白搭。这块HAT在模拟输入端加了一级RC滤波还有一个运算放大器做缓冲。RC滤波的作用是滤掉高频干扰比如电机启动瞬间产生的尖峰或者PWM信号串进来的噪声。运放缓冲的作用是提高输入阻抗避免传感器直接被ADC的采样电容拉垮。有些传感器内阻很高不带缓冲直接采样读数会明显偏低接上缓冲之后才能保证信号源不受影响。板上还做了输入过压保护模拟输入引脚可以承受正负一定范围的反向电压而不损坏芯片。这个设计很贴心实际接线的时候谁还没手抖接反过线没有保护的话一个接反就可能烧掉一片几十块的ADC芯片有保护的话顶多是读数不对排查一下接线就好。另外每个输入通道还有一个分压电阻网络可以把输入量程扩展到更高比如0到10V的工业标准信号。默认出厂配置一般是0到5V想改成0到10V需要动板上的跳线和电阻动手能力强的可以自己改不想折腾的直接买板上已经焊好的版本也行。2.3 堆叠机制与I2C地址分配这是这块HAT最核心的设计。I2C总线上每个设备必须有独立的地址否则多个设备挂在同一条总线上就会互相冲突数据完全乱掉。很多单通道类型的传感器模块就死在这一点上比如某些I2C温度传感器地址是固定的焊死在那里同一个I2C口上只能接一个。这块HAT把地址做成可配置的通过板上三个地址跳线或者一组拨码可以组合出多个不同的地址覆盖0x48到0x4F这个范围。8层堆叠的时候每块板子的地址要通过跳线设置成不同的值然后再叠起来。上下板之间通过排针的I2C信号线级联总线上的电容负载会随着板卡数量增加而变大。八块板叠满的时候我实测SDA和SCL线上的波形边沿会变缓但100kbps的标准模式还是能稳定跑。如果你在超频跑400kbps高速模式可能会遇到偶发通信错误这个下面会专门说。堆叠的时候还有一个细节每块板的地址跳线要在叠上去之前就设好叠上去之后就很难再拨了你要是手伸不进去就只能一块块拆下来重弄别问我怎么知道的。3. 实操从硬件安装到首采数据3.1 接线与硬件安装拿到板子之后别急着往树莓派上插先检查一遍有无运输损伤。这套板卡通常配的是GPIO排母直接把排针对准树莓派40针排母均匀用力压下去就行。注意对准1号引脚也就是靠近TF卡槽那一侧的角落板子上的丝印一般都会标一个三角或者数字1别插反了反插通电的一瞬间就可能把板子烧掉。堆叠多块的时候建议每块板子之间加尼龙铜柱隔开一方面是为了固定结构另一方面也是为了让板子之间留出空气流通的空隙防止长时间运行过热。虽然HAT本身功耗不大但树莓派4B或者CM4在满载跑的时候发热量不小叠得太紧会互相烤。我习惯在每块板的四个角都用M2.5铜柱支撑螺丝不要拧太紧刚好固定住即可。如果用到的是树莓派Compute Module 4的底板方案需要注意CM4核心板的GPIO引脚图和标准40针排针对应关系其实是一致的都是BCM2837系列的引脚复用。网上查CM4 GPIO引脚图的时候重点确认I2C1的SDA和SCL这两个引脚物理位置在CM4底板上一搬也是3号和5号引脚和标准树莓派4B一致。接传感器的时候先把信号线接到HAT的螺丝端子或者排针上正极接正极负极接负极如果是差分输入还要分清楚P和N。3.2 使能I2C并确认设备挂载树莓派默认I2C接口是关闭的需要手动打开。最简单的办法是运行raspi-config在Interface Options里把I2C使能打开然后重启。如果用的是Lite版系统也可以在/boot/config.txt里加上一行dtparami2c_armon然后重启生效。重启之后先用ls /dev/i2c-*看看设备节点有没有正常生成一般会有一个/dev/i2c-1。接下来用i2cdetect -y 1扫描I2C总线上的设备如果HAT接好了并且供电正常你应该能看到类似48、49这样的十六进制地址出现在扫描表里。我第一次用这块板子的时候扫描出来啥都没有排查了半天结果发现是I2C使能之后忘了重启。你要是扫不到设备先别急着怪板子重启、查线、确认供电这三步做完再说。3.3 用Python读取第一路电压确认I2C设备挂载之后就可以写代码读数据了。这里用Python的smbus2库或者adafruit-blinka这类库都能操作。我习惯先用最底层的方式验证通信然后再加上上层封装。最简单的读单通道电压代码如下import smbus2 import time bus smbus2.SMBus(1) address 0x48 # 芯片寄存器配置这里以常见16位ADC为例 config_register 0x01 config_value 0x8380 # 单端输入、增益1、连续转换模式 bus.write_word_data(address, config_register, config_value) while True: data bus.read_i2c_block_data(address, 0x00, 2) raw_value (data[0] 8) | data[1] # 16位ADC2的补码满量程5V if raw_value 0x8000: raw_value - 0x10000 voltage raw_value * 5.0 / 32768.0 print(f通道电压: {voltage:.4f} V) time.sleep(1)这段代码的逻辑很直接先向配置寄存器写入转换参数然后循环读取转换结果把16位原始值换算成电压值。第一次跑通这个代码你能看到稳定的电压读数说明整条链路已经通了。如果读数始终是0或者满量程先查输入线是不是接对了再看量程档位确认不是分压网络把信号衰减掉了。实际使用中我给你一个建议先用一节干电池或者一个可调电源接一个已知电压验证读数对不对再连真实传感器。直接拿传感器试出了问题很难分清到底是传感器坏了、接线错了还是程序有问题。4. 八层堆叠的完整配置与测试4.1 为每一层设置独立I2C地址堆叠之前的关键步骤是给每块板卡设置不同的地址。这块HAT的地址跳线区一般在板子的角落丝印上有A0、A1、A2三个焊盘或者三组跳线。地址计算公式通常是基础地址加上二进制权重比如基础地址是0x48A0焊盘短接代表加1A1短接代表加2A2短接代表加4。所以第一块板全不短接就是0x48第二块只短接A0就是0x49第三块只短接A1就是0x4A以此类推。这里有个坑必须提醒你焊盘短接之后你最好用万用表确认一下确实导通因为有些PCB焊盘的过孔被绿油盖住了看起来焊上了实际是虚焊。另外建议把每块板子的地址用标签纸贴在板上叠起来之后就看不到了不贴标签要排查问题的时候只能一块一块拆特别浪费时间。我自己的习惯是每块板子除了贴地址标签还会在纸上画一个堆叠图记录哪一层是哪个地址、接的什么传感器这个表在后面调程序的时候非常有用。4.2 级联供电与总线负载验证八块板叠起来之后整摞板子的供电和信号完整性都要留意。树莓派的5V引脚输出能力有限常规供电下能提供的电流大概在1.5A到2A左右还要扣除树莓派自身的功耗叠加多层HAT之后要给每一层的模拟电路供电电流需求不可小觑。建议堆叠超过四层的时候用外部的5V电源通过树莓派的USB-C口供电或者直接给HAT的供电端子供一路独立5V电源。叠好之后再用i2cdetect -y 1扫描一次这次应该能看到8个连续的地址。如果少了一个别着急拆先用万用表测一下那块板子的供电引脚有没有电压再看它的地址跳线是不是跟别的板重了。I2C协议里如果两个设备地址相同总线上会出现应答混乱扫描结果有时会跳动、有时会死锁这时候扫到的设备数会忽多忽少是很典型的地址冲突症状。4.3 多板卡读取程序框架八块板卡同时工作的时候程序上要做的就是轮询每个I2C地址的转换结果。这里可以写一个简单的字典来管理每个通道的映射关系import smbus2 import time bus smbus2.SMBus(1) # 地址 - 通道信息映射 board_channels { 0x48: [0, 1, 2, 3], 0x49: [0, 1, 2, 3], # 实际按你的配置继续加 } def read_channel(address, channel): # 根据ADC芯片手册改通道需要重新写配置寄存器 config_base 0x8000 | (channel 12) bus.write_word_data(address, 0x01, config_base) time.sleep(0.01) # 等待转换完成 data bus.read_i2c_block_data(address, 0x00, 2) raw (data[0] 8) | data[1] if raw 0x8000: raw - 0x10000 return raw * 5.0 / 32768.0 while True: for addr, chs in board_channels.items(): for ch in chs: value read_channel(addr, ch) print(f板卡 {hex(addr)} 通道 {ch}: {value:.4f} V) time.sleep(1)这个框架本身很简单真正要注意的是切换通道之后需要留一点稳定时间。因为ADC的输入多路复用器切换之后采样电容需要时间充电到新的输入电压如果上一次通道电压很高、下一次很低切换之后立刻读数值会有一个明显的过渡过程。我实测切换后等10毫秒上下读数就比较稳定了。另一个方案是让ADC在后台连续转换固定通道然后并发地去读不同地址但这样每个地址只能读一个通道没有刚说的通道切换方案灵活。如果项目里每个通道的传感器是固定接好的我建议每块板卡只用一个通道这样就不用在通道切换上纠结了。5. 常见问题排查与避坑5.1 I2C设备识别不到的完整排查这个问题出现的频率最高而且原因五花八门。我把排查路径按优先级列一下第一步查系统配置确认I2C内核模块有没有加载/boot/config.txt里的dtparami2c_armon有没有写对第二步查硬件接线板子和树莓派是不是插到底了有没有歪针第三步查供电板子上的电源指示灯有没有亮没亮就换一个供电口试第四步查地址冲突用i2cdetect多看几次看扫描结果是否稳定第五步查板子本身拿一块单独叠到树莓派上看能不能识别能识别就说明是堆叠过程中的接触问题。我碰到过一个很诡异的情况扫描的时候能看到设备但一读写就报OSError: [Errno 121] Remote I/O error。排查到最后发现是杜邦线把SDA和SCL接反了低层阻塞了总线。这种问题用肉眼很难看出来但只要换个正确接线立马就好。还有一次是因为SCL线上被接了太多传感器模块上拉电阻不够导致信号电平拉不上去。解决方法是在总线上额外加一个4.7k欧的上拉电阻到3.3V或者减少总线上挂的无关设备。5.2 噪声大和读数跳动的处理办法噪声问题是数据采集里逃不掉的话题。刚上手这块HAT的时候如果板子直接叠在树莓派上读出来数据会有几个毫伏的随机跳动这是正常的因为树莓派的开关电源和数字电路会向空间辐射电磁干扰ADC前端再怎么做滤波也挡不住近距离的强干扰源。我做了几件事情之后噪声明显降下来了第一模拟传感器信号线用屏蔽线屏蔽层单端接地第二传感器和HAT之间不要共地回路的环路供电回路尽量星型连接第三程序里对采样结果做滑动平均或者中值滤波这就属于软件层面的降噪了。还有一种情况是读数有明显周期性波动比如50Hz的工频干扰。如果传感器的引线比较长就会像天线一样接收市电频率的干扰信号导致ADC读数里叠了一个正弦波。处理办法是在输入端加一个低通滤波器或者在软件里做一个50Hz的陷波滤波。如果条件允许模拟信号线尽量短传感器就近接HAT比后级加什么滤波都管用。我实测过同样的传感器1米屏蔽线和10厘米普通跳线接出来的数据质量完全没有可比性。5.3 采样率上不去的瓶颈在哪里用I2C接口做数据采集采样率的瓶颈往往不在ADC本身而在I2C传输和软件处理的环节。这块HAT的ADC芯片本身转换速度可以做到每秒几千次但I2C标准模式只有100kbps每次读取两字节数据加命令开销差不多要几百微秒算下来单板全通道轮询也就每秒钟几十次到上百次。如果你需要更高的速率有几个方向可以参考一个是改用I2C高速模式把总线频率提到400kbps这个需要在/boot/config.txt里配置dtparami2c_arm_baudrate400000但前面说了堆叠多层的时候高速模式可能不稳定要自己权衡另一个是只采集需要的通道减少通道切换和读取次数还有一个是让ADC在后台连续转换同一通道软件只负责定期读结果减少配置寄存器带来的开销。如果你的应用对采样率要求非常高比如振动分析需要每通道1kSPS以上那这块HAT可能不太够用建议选SPI接口的独立ADC采集板。但如果是温度、湿度、压力、液位这类慢变化信号每秒几十次的扫描率绰绰有余。5.4 热插拔和静电注意事项树莓派HAT这东西理论上是带电插拔的但实际操作中不建议这么干。因为GPIO引脚在带电状态下插拔容易产生瞬间冲击电流轻则复位重则损坏IO口。我个人的习惯是断电之后再进行叠板、拆板、接线操作。接传感器的时候也先断电再接接好再上电。特别是工业现场电磁环境复杂的地方静电放电可能直接击穿ADC的输入级有条件的话在板卡的模拟输入端加TVS管做ESD保护。还有一点容易被忽略树莓派的3.3V和5V引脚引出的电源能力是有限的如果传感器是直接从HAT的电源引脚取电需要核算总电流。我曾经把两个大功率传感器接到板子上取电结果树莓派直接电压跌落重启了后来改成传感器单独供电数据采集稳定了树莓派也不浪了。传感器供电回路和采集电路的参考地保持共地信号电压才有意义这个别忘了。6. 从单点采集到多通道系统的扩展建议如果你已经把一块HAT跑通了接下来做多通道系统就水到渠成。我建议你在设计整体架构的时候尽量把模拟信号线缆分区域捆扎信号线和电源线分开走避免交流电线和传感器信号线平行走线过长。这种工程细节短期内看不出差别但到了工业现场调试的时候会帮你省掉无数排查干扰的头痛时刻。软件层面如果数据量大了建议把Python的读取程序做成一个后台服务用队列把数据推到数据库或者消息队列后面再接可视化面板。树莓派的CPU做这点事情绰绰有余但别把采集程序和Web服务塞在一个进程里跑回头一个假死全都卡住。用systemd把一个采集服务常驻跑起来别用screen或者nohup挂在终端里重启服务不方便还容易丢数据。我自己的做法是采集进程把原始数据存成CSV按天分割文件然后是另一个进程去解析和入库这样即使数据解析程序挂了原始数据还在不会出现数据丢失的尴尬。如果你做的是在线监测系统还有一个坑得提醒树莓派的SD卡寿命是有限的长时间高频写入数据可能把卡写坏。我把采集数据写到外接固态硬盘或者网络存储上SD卡里只放系统和程序这样数据安全和系统稳定都有保障。数据写坏了还能重新采集系统盘写坏了整个监测站点就黑了。这块DAQ HAT给我最大的感受是省心。以前做一套64路采集系统得用机架式数据采集设备现在树莓派加八层HAT铺开还没有A4纸大成本降了一个数量级性能在慢变信号采集场景下完全够用。如果你也是被USB采集卡的体积和驱动折腾过的人可以试试这条路。根据我自己的经验先拿两块板子叠起来跑通再扩展到八层整个过程两三天就能搞定踩平了坑之后后续加传感器就是插线配置的事情。
返回列表