
1. 项目概述与核心价值如果你对摩斯码感兴趣或者身边有朋友因为行动不便使用传统触摸屏键盘输入文字非常困难那么这个项目可能会给你带来一些全新的思路。我们这次要做的不是一个复杂的、需要焊接和精密加工的电子项目而是一个利用手边常见开发板和简单材料就能快速搭建起来的Android手机摩斯码输入“外设”。它的核心原理并不复杂用一块Circuit Playground Express开发板编写一小段CircuitPython代码让它模拟成一个USB键盘即HID设备。然后通过USB OTG线把它连接到Android手机上。当你按下开发板上的不同按钮代表“点”和“划”时开发板就会向手机发送对应的键盘信号句点“.”和减号“-”。此时如果你在手机上安装了谷歌的GBoard输入法并启用了其中的摩斯码键盘它就能识别这一连串的“.”和“-”并将其转换为对应的字母、数字或标点最终实现用摩斯码输入文字。这个项目的魅力在于它的灵活性和可访问性。你既可以用板载的按钮或电容触摸点来操作也可以用鳄鱼夹连接两个大大的街机按钮让按压变得更轻松、更有确认感。整个制作过程无需动用电烙铁一个下午就能从零到一地完成。对于辅助技术应用而言它提供了一种低成本、高定制化的输入解决方案对于创客和教育者来说它是一个绝佳的、融合了硬件、软件和实际应用场景的入门项目。2. 核心组件与工具选型解析在动手之前我们先来盘点和理解一下需要用到的核心“食材”。选择这些组件并非偶然背后都有其针对这个项目的特定考量。2.1 核心控制器Circuit Playground Express为什么是它市面上微控制器那么多从Arduino Uno到ESP32选择Circuit Playground Express主要基于以下几点高度集成开箱即用CPX板载了10个可编程NeoPixel RGB LED、运动传感器、温度传感器、光线传感器、声音传感器、一个迷你扬声器以及两个按钮和多个电容触摸焊盘。对于本项目我们主要利用其按钮、电容触摸、扬声器用于音频反馈和USB HID功能。这种集成度意味着我们不需要为了基础功能而连接任何外部模块极大降低了入门门槛和出错概率。CircuitPython原生支持CPX是Adafruit力推的CircuitPython开发板之一。CircuitPython是MicroPython的一个分支针对教育和小型嵌入式项目做了大量优化。其最大的特点是无需编译代码以.py文件形式直接存放在板载的存储盘符中修改后保存即可自动运行。这对于快速迭代和调试尤其是对于Python初学者来说体验非常友好。完善的HID库支持Adafruit为CircuitPython提供了成熟稳定的adafruit_hid库可以轻松模拟键盘、鼠标等设备。库的API设计简洁发送一个按键只需要一行代码如kbd.send(Keycode.PERIOD)学习成本极低。坚固的物理设计板子周围有一圈坚固的孔洞方便固定也适合用鳄鱼夹进行临时连接这正是我们“免焊接”方案的基础。实操心得如果你手头没有CPX理论上任何支持CircuitPython和USB HID的开发板如Adafruit ItsyBitsy nRF52840、Feather RP2040等都可以替代。但CPX的集成传感器和即用性能让这个项目的原型阶段和功能演示更加直观和有趣。2.2 输入方式的选择与演进项目提供了三种输入方式的代码范例这体现了从简到繁、从验证到实用的设计思路板载按钮验证阶段使用板子自带的A、B按钮。这是最快速验证逻辑的方式。代码只需检测按钮状态并控制板载蜂鸣器发出不同时长的“嘀”声。此时项目还只是一个独立的摩斯码练习器尚未与手机连接。电容触摸便捷交互利用板子边缘的电容触摸焊盘如A3 A4。只需用手指轻触无需物理按压体验更流畅。代码上只需将检测cpx.button_a改为检测cpx.touch_A4。这种方式适合制作一个轻便的、桌面上的输入板。外部街机按钮辅助技术核心这是项目的终极形态。通过鳄鱼夹将两个大型街机按钮连接到CPX的A3和A4引脚以及GND地线。大按钮提供了明确的物理反馈和更大的按压面积对于手指灵活性受限的用户来说操作起来远比触摸小焊盘或屏幕虚拟键盘要可靠和舒适得多。为什么选择街机按钮和鳄鱼夹街机按钮通常具有较长的键程和清晰的“咔哒”声提供良好的触觉和听觉反馈。使用鳄鱼夹连接意味着完全避免了焊接。你可以随时调整、更换按钮甚至用其他形式的开关如脚踏开关来替代赋予了项目极高的可扩展性和容错性。这种“低技术”连接方式让不具备电子焊接技能的人也能轻松完成制作。2.3 连接桥梁USB OTG线缆这是连接手机与开发板的关键。大多数Android手机的充电口是Micro-B或Type-C而CPX也是Micro-B接口。因此你需要一根Micro-B公头 对 Micro-B公头的USB OTG线。请注意普通的Micro-B数据线一端是USB-A一端是Micro-B是无法直接连接手机和开发板的。关键细节OTG是“On-The-Go”的缩写它允许手机等设备扮演“主机”角色为其他USB设备供电并与之通信。购买时务必确认线缆支持OTG功能。如果找不到这种双Micro-B公头的线另一种方案是使用一个Micro-B OTG转接头搭配一根普通的Micro-B数据线USB-A to Micro-B将转接头插在手机上数据线的USB-A端插入转接头Micro-B端连接开发板。原理是一样的让手机识别开发板为一个外接USB键盘。2.4 结构材料纸板与Makedo工具包项目建议用瓦楞纸板制作一个容纳所有元件的小盒子并使用Makedo塑料螺丝Scrus进行组装。这是一个非常巧妙的“快速原型”思路。成本与环保纸板几乎零成本且易于裁剪和修改。安全性纸板是绝缘材料为内部的电子元件提供了一个安全的非导电外壳。Makedo系统的优势传统的胶水或胶带固定不牢固且难以拆卸。Makedo的塑料螺丝和打孔器专为纸板结构设计连接牢固又可无损拆卸方便后期调试和维修。这比单纯用热熔胶要优雅和实用得多。注意事项在设计纸盒尺寸时一定要为USB连接头留出足够的空间并考虑按钮按下时所需的内部行程高度。可以在CPX底部垫一小块泡沫胶或另一层纸板将其垫高为下方的鳄鱼夹和电线留出空间避免短路或挤压。3. 软件环境搭建与核心代码逐行解析硬件准备就绪后我们来搞定软件部分。整个过程可以分为手机端配置和开发板编程两部分。3.1 手机端GBoard输入法与摩斯键盘配置安装GBoard在Google Play商店搜索“GBoard”并安装。确保是Google LLC发布的官方版本。启用并设为默认安装后打开GBoard按照引导将其启用并设为默认输入法。这通常在系统设置的“语言与输入法”中完成。添加摩斯码键盘这是关键一步。打开任意一个可以输入文本的应用如备忘录。唤出GBoard键盘长按键盘上的“地球仪”图标用于切换语言。在弹出的语言列表中选择“添加键盘”然后找到“摩斯码Morse code”并添加。之后你就可以通过短按“地球仪”图标在常规键盘和摩斯码键盘间切换了。测试切换到摩斯码键盘它的界面会变得非常简单通常只显示一个大的输入区域并等待接收“.”点和“-”划的信号。注意不同手机品牌和Android版本设置路径可能略有差异。如果找不到摩斯码选项请确保你的GBoard已更新到最新版本并在其设置中仔细查找“语言”或“键盘布局”相关选项。3.2 开发板端CircuitPython固件与代码库刷入CircuitPython固件如果你的CPX还是出厂状态它可能运行着MakeCode或Arduino程序。我们需要先将其“变身”为CircuitPython设备。访问CircuitPython官网找到Circuit Playground Express的页面下载最新的.uf2固件文件。用USB数据线将CPX连接到电脑。快速双击板子上的“RESET”按钮此时板子上的所有LED会变成红色电脑上会出现一个名为CPLAYBOOT的U盘。将下载好的.uf2文件拖入这个U盘。U盘会自动弹出板子重启后电脑上会出现一个新的名为CIRCUITPY的U盘。这表明CircuitPython固件刷写成功。安装必要的库文件CircuitPython系统自带很多核心库但adafruit_hid库有时可能需要单独安装。访问Adafruit的CircuitPython库包发布页面下载最新的“Adafruit CircuitPython Library Bundle”。解压下载的压缩包找到lib文件夹下的adafruit_hid文件夹。将其复制到CPX的CIRCUITPY盘符下的lib文件夹中如果lib文件夹不存在就新建一个。3.3 核心代码逻辑深度剖析我们将以最终的“通用版”代码为蓝本拆解其每一部分的设计意图和实现细节。这个版本的代码通过注释开关兼容了所有输入输出模式结构清晰是学习嵌入式程序模块化设计的好例子。# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries # SPDX-License-Identifier: MIT Circuit Playground Express GBoard: universal/customizable version # pylint: disableunused-import import time from adafruit_circuitplayground.express import cpx # ------- 配置区通过取消注释来选择功能 ------- # 如果想使用外部按钮取消下面两行注释 # from digitalio import DigitalInOut, Direction, Pull # import board # 如果想使用HID键盘输出连接手机取消下面三行注释 # from adafruit_hid.keyboard import Keyboard # from adafruit_hid.keycode import Keycode # import usb_hid DOT_DURATION 0.20 # “点”的音频持续时间秒 DASH_DURATION 0.5 # “划”的音频持续时间秒 # 如果想使用电容触摸取消下面一行注释以调整灵敏度 # cpx.adjust_touch_threshold(100) # 如果想使用外部按钮取消下面六行注释以配置A3、A4引脚 # button_a DigitalInOut(board.A4) # button_a.direction Direction.INPUT # button_a.pull Pull.UP # button_b DigitalInOut(board.A3) # button_b.direction Direction.INPUT # button_b.pull Pull.UP # 如果想使用HID输出取消下面一行注释以初始化键盘对象 # kbd Keyboard(usb_hid.devices) # ------- 输入函数定义 ------- def touch_a(): # 根据你的硬件选择只取消注释其中一行 # return cpx.button_a # 使用板载A按钮 # return cpx.touch_A4 # 使用A4电容触摸 # return not button_a.value # 使用外部按钮连接A4 return False # 安全返回值防止Python报错 def touch_b(): # 根据你的硬件选择只取消注释其中一行 # return cpx.button_b # 使用板载B按钮 # return cpx.touch_A3 # 使用A3电容触摸 # return not button_b.value # 使用外部按钮连接A3 return False # 安全返回值 # ------- 输出函数定义 ------- def dot(): # 根据你的需求可以取消注释音频或HID输出 # cpx.play_tone(4000, DOT_DURATION) # 播放4000Hz的“点”音 # time.sleep(0.1) # 短暂静音区分声音 # kbd.send(Keycode.PERIOD) # 发送句点“.”键 pass # 占位符 def dash(): # 根据你的需求可以取消注释音频或HID输出 # cpx.play_tone(4000, DASH_DURATION) # 播放4000Hz的“划”音 # time.sleep(0.1) # kbd.send(Keycode.MINUS) # 发送减号“-”键 pass # 占位符 # ------- 主循环 ------- while True: if touch_a(): # 检测“点”输入 dot() # 执行“点”输出 while touch_a(): # 等待输入释放防抖 pass elif touch_b(): # 检测“划”输入 dash() # 执行“划”输出 while touch_b(): # 等待输入释放 pass代码逻辑精讲模块化与配置化代码将可能变化的硬件接口输入和功能输出抽象成了函数touch_a(),dot()等。主循环while True只关心“如果A被触发就执行点如果B被触发就执行划”完全不知道底层是按钮、触摸还是键盘发送。这种设计使得代码核心逻辑极其稳定更换硬件只需修改配置区的几行注释和对应的函数返回值而无需触动主循环。这是嵌入式开发中应对需求变化的优秀实践。输入防抖Debouncing主循环中在执行完dot()或dash()后都有一个while touch_a(): pass的循环。这个循环的目的是等待按键释放。如果没有这个等待在按住按钮的几十毫秒内主循环会飞速运行成百上千次导致发送出无数个点或划信号。这个简单的循环实现了“松手检测”是机械按钮防抖最基础且有效的方法之一。上拉电阻与电平逻辑当使用外部按钮时我们配置引脚为Pull.UP上拉。这意味着在引脚内部连接了一个电阻到高电平3.3V。当按钮未按下时引脚通过上拉电阻保持在高电平value为True或1。按钮的另一端连接的是GND地0V。当按钮按下时引脚直接与GND连通电平被拉低value为False或0。因此在touch_a()函数中我们使用return not button_a.value。当按钮按下value为False时not False就是True表示“触发”。这种“按下为低松开为高”的连接方式是最常见的因为大多数MCU的内部上拉电阻比下拉电阻更可靠。电容触摸灵敏度cpx.adjust_touch_threshold(100)用于调整电容触摸的触发阈值。数值越小越敏感但也更容易误触发比如因为靠近其他物体。你可以根据实际使用环境如干燥/潮湿气候是否戴手套调整这个值。调试时可以先注释掉这行使用默认值如果发现不灵敏或太灵敏再调整。4. 硬件组装与物理构建全流程有了代码我们就可以把想法变成实物了。这个过程更像是一个有趣的动手工作坊。4.1 电路连接详解我们以使用外部街机按钮为例讲解连接细节。你需要两个30mm街机按钮、三根带鳄鱼夹的导线。理解按钮结构典型的街机按钮有四个引脚分为两组。通常同一侧的两个引脚在内部是连通的。我们只需要使用其中一组两个引脚即可。你可以用万用表的通断档测量一下按下按钮时连通的两个引脚就是我们要用的。连接GND地线取一根导线一端夹在CPX板子上任何一个标有“GND”的焊盘上板子边缘有很多个任选一个。这根导线的另一端需要同时连接到两个按钮的其中一个引脚上。你可以用“Y型分线”的方式或者先将两个按钮的这个引脚用短线连接再统一接到GND线上。这构成了电路的公共地端。连接信号线取第二根导线一端夹在CPX的“A4”焊盘上另一端夹在**“点”按钮**剩下的那个独立引脚上。取第三根导线一端夹在CPX的“A3”焊盘上另一端夹在**“划”按钮**剩下的那个独立引脚上。检查连接完成后确保没有裸露的金属部分相互接触造成短路。可以轻轻拉扯导线确认鳄鱼夹夹持牢固。为什么这样连接这形成了一个简单的回路。当按钮未按下时A4/A3引脚通过内部上拉电阻连接到3.3V我们读到高电平。当按钮按下时按钮将A4/A3引脚与GND直接接通引脚被拉低到0V我们读到低电平。代码中的not button_a.value就是将这个低电平False转换为表示“按下”的True。4.2 纸盒设计与制作要点按照项目指南一个6cm x 9cm x 4cm的盒子是合适的。但我不建议你一开始就严格按这个尺寸切割。更好的方法是实物摆放定位将CPX、两个街机按钮、以及连接好的鳄鱼夹线松散地放在一张大纸板上。手动排列它们找到最紧凑、最合理的布局。确保按钮之间有足够间距便于操作CPX的USB口位置要预留开口。标记与测量用笔在纸板上描出每个元件的外轮廓和固定孔位。然后测量这个“包围圈”的长、宽、高。这个尺寸就是你盒子的内部最小尺寸再额外加上纸板厚度约3-5mm作为外部尺寸。绘制展开图在纸板上画出盒子的展开图。一个经典的长方体纸盒展开图像一个“十字”。记得在顶部为两个按钮开30mm的圆孔在侧面为USB线开一个方形或半圆缺口。使用美工刀和钢尺进行切割折痕处可以用刀背轻轻划一下不要切断这样更容易折叠整齐。使用Makedo组装在需要连接的纸板边缘用Makedo的打孔器打出小孔然后用塑料“Scru”螺丝和卡扣进行固定。先从底部和侧面开始组装最后安装顶盖。这种连接方式牢固且可逆方便你随时打开盒子检查或修改内部连接。实操心得在放入CPX前可以在其底部粘贴几层双面泡沫胶然后粘在盒内底板上。这不仅能固定CPX还能起到缓冲和绝缘的作用。确保所有电线在盒内有适当的余量不要被挤压或过度弯折。5. 系统集成测试与问题排查实录将所有部分组合在一起后激动人心的测试阶段就开始了。这个过程很少一帆风顺但每一个遇到的问题都是学习的机会。5.1 完整测试流程阶段一独立音频测试不连手机将编写好的代码使用板载按钮/触摸音频输出模式保存为code.py到CPX的CIRCUITPY盘根目录。拔掉USB线等待几秒后重新插入电脑或使用电池供电。此时板子应自动运行新代码。按下A按钮或触摸A4点应听到一声短促的“嘀”。按下B按钮或触摸A3点应听到一声较长的“嘀”。这验证了输入检测和音频输出功能正常。阶段二HID功能测试连接电脑修改代码启用HID键盘输出部分并注释掉音频输出部分。保存代码。此时CPX会模拟成一个键盘。打开电脑上的记事本或文本编辑器。触发“点”和“划”你应该在文本编辑器里看到“.”和“-”字符被输入。这验证了HID功能正常。阶段三手机端集成测试保持HID代码。用Micro-B OTG线将CPX与Android手机连接。手机会提示“USB设备已连接”或类似信息。打开手机备忘录将输入法切换到GBoard的摩斯码键盘。触发“点”和“划”。此时手机屏幕上GBoard的摩斯码输入界面应该能接收到信号并开始组字。尝试输入简单的摩斯码如“···”S或“---”O看是否能正确输出字母。5.2 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案CPX连接电脑后不出现CIRCUITPY盘符1. 未正确刷入CircuitPython固件。2. 板子处于Bootloader模式。3. USB线仅支持充电。1. 重新执行刷写UF2固件的流程。2. 按一次RESET键等待重启。3. 更换一根确认能传输数据的Micro-USB线。代码保存后无反应或报错1. 代码语法错误。2. 库文件缺失或路径错误。3. 文件名不是code.py。1. 检查Mu编辑器或终端是否有红色错误提示。仔细核对代码特别是缩进和冒号。2. 确认adafruit_hid库已正确放入CIRCUITPY盘下的lib文件夹。3. 确认主程序文件名为code.py全部小写。按下按钮电脑有反应但手机无反应1. 手机未开启OTG功能或线缆不支持OTG。2. 手机未切换到GBoard摩斯码键盘。3. 部分手机品牌对USB HID设备支持需手动授权。1. 尝试将CPX连接电脑测试HID功能是否正常以排除板子问题。确认OTG线或转接头是好的。2. 确保在文本输入框内并手动切换到GBoard的摩斯码键盘有时需要先切到GBoard再切到摩斯码。3. 连接时留意手机是否有“允许USB设备访问”的弹窗点击允许。在系统设置中搜索“USB”或“OTG”检查相关权限。电容触摸不灵敏或误触发触摸阈值设置不当。调整代码中的cpx.adjust_touch_threshold()值。尝试从200开始向下调如150 100或在干燥环境下从50开始向上调找到稳定触发点。外部按钮按下无反应1. 接线错误。2. 引脚配置错误。3. 按钮内部接触不良。1. 用万用表通断档检查按钮未按下时信号线与GND应不通按下时应导通。2. 检查代码中button_a和button_b定义的引脚号board.A4,board.A3是否与实际连接一致。3. 尝试更换按钮或直接用导线短接信号线与GND来测试如果短接有效则是按钮问题。发送信号过快一个按压产生多个字符缺少防抖或防抖逻辑有误。检查主循环中while touch_a(): pass这行代码是否存在且正确。这行代码确保了在按键释放前不会重复检测到新的按下动作。GBoard摩斯码键盘不转换字符1. 字符间隔时间不符合GBoard预期。2. GBoard语言/设置问题。1. 摩斯码靠“点”、“划”之间的时间间隔来区分字符和单词。我们的代码在每次发送后没有额外的延迟。可以尝试在dot()和dash()函数中的kbd.send()语句后添加一个短暂的time.sleep(0.05)给GBoard一点处理时间。2. 检查GBoard的摩斯码设置确保其处于激活状态并尝试重启输入法或手机。一个关键的调试技巧充分利用CPX板载的10个NeoPixel LED。你可以在代码的关键位置如进入dot()函数、进入dash()函数、检测到按钮按下时添加让特定LED亮起不同颜色的代码。例如cpx.pixels[0] (10 0 0) # 点亮第一个LED为红色这样即使没有声音或HID输出你也可以通过LED的闪烁状态直观地判断程序运行到了哪一步是硬件排查的利器。最后当所有功能测试通过你的摩斯码输入盒就正式诞生了。它可能看起来有些简陋但其中蕴含的从问题定义、方案选型、代码编写到物理实现的全过程正是创客精神的体现。你可以用它来练习摩斯码也可以为有需要的朋友定制一个更大、更符合其操作习惯的输入界面。这个项目的代码框架具有很强的扩展性你完全可以在此基础上增加更多的按钮来实现空格、回退、甚至自定义快捷键让这个小小的盒子发挥更大的作用。