树莓派上跑数据采集,最烦的不是写代码,而是硬件通道死活不够用。我手头这块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到5V,76微伏的噪声底完全不会影响读数。
芯片内部还集成了可编程增益放大器,增益档位可以从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里加上一行dtparam=i2c_arm=on,然后重启生效。重启之后,先用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位ADC,2的补码,满量程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三个焊盘或者三组跳线。地址计算公式通常是基础地址加上二进制权重,比如基础地址是0x48,A0焊盘短接代表加1,A1短接代表加2,A2短接代表加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里的dtparam=i2c_arm=on有没有写对;第二步查硬件接线,板子和树莓派是不是插到底了,有没有歪针;第三步查供电,板子上的电源指示灯有没有亮,没亮就换一个供电口试;第四步查地址冲突,用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里配置dtparam=i2c_arm_baudrate=400000,但前面说了,堆叠多层的时候高速模式可能不稳定,要自己权衡;另一个是只采集需要的通道,减少通道切换和读取次数;还有一个是让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采集卡的体积和驱动折腾过的人,可以试试这条路。根据我自己的经验,先拿两块板子叠起来跑通,再扩展到八层,整个过程两三天就能搞定,踩平了坑之后,后续加传感器就是插线配置的事情。