当前位置:首页 > 工业控制 > 电路设计项目集锦
[导读]几周前,我决定开发CyberKey。这个想法源于工作中一件烦人的事:当我锁定电脑时,VPN会断开连接,而且我每天都要多次输入TOTP验证码。每次解锁手机、打开验证器应用、读取验证码并及时输入,直到它过期为止。CyberKey是一款小巧的设备,能彻底解决这一麻烦。只需将食指放在上面,蓝牙就会自动输入验证码。无需任何应用,无需手机,也无需复制粘贴。仅凭手指一动,验证码就会出现在输入框中。

CyberKey:从网页开发转行嵌入式项目时学到的经验

我是一名拥有6年经验的全栈Web开发人员,擅长Python、Rust、JavaScript、数据库和API。这就是我的日常工作。我从未接触过电子设备。

几周前,我决定开发CyberKey。这个想法源于工作中一件烦人的事:当我锁定电脑时,VPN会断开连接,而且我每天都要多次输入TOTP验证码。每次解锁手机、打开验证器应用、读取验证码并及时输入,直到它过期为止。CyberKey是一款小巧的设备,能彻底解决这一麻烦。只需将食指放在上面,蓝牙就会自动输入验证码。无需任何应用,无需手机,也无需复制粘贴。仅凭手指一动,验证码就会出现在输入框中。

该项目运行在一块M5StickC Plus 2上,这是一款大小如打火机的ESP32微控制器。它由M5Stack公司生产,该公司专门制造基于ESP32的模块,配备屏幕、电池和内置接口,同时还提供一系列兼容的传感器和外设。CyberKey中的指纹识别传感器就是其中之一。对于不想使用面包板和焊接的软件开发者来说,这是一个相当合适的入门选择。固件(直接运行在芯片上的程序,无需底层操作系统)采用Rust语言编写。在整个开发过程中,Claude给予了我大量帮助,大部分工作都发生在宝宝午睡的时间段,每天大约两小时。如果没有他的协助,我根本无法在合理的时间内完成这个项目。

这不是教程,而是我在六年网络开发中从未接触过的概念的总结,以及对固件架构的详细讲解,面向那些好奇网络开发背后技术细节的开发者。

硬件:当你的代码与物理世界交互时

最让我感到意外的是,微控制器与我之前接触过的任何东西都截然不同。服务器在其底层有操作系统:调度器、文件系统、网络栈和内存分配器。你可以在这些基础上编写代码。而微控制器则没有这些功能。它只有一块芯片、一些闪存和几百KB的RAM。无论你的程序需要做什么,都必须自己完成初始化设置。

最具体的体现就是**GPIO**引脚(通用输入/输出)。这些是芯片的物理引脚,每个引脚都连接到电路板上的导线,你的代码可以将其设置为高电平(3.3V)或低电平(0V),也可以读取其当前状态。这是一种布尔值,但由电流构成。点亮LED实际上就是将某个引脚设为“真”;而读取按钮按下事件,则是在循环中读取该引脚的电平值。

为了让芯片之间能够相互通信,嵌入式系统使用了一组小型的标准协议。我在CyberKey中使用的三种是**UART**、**I2C**和**SPI**。让我印象深刻的类比是,它们在功能上大致相当于网络开发中的不同网络协议:每种协议都在简单性、速度以及可连接设备数量之间做出了权衡。

UART 最简单:两根线,两个设备,无共享时钟。双方事先约定传输速率(波特率),仅发送比特。这正是你用来烧录和调试电路板的 USB 串口所基于的协议。I2C 只用两根线,但支持同一总线上多个设备,每个设备都有独立地址,类似于 IP 地址。速度较慢,但非常适合传感器和时钟等不需要高吞吐量的应用。SPI 是最快的:四根线,带专用时钟,可实现高达 80 MHz 的数据传输速率,因此常用于显示屏。

最让我感到惊讶的是SPI背后的层次结构。它有四根线:CLK(时钟)、MOSI(数据输出)、MISO(数据输入)和CS(片选)。前三个构成一个**总线**,物理上由所有组件共享,就像一根电缆同时连接多个芯片一样。当ESP32发送时钟信号时,所有连接的芯片都会同时接收到该信号。第四根线CS的作用是决定哪一块芯片响应,而其他芯片不响应:当特定芯片的CS被拉低时,该芯片才会响应;其余芯片则忽略该信号。

在代码中,这对应于一个清晰的层次结构:一个**驱动器**管理三条共享的总线,而一个**设备**将该驱动器与一个特定的CS引脚结合,以表示单个组件。如果你的显示设备和SD卡共用同一根总线,那么你就会有一个驱动器和两个设备,每个CS引脚对应一个设备。这里的“总线”并非偶然,它与城市公交车的比喻相同——一条共享路线,多个乘客可以乘坐,每个人在自己的站点下车。

固件架构

Web服务器入口在开始处理请求之前,会执行许多操作:连接数据库、注册中间件、设置路由、启动后台作业队列。但在这些功能的背后,还存在操作系统对内存和调度的管理、运行时对输入输出的处理,以及提供事件循环的框架。你是在建立已经存在的多个层次之上进行开发的。

在嵌入式系统中,这些层并不存在。`main()` 并不是程序的起点,而是整个程序。在 CyberKey 的固件中,`main()` 是一个长而连续的初始化函数:

电源引脚:必须立即保持高电平,否则在松开按钮时电路板将关闭。

**电池ADC**:用于读取电池电压的模数转换器;该芯片只能识别数字,无法直接处理电压,因此需要硬件进行转换。

**命令行界面的UART**:用于连接笔记本电脑的串行接口,通过USB进行指纹录入和时钟同步

I2C 用于实时时钟:这样设备就能知道当前时间,从而生成有效的 TOTP 代码

**显示的SPI**:用于显示当前状态、TOTP验证码以及BLE配对PIN码的屏幕

**BLE**:蓝牙低能耗,一种无线协议,使设备在计算机上表现为键盘

指纹传感器:通过UART连接至Grove接口(M5Stack标准接口,单个插头内集成了电源和通信协议,无需焊接)

每个组件都需要独立的协议配置、独立的引脚和独立的驱动程序。只有在所有内容初始化完成后,控制权才会传递给主循环。

顺序至关重要。在完成硬件复位序列之前初始化显示控制器会导致黑屏。在SPI总线准备好之前启动BLE会引发崩溃。没有任何框架能捕获你的错误。如果操作顺序有误,设备将无法正常工作,而且通常不会显示任何错误信息。

初始化后,固件会运行一个永不退出的循环。它检查按钮、处理BLE事件、监听指纹匹配、更新显示并读取电池电量。这就是你自己编写的事件循环。

在网页开发中,没有能与之相媲美的东西就是电源管理。运行在200mAh电池上的设备会快速耗电,而你让任何组件持续运行都会产生运行成本。ESP32具备睡眠模式,本应能在使用之间大幅降低功耗。我花了不少时间试图让这些模式生效,却始终未能成功。由于一些我至今仍无法完全确定的原因,芯片实际上从未真正进入睡眠状态。最简单的有效解决方案是:按下按钮C,通过将GPIO拉低来完全切断电源。此时电路板立即关闭,不再消耗电力,并在下次启动后几秒内自动重新连接到已绑定的主机。

嵌入式中的 Rust:介于 C++ 与空之间

嵌入式系统中,Rust 并非主流语言。C 和 C++ 是主流。Espressif 的官方 ESP32 SDK(称为 ESP-IDF)是用 C 编写的。M5Stack 的官方驱动程序则使用 C++ 编写。大多数社区成员、教程和示例也都采用 C 和 C++ 语言。

使 Rust 在这里可用的原因在于,有一层 crates 将 ESP-IDF 的 C 代码封装起来,并通过 Rust API 提供接口。当我调用函数来读取电池电压时,表面上是 Rust,但底层仍是 C 语言实现的。你获得了 Rust 提供的安全保障,同时仍然建立在用 C 编写的底层基础之上。

实际的结果是,阅读C++代码已成为工作流程的一部分。要了解某个组件的运行方式,最可靠的来源通常是官方的C++驱动程序:需要切换哪个引脚、按什么顺序以及使用什么样的时序。对于指纹传感器,M5Stack发布了用C++编写的Arduino驱动程序。我读了它,理解了其实现的UART通信协议,并从零开始用Rust重新编写了这个驱动程序。这并非因为Rust本身要求这样做,而是因为当时还没有适用于该传感器的Rust驱动程序。

这给了我一个名为 `fingerprint2-rs` 的 crate,使用 `no_std` 编译。`no_std` 注解告诉编译器,这段代码不能依赖标准库,因为标准库假设底层有一个操作系统。没有操作系统,就没有标准库,也就没有运行时开销。

至于Rust具体带来了什么:编译器在每个阶段都强制执行错误处理,这一点很重要,因为一次失败的I2C读取可能会悄无声息地破坏你的状态。内存由开发者显式管理,没有垃圾回收机制。当可用内存仅有几百KB时,这一点就显得尤为关键。我不会夸大其词:Rust并没有让硬件更易于理解,但它确实让代码在编译后更值得信赖。

网页开发没有为你准备好的东西

**无需热重载。** 固件的每次修改都遵循相同的流程:编辑代码、编译、通过USB将二进制文件刷入设备、等待设备启动,然后观察。一个完整的迭代大约需要一分钟。你很快就会学会在敲代码前先思考。

**崩溃可能导致设备无法使用。** 在网页开发中,未处理的异常会打印堆栈跟踪并导致进程重启;而在嵌入式系统中,劣质的固件可能会使设备陷入无限重启循环,无输出或完全无响应。所谓“砖机”(bricking)意味着设备变得如同砖块一般:无法启动,且若要恢复它,必须执行特定的刷写程序,甚至可能根本无法恢复。在本项目中,我从未遇到过这种情况,但这种可能性决定了你对每次更改进行测试时的严谨程度。

内存不可弹性扩展。ESP32 内部有 520 KB 的 RAM,没有堆内存的扩展、无交换空间,也没有“简单增加更多”的选项。每一次内存分配都是一个决策。这正是 `no_std` 能发挥作用的地方:通过设计,内存使用量变得明确且可预测。

电池始终萦绕在你心头。在网页开发中,能耗是隐形的,这是云服务提供商的问题。对于一个使用200毫安时电池的设备而言,任何被开启的组件都会消耗你的续航能力。这迫使我们以不同的方式思考每一项架构决策,而这种思维方式完全出乎我意料,原本并非来自网络领域。

与AI共同协作开发

我在引言中提过,但有必要具体说明:在整个项目过程中,我大量依赖了Claude。并不是盲目地信任它作为代码生成器,而是作为一种保持思路畅通的方式。当你在宝宝醒来前还有两个小时时,绝不能花四十五分钟去弄清楚为什么你的I2C总线卡住了。有了能解释概念、指出相关部分并勾勒出方向的工具,整个进度就会完全改变。

它所不能替代的,是那些需要判断的决策。我负责确定方向、功能设计、架构以及质量标准。当某件事出现问题时,我会在设备上进行测试,查看终端输出,并查阅M5Stack官方文档、他们的GitHub仓库,以及一些基于相同硬件开发的开源项目,寻找解决方案。很多时候,正是这些方法最终帮我们解决了问题,而不是AI。有时,直觉也恰恰证明了正确。

我遇到的风险是:动作太快。在多个阶段,我实现了某个功能、上线后便继续前进,却并未完全理解自己刚刚写下的代码。后来当系统出现问题时,我才不得不重新阅读自己的代码,仿佛它属于别人一般。

结果与要点

设备运行正常。将已注册的手指放在传感器上,系统会识别并显示TOTP验证码,通过蓝牙在不到一秒内输入完成配对。BLE配对、显示屏、实时时钟、USB命令行接口:所有功能均按预期运行。对于首个嵌入式项目来说,目前的成果让我感到满意。

唯一令人失望的是电池续航。200mAh的电池,设备能使用大约3到4小时。我尝试了各种方法来改善这一点——睡眠模式、传感器待机、不同的组合设置,但都没有带来显著的提升。我一直没能完全理解其中的原因。目前最务实的解决方案是强制关机:按一下按钮C即可在硬件层面切断所有电源,下次开机时设备会自动重新连接到已绑定的主机。虽然不够优雅,但诚实可靠。如果你有不需要硬件改动的改进想法,我非常乐意看到你的拉取请求。

如果我再做一次,我会在编写代码之前花更多时间去理解核心概念。我遇到最困难的时刻,总是那些跳过了基础内容的时候。此外,我还会从一开始就添加日志,没有它们调试嵌入式硬件就只能盯着一个静止的设备猜测。

更广泛的启示是:嵌入式开发对网页开发者来说是可接触的。这些概念虽然陌生,但易于学习,而清晰架构和可读代码的直觉也容易迁移。它只是比学习一个新框架更令人困惑的一种形式而已。

本文编译自hackster.io

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

7月10日至12日,2026人工智能终端产业博览会暨“苏品苏货·必购必带”智能潮品展于南京国际博览中心举办。本次活动由江苏省工业和信息化厅、江苏省商务厅、江苏省科学技术协会、新华报业传媒集团共同主办,旨在全面落实“人工智...

关键字: 人工智能 智能终端 嵌入式

无安装次数限制、内置优化工具,可简化并加速嵌入式与边缘AI部署

关键字: 编译器 机器学习 嵌入式

meta-xilinx 生成的默认 boot.scr 使用了 bootm 命令,该命令需要一个 FIT 图像(image.ub)或 uImage。由于我们已将 Yocto 配置为构建 zImage,U-Boot 能够加载...

关键字: 嵌入式 Linux系统 Zynq板

近日,西门子家电携手中国室内装饰协会,正式重磅发布《家居一体化嵌入式冰箱室内装饰融合技术规范》*。本次标准的落地,以专业准则定义行业新标杆,以创新设计赋能人居生活,有效推动嵌入式家电与室内装饰场景的深度融合、协同共生,为...

关键字: 嵌入式 冰箱 传感器

以往的微控制器字节节奏播放器都是静态的,每次修改都需要重新烧录字节节奏算法,这种方式效率低,不利于对字节节奏算法和数字音频合成进行实验。Bytebed 是一种全新的生动方式,用于演奏和探索字节节奏的世界。

关键字: 嵌入式 微控制器 M5Stack

基于Hypervisor虚拟机融合CODESYS PLC,在标准硬件上高效整合混合关键性负载

关键字: 工业自动化 嵌入式 机器人

AI数据中心带火了内存,但在高性能的嵌入式系统中,内存同样关键。无论是广播级的8K视频处理、精密的PXIe测试仪器,还是电信级的网络安全设备,它们同样面临着数据爆发带来的挑战。一方面,由于AI驱动导致内存需求激增,全球内...

关键字: AMD MoP 自适应SoC 嵌入式 LPDDR5X

项目背景:随着嵌入式 AI 技术的快速发展,边缘计算设备的算力不断提升,使得在低功耗、低成本的嵌入式平台上部署深度学习模型成为可能。本项目基于瑞芯微 RK3576 芯片的 NPU(神经网络处理单元)加速能力,结合 YOL...

关键字: 机器人 视觉伺服系统 嵌入式

随着智能汽车、具身智能和智能制造等各个战略新兴技术领域快速发展,物理AI时代正在加速到来;随着而来的新场景、新技术和新功能为系统开发者提出了众多新的要求,也带来了诸如多架构SoC、更高代码质量、功能安全性、更高可视度、自...

关键字: 物理AI 嵌入式 智能汽车

剪掉参数后推理反而变慢,听起来矛盾,却很常见。嵌入式AI优化若只盯 FLOPs,不看硬件支持的算子形状,模型压缩会把规则计算改成低效搬运。

关键字: 嵌入式 AI 算子
关闭