基于树莓派Pico的自定义USB键盘制作:从电路设计到CircuitPython编程
1. 项目概述与核心思路前阵子在网上冲浪看到一个挺有意思的梗图一个键盘上只有几个特定的字母刚好能拼出一句“国粹”。当时就觉得这玩意儿要是真能做出来不仅是个有趣的桌面摆件还能在特定场景下比如快速输入常用短语派上用场。于是一个基于Raspberry Pi Pico的自定义键盘项目就这么诞生了。这个项目的核心就是利用一块廉价的微控制器模拟成一个标准的USB人机接口设备HID也就是电脑能直接识别的键盘。它不依赖于复杂的键盘主控芯片而是通过编程让Pico的每一个GPIO引脚都对应一个独立的按键。当你按下连接在某个GPIO上的机械轴时Pico就会通过USB协议向电脑发送一个对应的键值码从而实现输入。这种方法的自由度极高你可以定义任意布局、任意功能的键盘从简单的数字小键盘到复杂的宏键盘甚至是这种“专精于某一句话”的趣味键盘。整个制作过程融合了硬件和软件硬件部分包括3D建模打印外壳、焊接轴体电路软件部分则集中在为Pico刷写固件并编写按键映射逻辑。我选择使用CircuitPython作为开发环境因为它对USB HID设备的支持非常友好库函数封装得很好几行代码就能实现键盘功能大大降低了嵌入式开发的门槛。无论你是想复刻这个“国粹键盘”还是想制作属于自己的个性化输入设备这篇教程都能给你提供一个清晰、可复现的路径。2. 核心硬件选型与物料清单解析制作一个可用的自定义键盘硬件是基石。选对部件不仅能保证功能正常还能提升最终成品的质感和使用体验。下面我结合自己的踩坑经验详细拆解每一个关键部件的选择逻辑和注意事项。2.1 主控核心为什么是Raspberry Pi Pico在众多微控制器中我选择了树莓派基金会出品的Raspberry Pi Pico。原因主要有三点性价比、生态和USB功能。首先Pico的价格极具竞争力通常只需二三十元。它搭载了RP2040双核ARM Cortex-M0处理器性能对于键盘扫描这种任务绰绰有余。最关键的是RP2040芯片原生支持USB 1.1全速12Mbps并且其硬件结构使得实现USB设备功能相对容易。相比之下一些更古老的AVR芯片虽然也能做USB键盘但往往需要额外的USB转串口芯片或更复杂的固件开发。其次Pico的生态非常繁荣。除了官方的MicroPython和C/C SDKCircuitPython对它的支持尤为完善。CircuitPython由Adafruit主导开发其设计哲学就是“极简”和“易用”特别适合快速原型开发。对于键盘项目Adafruit_HID库已经封装好了所有发送键盘按键、鼠标移动的底层协议我们只需要调用简单的函数比如keyboard.press(Keycode.A)就能实现按键发送完全不用去啃复杂的USB协议手册。最后Pico的引脚布局规整GPIO数量充足本项目用了10个GPIOPico有26个可用并且有专门的3.3V输出和接地引脚方便为按键矩阵供电。它的BOOTSEL按钮和可移动存储模式当插入USB时显示为一个U盘使得刷写固件像拷贝文件一样简单这对新手极其友好。注意市面上有一些Pico的兼容板价格可能更便宜。在选购时务必确认其使用的主控是RP2040并且USB接口和数据引脚是完好可用的。有些劣质兼容板的USB稳定性可能较差。2.2 输入灵魂机械轴与键帽的搭配学问键盘的手感很大程度上由机械轴决定。我选择了最经典的Cherry MX轴体并且是板载式版本。这里有两个关键点容易混淆轴体类型和安装方式。轴体类型Cherry MX轴主要有青轴Click、红轴Linear、茶轴Tactile等区别在于段落感和压力克数。对于这个趣味小键盘手感选择全凭个人喜好。我用了红轴因为直上直下比较安静。安装方式这是新手最容易踩坑的地方。机械轴分为PCB安装式和钢板安装式。PCB安装式轴体底部除了两个金属引脚还有两个额外的塑料定位柱。这三个“脚”需要插入PCB板上对应的三个孔中固定。钢板安装式轴体底部只有两个金属引脚。它需要依靠一块金属或塑料定位板来固定轴体是卡在定位板上的孔里的。本项目必须使用钢板安装式轴体因为我们的“电路板”实际上是用飞线直接连接Pico的GPIO并没有一块真正的PCB来提供那三个固定孔。如果你错买了PCB安装式轴体那两个多余的塑料柱会无法安装要么剪掉破坏轴体要么就无法牢固固定。键帽的“高度”与“一致性”键帽不是随便买一套就能用的。大多数键帽是“阶梯高度”即不同行的键帽高度和倾斜角度不同以符合人体工学。例如数字键“F5”那一行的键帽和字母键“T”那一行的形状就不同。对于我们的自定义键盘按键位置完全打乱了原有的行序。如果你使用阶梯高度的键帽装上去后会高低错落非常别扭且难按。因此必须选择统一高度的键帽。目前主流的统一高度键帽有两种XDA高度球帽造型所有键帽高度一致顶部是平的或微球面。DSA高度比XDA稍矮也是球帽所有键帽高度和造型完全一致。我选择了一套XDA高度的键帽视觉上整齐划一手感也不错。另外由于这个键盘需要两个“U”键而标准键帽套装通常每个字母只有一个我特意选了一套附赠数字小键盘键帽的套装用里面的“*”号键来代替第二个“U”因为它的颜色和主键区一致。卫星轴对于长度超过1个标准键位1u的按键比如空格键和回车键为了防止按压时跷跷板需要安装卫星轴来平衡。我选用的是适合钢板安装的卫星轴。安装时要注意润滑否则可能会有杂音。卫星轴的组装稍复杂通常包含一根金属钢丝、两个塑料底座和两个滑动假轴。建议先在地面上组装好钢丝卡入底座和假轴再整体卡入定位板上为它预留的长条形孔位中。2.3 结构基础外壳设计与3D打印实践外壳承担着固定所有元件的重任。我使用Autodesk Fusion 360进行设计将上盖定位板和下盖设计为一体式。设计核心是上盖的开口。开口尺寸的精确计算每个Cherry MX轴体需要穿过一个方孔。这个方孔的标准尺寸是14mm x 14mm。轴体之间的中心距标准是19.05mm即0.75英寸。这两个尺寸必须精确否则轴体要么塞不进去要么装上去歪歪扭扭。在Fusion 360中我使用矩形草图工具配合尺寸约束和矩形阵列快速且准确地绘制出了所有轴孔。卫星轴开口对于空格键本例中我们用的是2u长度的键位即两个标准键宽需要在轴体方孔的两侧再开两个小方孔来固定卫星轴的底座。这个尺寸需要根据你购买的卫星轴型号来确定通常需要查阅卫星轴的产品说明书或社区维基。打印工艺选择为了获得光滑、无层纹的表面质感我使用光固化树脂3D打印机来打印上盖。树脂打印的精度极高能完美呈现14mm的方孔并且表面如玻璃般平滑无需后期打磨。下盖对表面要求不高为了节省成本我使用了普通的FDM熔融沉积打印机即常见的挤塑料丝的打印机来打印。当然上下盖全部用同一种工艺打印也完全没问题。材料建议对于FDM打印推荐使用PETG或ABS材料它们比PLA强度更高更耐温不易因长时间使用或环境温度变化而变形。对于树脂打印选择标准的刚性树脂即可。3. 电路设计与焊接实操详解硬件准备就绪后下一步就是让电路“活”起来。自定义键盘的电路原理其实非常简单就是一个“一对多”的并联扫描电路但焊接和走线的细节决定了成品的可靠性与美观度。3.1 电路原理共地扫描与GPIO检测我们采用的不是复杂的矩阵扫描常用于全尺寸键盘以节省GPIO而是更直接的“一轴一线”连接方式。每个按键开关都独立连接到一个GPIO引脚上。其工作原理如下共接高电平每个Cherry MX轴体有两个金属引脚引脚A和引脚B。我们将所有轴体的引脚A通常标记为“C”或公共端用一根导线并联起来然后统一连接到Pico的3.3V输出引脚上。这意味着在未按下时引脚A始终处于3.3V高电平。独立检测每个轴体的引脚B分别用一根独立的导线连接到Pico的一个GPIO引脚上例如GP2, GP3, GP4...。在程序中我们将这些GPIO配置为输入模式并启用内部下拉电阻。按键检测当按键未被按下时轴体内部断开GPIO引脚通过内部下拉电阻被拉到低电平0V程序读到的值是False或0。当按键被按下时轴体内部导通3.3V的高电平从引脚A直接传到引脚BGPIO引脚读到高电平3.3V程序读到的值是True或1。程序通过持续扫描这些GPIO的状态变化就能判断哪个键被按下了。这种方式的优点是电路直观编程简单几乎没有按键冲突鬼键问题。缺点是每个按键占用一个GPIO不适合键位很多的情况。但对于我们这个10键键盘Pico的GPIO完全够用。3.2 焊接步骤与工艺要点焊接是连接硬件灵魂的步骤好的焊点不仅牢固也更安全。工具准备你需要一把可调温电烙铁建议温度设置在320°C-350°C、焊锡丝建议含松香芯的中细规格、助焊剂、吸锡器或吸锡线、镊子以及耐热胶带或热缩管。步骤一处理轴体引脚将Cherry MX轴体插入3D打印好的上盖定位板中确保卡紧。观察轴体底部的两个金属引脚。用钳子或指甲将每个引脚轻轻向外弯折约45度使其变成“L”形。这样做的目的是为了在后续焊接时导线能更容易地搭在引脚上并固定住。关键取一段导线建议使用AWG 22-24的硅胶线柔软耐折剥开约2-3mm的线头预先上好锡即用烙铁融化一点焊锡包裹住裸露的铜丝。步骤二焊接“共地线”剪取一段足够长的导线作为“共地线”即连接所有轴体引脚A的线。将这根线的一端焊接在Pico的3V3(OUT)引脚上。将这根线依次穿过每个轴体弯曲的引脚A下方用烙铁快速点焊使导线与每个引脚A都牢固连接。操作时先将上好锡的线头搭在弯折的引脚上然后用烙铁头同时接触线和引脚送入焊锡丝焊锡熔化流动包裹住连接点后迅速移开烙铁。确保每个焊点都饱满、光滑呈圆锥形没有虚焊焊锡只堆在表面未与引脚融合或冷焊焊点粗糙无光泽。步骤三焊接独立的GPIO线为每个轴体的引脚B准备一根独立导线建议用不同颜色区分方便后续排查。参考之前的引脚映射表将每根导线的一端焊接到对应的轴体引脚B上。将每根导线的另一端焊接到Pico对应的GPIO引脚上。例如连接“K”键的导线另一端焊接到GP3。焊接Pico引脚时要格外小心。Pico的焊盘较小烙铁温度不宜过高停留时间要短1-2秒避免过热损坏芯片或导致焊盘脱落。可以使用镊子固定导线。步骤四绝缘与整理所有焊接完成后必须检查是否有焊锡搭桥两个不该连接的焊点被焊锡连在了一起。用放大镜仔细查看如有搭桥用吸锡线清理。使用电气绝缘胶带如聚酰亚胺胶带俗称金手指胶带或热缩管将所有暴露的焊点、Pico的金属引脚排针仔细包裹起来防止在安装时因金属接触导致短路。用扎带或线缆固定座将壳内杂乱的导线梳理整齐这不仅美观也能避免线材被挤压脱落。实操心得焊接时在焊点上使用少量助焊剂能让焊锡流动更顺畅焊点更光亮牢固。焊接Pico这类精密器件时一个第三只手持工具或“焊锡助手”能帮你稳稳地固定导线和板子解放双手。4. 固件编程与功能实现全流程硬件电路搭建完毕接下来就是注入“灵魂”——编程。我们将使用CircuitPython让Pico变身成为一个即插即用的USB键盘。4.1 搭建CircuitPython开发环境CircuitPython的开发流程极其简单本质上就是向一个U盘里拷贝文件。获取固件访问CircuitPython官网找到Raspberry Pi Pico的页面下载最新的.uf2格式固件文件。进入BOOTSEL模式断开Pico的USB连接。按住Pico板上的白色BOOTSEL按钮不放同时将Pico通过Micro USB线连接到电脑。此时电脑会识别到一个名为RPI-RP2的可移动磁盘。刷写固件将下载好的.uf2文件例如adafruit-circuitpython-raspberry_pi_pico-xx.x.x.uf2直接拖拽或复制到RPI-RP2磁盘中。复制完成后Pico会自动重启。验证安装重启后电脑会识别到一个新的可移动磁盘名字通常变为CIRCUITPY。这说明CircuitPython固件已经刷写成功。打开这个磁盘你会看到一些默认的文件如boot_out.txt。4.2 安装必要的库文件CircuitPython通过库文件来扩展功能。我们需要Adafruit_HID库来实现键盘模拟。访问Adafruit的CircuitPython库包页面下载最新的库包通常是一个.zip文件。解压这个库包在里面找到adafruit_hid这个文件夹。打开CIRCUITPY磁盘如果里面没有lib文件夹就新建一个。将adafruit_hid整个文件夹复制到CIRCUITPY磁盘的lib文件夹内。4.3 编写键盘逻辑代码现在在CIRCUITPY磁盘的根目录下创建一个名为code.py的文件。CircuitPython会在每次启动时自动运行这个文件。将以下代码写入code.pyimport time import board import digitalio import usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode # 初始化USB键盘设备 keyboard Keyboard(usb_hid.devices) # 定义按键引脚映射 # 格式 (GPIO引脚对象, 对应的键盘键值) keymap [ (board.GP2, Keycode.BACKSPACE), (board.GP3, Keycode.K), (board.GP4, Keycode.C), (board.GP6, Keycode.U), (board.GP7, Keycode.F), (board.GP8, Keycode.Y), (board.GP10, Keycode.O), (board.GP11, Keycode.U), # 第二个U键 (board.GP12, Keycode.KEYPAD_PLUS), # 用数字小键盘的号键代替回车 (board.GP13, Keycode.SPACEBAR), ] # 初始化所有按键引脚为输入模式并启用内部下拉电阻 keys [] for pin, keycode in keymap: key_pin digitalio.DigitalInOut(pin) key_pin.direction digitalio.Direction.INPUT key_pin.pull digitalio.Pull.DOWN # 启用内部下拉电阻默认读到低电平 keys.append((key_pin, keycode)) # 记录按键之前的状态用于检测按下和释放事件 prev_states [False] * len(keys) print(自定义键盘已启动) # 主循环持续扫描按键状态 while True: for i, (key_pin, keycode) in enumerate(keys): current_state key_pin.value # 读取当前引脚电平True为高电平按下 # 检测按键按下事件从低电平变为高电平 if current_state and not prev_states[i]: print(f按键按下: {keycode}) keyboard.press(keycode) # 检测按键释放事件从高电平变为低电平 elif not current_state and prev_states[i]: print(f按键释放: {keycode}) keyboard.release(keycode) # 更新前一个状态 prev_states[i] current_state # 加入一个短暂的延迟防止扫描过于频繁消耗CPU time.sleep(0.01)代码逻辑深度解析导入库board库用于访问Pico的特定GPIOdigitalio用于控制数字输入输出usb_hid和adafruit_hid是核心提供了模拟USB HID设备的能力。初始化键盘对象Keyboard(usb_hid.devices)这行代码创建了一个键盘对象它通过USB与电脑通信。建立键位映射表keymap列表是核心配置。每个元素是一个元组第一个是GPIO引脚如board.GP2第二个是对应的Keycode。Keycode包含了所有标准键盘键值比如Keycode.A,Keycode.ENTER等。这里我将GP12映射为KEYPAD_PLUS是因为我外壳的回车键位是2u而标准回车键是2.25u我用了一个2u的“”键帽来代替。引脚初始化遍历keymap为每个GPIO引脚创建一个DigitalInOut对象。设置方向为输入(INPUT)并启用内部下拉电阻(Pull.DOWN)。这意味着当按键未按下电路断开时引脚被电阻拉至低电平0按下时3.3V高电平输入引脚变为高电平1。状态扫描与事件检测主循环不断读取每个引脚的状态(key_pin.value)。我们通过对比当前状态和上一次循环的状态(prev_states)来精确判断是“按下”事件从0变1还是“释放”事件从1变0。只有在检测到事件时才调用keyboard.press()或keyboard.release()函数这符合标准键盘的行为也避免了长按重复触发的问题。防抖与延迟机械开关在闭合瞬间会产生物理抖动可能导致微控制器误判为多次按下。代码中通过time.sleep(0.01)10毫秒的延迟以及“检测状态变化”而非“检测当前状态”的逻辑在一定程度上实现了软件防抖。对于要求更高的场景可以增加更复杂的防抖算法。保存code.py文件后CircuitPython会自动重新加载并运行新代码。此时将键盘插入电脑USB口电脑应该会识别出一个新的键盘设备。打开一个文本编辑器按下你焊接的按键对应的字母就应该出现了。5. 组装、测试与问题排查实录当所有部件都准备妥当代码也运行无误后最后的组装阶段就是将散件变成一件完整作品的过程。这个阶段需要耐心和细心同时这也是问题最容易暴露的时候。5.1 系统化组装步骤功能预测试在完全封闭外壳前务必进行最后一次裸板测试。将焊接好所有线路的Pico和轴板通过USB连接电脑打开一个记事本用镊子或导线依次短接每个轴体的两个引脚模拟按键检查屏幕上输入是否正确。这一步能排除组装后因内部挤压导致短路或断路的问题。安装键帽确认所有按键功能正常后将键帽对准轴体的十字柱垂直用力按下直到听到“咔哒”一声表示键帽已卡紧。对于空格等大键需要先将卫星轴的假轴部分卡入键帽背面的卡扣然后再整体按下。内部绝缘与固定这是保证长期使用稳定性的关键。用电气绝缘胶带如聚酰亚胺胶带将Pico上所有裸露的焊点和金属排针仔细包裹起来特别是USB口附近的5V和GND引脚。由于我没有为Pico设计专门的固定柱我用一小块双面泡沫胶将它粘在了底壳内部一个平整的位置防止其晃动导致焊点脱落或短路。理线与收尾使用尼龙扎带或线卡将壳内杂乱的导线捆扎整齐固定在壳体内侧避免其干扰底部盖板的安装或接触到Pico的引脚。合盖与出线将上盖已安装轴体和键帽与下盖对齐。特别注意要将Pico的USB线从底壳预留的线槽中穿出。然后使用4颗M3x8mm的自攻螺丝或机械螺丝从底壳四角的支柱孔位拧入上盖将上下壳紧固。拧螺丝时应对角线逐步拧紧避免单边受力导致外壳变形或产生缝隙。最终外观处理我用丙烯颜料填充了3D打印外壳上的Logo凹槽待干透后一件个性化的桌面玩具就诞生了。5.2 常见问题与故障排查指南即使按照教程操作你也可能会遇到一些问题。下面是我在制作和调试过程中遇到的一些典型情况及其解决方法。问题现象可能原因排查与解决方法电脑完全无法识别设备1. USB线仅能充电无数据传输功能。2. Pico未正确进入CircuitPython模式。3.code.py语法错误导致启动失败。1.换一根已知良好的数据线测试。2. 重新进入BOOTSEL模式按住BOOTSEL上电检查CIRCUITPY磁盘是否存在。若不存在重新刷写UF2固件。3. 连接串口监视器如Mu编辑器、Thonny查看启动错误信息修正code.py代码。电脑识别为“未知设备”或“CIRCUITPY”磁盘但按键无反应1.adafruit_hid库未正确安装。2. 代码中键盘初始化失败。3. 按键引脚接线错误或虚焊。1. 检查CIRCUITPY/lib/目录下是否有adafruit_hid文件夹及其内部文件。2. 在代码开头添加print(“Start”)并打开串口监视器看是否有输出确认代码在运行。3. 用万用表通断档测量按键按下时轴体两个引脚是否导通测量Pico的GPIO引脚到轴体引脚的导线是否连通。检查共地线3.3V是否连接到所有轴体。某个或某几个按键失灵1. 对应GPIO引脚接线断路或虚焊。2. 代码中引脚定义错误。3. 该轴体本身损坏。1.重点检查失灵按键的独立连接线从轴体引脚到Pico GPIO用万用表逐段测量。2. 核对code.py中keymap列表确保失灵按键的GPIO编号与实际焊接一致。3. 将失灵键的轴体与正常键的轴体互换判断是轴体问题还是电路问题。按键按下后字符连续输入连击1. 软件防抖不足机械抖动被识别为多次按下。2. 按键引脚内部上拉/下拉配置不稳定。1. 增加防抖延时。在主循环的time.sleep中增加时间例如从0.01改为0.02。或者实现更稳定的防抖逻辑记录按键稳定处于新状态超过一定时间如20ms后才判定为事件。2. 确保代码中设置了pull digitalio.Pull.DOWN。如果电路设计是共接GND引脚接上拉电阻则需改为Pull.UP同时逻辑取反。所有按键同时触发共地线3.3V或公共端接线与某个GPIO引脚短路。立即断电检查用万用表检查3.3V线路是否与任何GPIO引脚直接短路。重点查看Pico引脚排针处是否有焊锡搭桥或壳内导线绝缘皮破损导致相互接触。输入字符错乱keymap映射表中的Keycode与预期不符。仔细检查code.py中每个GPIO对应的Keycode常量是否正确。例如确认空格键是Keycode.SPACEBAR回车键是Keycode.ENTER或Keycode.KEYPAD_PLUS。一个高级调试技巧在代码中添加详细的打印信息。例如在检测按键事件的if语句里不仅打印按下的键值也打印对应的GPIO编号。这样当按键失灵时你可以通过观察串口输出快速判断是程序没检测到电平变化硬件或焊接问题还是键值映射错了软件问题。组装完成后如果发现某个键手感涩滞或回弹不畅可能是键帽安装不正或卫星轴没有润滑到位。可以拔下键帽检查卫星轴钢丝是否完全卡入卡扣必要时可以涂抹少量特氟龙或硅基润滑脂。整个制作过程从构思到成品最大的成就感不仅在于它能够工作更在于你完全掌控了从物理结构到逻辑功能的每一个细节。这种将想法通过代码和焊枪变为实物的过程正是创客精神的精髓所在。