十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Pi-Face 扩展板实战:树莓派 GPIO 与 CM4 引脚对照及 ADC 读取

Pi-Face 扩展板实战:树莓派 GPIO 与 CM4 引脚对照及 ADC 读取 Pi-Face 这名字一出来熟悉树莓派生态的人大概能猜到七八分它是一块给 Raspberry Pi 用的 GPIO 扩展板。我第一次接触它是在一个物理计算教学项目的实验清单里当时配套文档只有几页 PDF但照着接线、跑通示例代码只花了不到二十分钟这种“插上去就能用”的体验在 GPIO 外设里相当难得。后来我自己做控制类原型也经常把它翻出来用所以这次就专门聊聊这块板子的设计思路、引脚映射以及这段时间大家经常搜的 Compute Module 4 GPIO 引脚图到底该怎么对照。它可以做两路数字输入、两路数字输出和一路模拟输入核心价值是把树莓派裸奔的 GPIO 转换成安全、稳定的控制接口。适合刚接触硬件编程的学生、准备物理计算课件的老师也适合想快速验证控制逻辑的创客。下面把硬件原理、引脚映射和实操代码一次讲透。1. 项目定位与整体设计思路GPIO 扩展板为什么还有存在价值1.1 裸 GPIO 的痛点与 Pi-Face 的答案树莓派的 40-Pin GPIO 排针本身就能直接输出高低电平、读取按键状态为什么还要专门买一块 Pi-Face这个问题我经常在交流会上被问到。答案是裸针能干活但干得不够体面。直接拿杜邦线接 LED限流电阻算不对就容易超电流接按键去抖和上拉要自己处理想读模拟量几乎没门因为树莓派的 GPIO 是纯数字接口没有内置 ADC。Pi-Face 把这些外围电路统一做在一块板子上输入侧加了缓冲器输出侧用了达林顿驱动管模拟侧直接焊了一颗 10 位 ADC用户层面看到的只有干净的接口和稳定的事件。这块板子出自大学实验室带着很明显的教学基因。它不是把引脚全部引出了事而是刻意把功能裁剪成“2 路数字输入、2 路数字输出、1 路模拟输入”的最小集合。这个裁剪很关键初学者面对 40 个引脚会懵面对“两个按钮、两个灯、一个旋钮”却很容易理解。你仔细观察会发现现实里要控制的对象绝大多数可以归约成这几个基本量开关量检测、开关量输出、连续量采集。把这三种量练熟再往上做传感器网络或者电机控制思路都是相通的。1.2 硬件架构拆解数字输入、数字输出、模拟输入三条链路Pi-Face 的硬件链路可以拆成三条独立通路来理解这也是它调试起来舒服的根本原因。数字输入链路由板载按钮和外部接线端子共用信号经过缓冲芯片整形后才进入树莓派 GPIO缓冲器一方面做电平整形让输入信号变得干净利落另一方面提供静电防护避免直插树莓派引脚时把 BCM 芯片打坏。数字输出链路则正好相反树莓派 GPIO 先给到达林顿驱动管的基极再由驱动管去点亮板载 LED 或驱动外部负载。用达林顿而不是直接用 GPIO 驱动是为了把电流负载从主芯片上剥离出去树莓派的 GPIO 灌拉电流能力有限直接驱动继电器或小电机很容易把引脚烧出暗病。模拟输入链路的关键是一颗 MCP3002这是 Microchip 的 10 位、双通道 ADC树莓派通过 SPI 总线向它发起转换请求并读取结果。三条链路互不干扰这是分区设计带来的好处。实际调试时我经常只接其中一条链路来定位问题比如把模拟输入短路到地如果读数能稳定回到接近 0说明 ADC 和 SPI 通信是健康的问题大概率在外围传感器上这种隔离排查法能省掉大量时间。1.3 为什么把 ADC 挂在 SPI 上既然只是读一颗 ADC为什么树莓派原生不提供模拟输入端口我一般用这个例子向新手解释芯片内部是数字世界外部才是模拟世界中间必须有 ADC 这层翻译官。Pi-Face 选择把 ADC 挂在 SPI 上是因为 SPI 是树莓派上速度最快、最稳定的同步串行接口之一。MCP3002 的典型转换速率在 1.8 Mbps 左右对于旋钮、温度、光照这些慢变信号绰绰有余。相比之下 I2C 虽然只需要两根线但协议开销更大设备地址冲突也更多UART 是异步通信还得额外约定波特率。SPI 的四根线SCLK、MOSI、MISO、CE在逻辑上更纯粹非常适合作教学示范也方便用示波器直接观察时序。提示MCP3002 虽然是双通道但 Pi-Face 通常只把其中一路引到端子上另一路留给板载校准或悬空。如果你做多路采集可以外接模拟开关或者直接换 MCP30088 通道版本引脚和 SPI 协议基本兼容代码只需要改命令字节的通道位。2. 引脚映射与 Compute Module 4 GPIO 对照2.1 标准 40-Pin GPIO 关键引脚速查Pi-Face 全部引脚都通过树莓派顶部的排针引出不额外占用 USB 或 CSI/DSI 接口这是它最大的优势之一。要理解它你必须先会看树莓派的 GPIO 编号体系。树莓派上有三套命名在打架物理引脚号、BCM 编号、wiringPi 编号现在基本淘汰。Pi-Face 文档里使用的是 BCM 编号这也是所有 Python 库默认的编号方式。我整理了一张 Pi-Face 最常涉及的引脚对照表建议收藏信号BCM GPIO40-Pin 物理引脚说明SPI0 SCLKGPIO1123SPI 时钟SPI0 MOSIGPIO1019主出从入写配置命令SPI0 MISOGPIO921主入从出读 ADC 结果SPI0 CE0GPIO824片选选通 MCP3002数字输入 1GPIO1711经缓冲器输入数字输入 2GPIO1812经缓冲器输入数字输出 1GPIO2215经驱动管输出数字输出 2GPIO2316经驱动管输出5V-2 或 4驱动管及外部负载供电3.3V-1 或 17缓冲器与 ADC 供电GND-6、9、14、20 等公共地不同版本的 Pi-Face 对输出引脚的 BCM 编号可能有差异具体以板子丝印为准。关键是记住SPI0 的四根线是固定的输入输出通道大多落在 GPIO17、GPIO18、GPIO22、GPIO23 这几个口上因为它们不参与任何外设复用是最安全的通用输入输出口。这也是为什么很多 GPIO 扩展板都默认用这四个口算是一个行业惯例。2.2 CM4 的 100-Pin 连接器与转接思路最近很多人开始用 Compute Module 4 做产品搜“raspberry pi compute module 4 gpio引脚图”的概率也高了很多。CM4 和普通树莓派最大的差异是它没有 40-Pin 排针所有 GPIO 都分散在两个 100-Pin 的高速板对板连接器J1、J2上。我第一次拿到 CM4 核心板时也愣了一下因为光靠肉眼根本分不清哪个脚是 GPIO17。但你要记住一个关键事实CM4 的 BCM 编号体系没有变。GPIO11 仍然是 SCLKGPIO9 仍然是 MISOGPIO17 仍然是那个可用的通用输入脚。变的只是物理位置。在官方 CM4 IO Board 上40-Pin 排针的物理位置和标准树莓派一致所以 Pi-Face 插上去照样能用。如果你用的是第三方载板就得回到 CM4 数据手册里的 J1/J2 引脚表按“信号名 - BCM 编号 - 连接器引脚号”三步去找不要凭记忆乱接线。这里分享一个我踩过坑后养成的习惯拿到任何一块 CM4 载板第一件事不是接外设而是用万用表蜂鸣档测一下 40-Pin 排针的 GND 和 3.3V 分布确认默认上电不会把电源和地引反。CM4 核心板的引脚间距只有 0.5mm比标准排针密得多一旦接反损坏的速度比普通树莓派快得多返修成本也很高。2.3 引脚冲突排查从原理到实践的注意事项Pi-Face 占用的 SPI0 与部分扩展板存在资源冲突这是我在实际项目中遇到最多的问题。比如某些 LCD 屏幕、RFID 读卡器也默认挂在 SPI0 上两者同时启用时设备树会报错或者出现其中一个设备时好时坏的现象。排查思路其实很简单先看设备树加载了哪些 overlay。执行dtoverlay -a可以列出所有可用 overlay执行dtoverlay -l看当前加载的列表。如果发现 SPI 屏占了 spi0-1cs而你又在跑 Pi-Face要么把 Pi-Face 的 ADC 片选改到 CE1GPIO7要么换一个用 I2C 接口的屏幕。我在项目中一般优先把显示类外设挪到 I2C把 SPI0 完整留给数据采集因为 SPI 在采集上的时序稳定性更好。另外要注意CM4 系列的默认固件可能不会自动启用 SPI。有些第三方载板即使引出了排针系统里也找不到/dev/spidev0.0这不是硬件坏了而是设备树里没有把 spi0 打开。这个问题在下一节实操里会详细讲。3. 实操全流程配置、接线、代码逐行过3.1 系统配置启用 SPI 与安装依赖树莓派系统默认不启用 SPI 硬件接口这是新手最容易卡住的地方。我建议直接用命令行操作比图形界面的 raspi-config 更可控。执行sudo raspi-config选择Interface Options - SPI - Enable然后重启。重启后检查设备节点是否生成ls -l /dev/spidev*正常情况下你会看到/dev/spidev0.0和/dev/spidev0.1两个节点分别对应 CE0 和 CE1。如果节点不存在先确认config.txt里有没有以下两行dtparamspion dtoverlayspi0-1cs注意第二行不是必须的spi0-1cs的作用是只启用 CE0 一路片选释放 GPIO7 给其他用途。如果 Pi-Face 用的是 CE0这个配置能帮你多留出一个引脚。接着安装 Python 依赖。传统做法是装python3-spidev和RPi.GPIO我现在的推荐是gpiozero加spidev的组合因为 gpiozero 对按钮、LED 这类基础外设封装得非常好代码量能少一半sudo apt update sudo apt install python3-spidev python3-gpiozero注意新版系统里 RPi.GPIO 在部分内核上会有兼容警告如果只是读写数字引脚gpiozero 底层会自己选择合适的驱动方式省去一堆麻烦。如果你的代码依赖 RPi.GPIO 的 PWM再单独安装它即可。3.2 接线步骤与负载能力边界接线是整个过程中最容易出问题的环节。我的操作顺序是先断电再接 Pi-Face最后上电检查。别嫌我啰嗦带电插拔 GPIO 扩展板是烧芯片的头号原因。Pi-Face 的接线分三类。第一类是板级连接直接把板子对齐排针插上去注意排针方向别错位一格错位通常会导致 5V 电源直接灌进某个 GPIO后果不用多说。第二类是数字输入把按钮或开关接到输入端子一端接信号另一端接 GNDPi-Face 内部已经做了上拉处理不需要额外接电阻。第三类是模拟输入把电位器中间抽头接到模拟输入端子另外两脚分别接 3.3V 和 GND这样你转动旋钮时ADC 读数就会在 0 到 1023 之间平滑变化。负载能力这个边界必须说清楚。Pi-Face 的输出级用的是达林顿驱动管它的电流能力比树莓派 GPIO 直接输出强不少但也不是无限大。驱动单个 LED 完全没问题驱动 5V 继电器线圈也勉强可以但建议在线圈两端并联一个续流二极管否则关断瞬间的反向电动势可能打坏驱动管。如果需要驱动电机或大功率负载正确做法是让 Pi-Face 只做逻辑控制后面再接继电器或 MOS 管驱动板千万不要试图让这个小板子扛大电流。3.3 Python 控制代码读按钮、控灯、取模拟量硬件接好之后上电开机写第一段测试代码。我习惯先读模拟量因为这是最容易做自检的通道把模拟输入悬空时读数不稳定是正常的接上电位器后读数应该随旋钮单调变化。下面这段代码实现了三个功能读两路按钮、控制两路输出、读取一路模拟电压import time import spidev from gpiozero import LED, Button spi spidev.SpiDev() spi.open(0, 0) # SPI0, CE0 spi.max_speed_hz 1000000 spi.mode 0b00 def read_adc(channel): # MCP3002 命令字节: 起始位 单端 通道选择 if channel 0: cmd 0b01100000 else: cmd 0b01110000 reply spi.xfer2([cmd, 0, 0]) value ((reply[1] 0x03) 8) | reply[2] return value btn1 Button(17, pull_upTrue) btn2 Button(18, pull_upTrue) led1 LED(22) led2 LED(23) try: while True: print(fADC0{read_adc(0):4d} ADC1{read_adc(1):4d} fB1{btn1.is_pressed} B2{btn2.is_pressed} fL1{led1.is_lit} L2{led2.is_lit}) # 按钮 1 按下时切换 LED1按钮 2 按下时切换 LED2 if btn1.is_pressed: led1.toggle() if btn2.is_pressed: led2.toggle() time.sleep(0.1) except KeyboardInterrupt: spi.close() print(\n退出)这段代码有几个设计细节值得讲。spi.max_speed_hz 1000000是我反复试验后觉得比较稳妥的值杜邦线长的时候 SPI 速率太高会导致 ADC 读数乱跳降到 1MHz 左右牺牲一点采样率换来的是稳定性如果你的线很短或者用的是面包板可以适当提高到 2MHz。spi.mode 0b00是 MCP3002 要求的 SPI 模式CPOL0、CPHA0这两个参数写错的话读出来的数据会整体错位表现为数值杂乱无章。按钮那两行用了pull_upTrue确保浮空时读到确定的高电平避免误触发。运行后如果一切正常你能看到串口不断刷新状态按下按钮时对应布尔值变化ADC 读数随电位器转动变化。这个“全状态回显”的写法是我做所有传感器调试前的习惯先把所有输入输出都打出来确认硬件通路没问题再往上叠加业务逻辑。3.4 扩展把 Pi-Face 接入自动化场景Pi-Face 这种结构化接口非常适合做无头模式下的自动化控制。我有一次用它做了一个办公室植物灌溉的原型土壤湿度传感器接在模拟输入上水泵继电器接在数字输出上当湿度低于阈值时自动启动水泵高于阈值就停止。整个代码在上一节的基础上只多了一个判断分支但价值立刻就不一样了。还有一次是拿它做门磁报警门磁开关接数字输入报警蜂鸣器接数字输出配上systemd服务开机自启放在角落里跑了一个多月除了偶尔 SD 卡掉线需要重启没有出过硬件问题。这种长时间运行的稳定性正是 Pi-Face 相比面包板飞线方案最大的优势没有松动的杜邦线没有悬空的引脚所有连接都被板子约束好了。4. 常见问题与排查技巧实录4.1 SPI 启用了但读不到数据现象是/dev/spidev0.0存在但 Python 里 open 时报FileNotFoundError或者 xfer2 返回的全是 0。第一种情况通常是用户权限问题试试让当前用户加入spi组sudo usermod -aG spi 你的用户名然后重新登录。第二种情况多半是接线问题重点检查 MISO 是否真的接到了 GPIO9。我遇到过最隐蔽的情况是有人把板子插反了一个引脚SPI 写命令正常但读数据永远不对因为 MISO 根本没有物理连通这种情况用万用表量一下排针对应关系立刻就能发现。4.2 数字输入被误触发按钮不按的时候偶尔会跳一下或者完全紊乱。先别怀疑 Pi-Face 坏了优先检查是不是按钮引脚浮空。虽然板载有上拉但如果外部按钮线特别长线缆本身就相当于一根天线工频干扰和电机启停产生的尖峰都会耦合进来。解决办法有三个在输入端并一个 0.1uF 电容做硬件滤波在代码里做 20ms 到 50ms 的去抖或者换用屏蔽线。我一般三重手段一起上实测下来能解决 99% 的误触发问题。4.3 模拟量读数跳变ADC 读数不稳定除了 SPI 速率过高以外最常见的原因是参考电压不稳。树莓派的 3.3V 是从板载稳压器出来的本身精度不错但如果同一时刻有大负载在数字输出端切换瞬间电流变化会引起电压波动传导到 ADC 参考引脚上读数就会跟着跳。我的建议是模拟传感器和数字负载供电分开模拟部分单独走板上的 3.3V 或外接一个低噪声 LDO数字负载走 5V。另外软件侧可以对连续采样做滑动平均取 5 到 10 次采样的均值呼吸灯一样平滑。4.4 CM4 载板上的设备树覆盖问题在 CM4 上跑 Pi-Face 遇到最多的是设备树问题。第三方载板的出厂固件往往只启用了和载板自身硬件相关的 overlaySPI 接口默认关闭。解决办法是在config.txt里手动追加[all] dtparamspion然后重启再检查/dev/spidev0.0。如果载板把 SPI0 的引脚复用成了其他功能比如 MIPI 摄像头或者 PCIe那 Pi-Face 就只能放弃 SPI0改用软件模拟 SPI或者把 ADC 换成 I2C 接口的型号。这里没有万能答案必须回到载板的原理图确认引脚最终接到了哪里这是 CM4 项目开发躲不掉的一步。经验小结凡是遇到“外设时好时坏”“读数偶尔全 0”“按键偶尔失灵”先按这个顺序排查——电源稳定性、地线完整性、SPI 速率、软件去抖。八成问题都在这几项里。在我实际用下来的感受里Pi-Face 最打动人的不是性能参数而是它把 GPIO 编程的门槛压到了一个“插上就能跑”的程度。对于新手它是理解数字输入输出和 ADC 采样最好的入门教具对于老手它又是快速搭控制原型的可靠底板。如果你手头正好有闲置的树莓派或 CM4 开发板不妨找一块 Pi-Face 接个电位器、两个按钮跑一遍上面的代码你会对 GPIO 的电气特性有非常直观的理解。最后再分享一个小技巧无论你用的是 Pi-Face 还是其他扩展板接线前打印一张当前型号的 GPIO 引脚图放在工作台旁边然后在代码里用 BCM 编号写死引脚所有硬件接线表单独用 Markdown 维护一份。磨刀不误砍柴工这套习惯能让你在项目切换时节省大量翻资料的时间。
返回列表