从简单的 CC 显示器入门嵌入式

从简单的 CC 显示器入门嵌入式

1. 背景:一个真实的小需求

这次分享的起点,是一个很具体的小需求。我们平时会同时开多个 Claude Code 窗口并行处理不同项目,比如一个改 TCP 服务、一个调 HTTP 服务、一个处理 dirtyfilter。

它们都在后台运行,但我很难一眼看出哪个已经完成、哪个在等待我输入、哪个出错了,只能逐个切换窗口查看,效率不高。我想要的东西其实很简单:桌面上有一块小屏幕,扫一眼就知道每个 Claude 窗口当前的状态。

用纯软件来解决(再开一个网页,或者写一个 App)也可以解决,但是总感觉有点不新鲜的感觉。于是想到可以在物理世界用一块闲置的 Arduino 来做。

**最终成果:**一块 20(字符)×4(行) 的字符屏,每行显示一个 Claude 窗口的状态(R 运行中 / W 等待输入 / D 已完成),实时刷新。整套成本不到 30 元,半天完成。下面就以这个项目为线索,介绍嵌入式的一些基本概念和我接触到的一些相关内容。

2. 什么是嵌入式

先澄清一个常见的误解:嵌入式并不是"底层、硬核、与日常开发无关"的领域。 实际上它无处不在。

简单说:嵌入式系统,就是把一块计算单元"嵌入"到设备中,专门完成某个特定任务。身边的例子很多:

  • 机械键盘里有芯片,负责扫描按键

  • 家用路由器,本质是运行精简系统的小型计算机

  • 扫地机器人、智能门锁、空调遥控器、汽车里的几十个控制单元

  • AirPods、氮化镓快充头(内部有芯片实时调节功率)它与我们熟悉的后端 / App 开发,有三个本质区别:

    • 资源 :常规软件内存以 GB 计、CPU 多核 GHz;嵌入式内存以 KB 计、主频 MHz。这次用的 Uno 只有 2KB 内存、16MHz 主频。

    • 运行方式:常规软件跑在操作系统上,可随时重启、发布;嵌入式往往没有操作系统,代码烧录进芯片后持续运行,修改需要重新烧录。

    • 软硬关系 :常规开发只关心软件;嵌入式软硬一体,需要了解某根线接哪个引脚、某个信号是高电平还是低电平。一句话概括:常规软件是"资源充足、随时可改",嵌入式是"资源受限、烧录后不易改动"。

用 AI 一句话描述嵌入式就是

  • 不跑在操作系统上、也不联网等部署的一种程序------它烧进芯片、上电即运行、专做一件事。

3. 软件工程师为什么值得了解它

可能有人会问:业务代码写得好好的,为什么要了解这个?

  • 打通软件与硬件之间的认知。 我们平时把硬件当作黑盒:网络慢、磁盘满。了解一点嵌入式后,会对"一个字节如何从内存传到网线上""中断是什么"有更具体的认识,而不只停留在概念层面。

  • AIoT 时代的复合竞争力。 端侧 AI、边缘计算正在快速增长。同时懂软件和硬件约束的工程师,能完成纯软件或纯硬件背景都难以独立完成的工作。

AIoT = AI(人工智能)+ IoT(物联网),即"人工智能物联网"------让联网设备不只是采集和上报数据,还能在本地或云端用 AI 对这些数据做判断、决策。

  • 反馈即时,便于建立兴趣。 常规后端开发改完需要部署、等待监控数据;嵌入式则是代码烧录后,屏幕或 LED 立即产生变化。这种直接的反馈,加上一个周末就能做出实物,是很好的入门体验。

  • Vibe Coding 趋于日常化。很多想法和内容都可以在以前实现不了的基础上去实现了,有想法可以多动手去完成


4. 实战案例:Claude Code 状态显示器

下面通过这个项目,看一个真实的嵌入式小系统是什么样子。

4.1 硬件选型(总成本约 30 元)

  • 主控板:Arduino Uno R3(国产兼容版,CH340 串口芯片,Type-C 接口),约 20 元。负责接收数据、驱动屏幕。

  • 显示屏:LCD2004(20 列 × 4 行字符屏,带 I2C 转接板),约 10 元。I2C 地址 0x27。

  • 连接线:杜邦线 4 根 + USB 线 1 根。I2C 只需 4 根线:电源 2 根、数据 2 根。

为什么选 Uno:它是嵌入式中最适合入门的板子------社区规模大、教程多、库齐全、烧录简单。入门阶段应优先把概念跑通,而不是追求性能。

4.2 整体架构

这是整个项目最关键的一张图,核心思想是职责分离

4.3 三个文件的职责划分

软件工程师第一次看时常会疑惑:烧录进板子的程序,似乎和 Claude、和项目状态没有任何关系。这正是嵌入式设计的关键所在。三个文件各自的职责:

  • 板子固件(.ino) :运行在 Uno 芯片中。只做显示:串口收到一行文本,按分隔符切成 4 段,刷新到屏幕 4 行。修改后需要重新烧录

  • monitor-daemon.py:运行在电脑后台。持有串口连接、汇总多个窗口的状态、决定最终显示内容。修改后重启进程即可生效。

  • status-hook.py :运行在电脑端,Claude 每次状态变化时调用。把"当前窗口的标识和状态"上报给守护进程。修改后立即生效。核心结论:板子固件中没有任何业务逻辑。 它不知道 R 代表 Running,也不知道某个字符串是项目名。它只负责一件事------收到文本就显示。所有的逻辑(采集状态、汇总、格式化)都在电脑端的 Python 中完成。

4.4 板子固件

整个固件只有几十行,核心是一个持续运行的循环:

C++ 复制代码
void loop() {
  while (Serial.available()) {   // 串口是否有数据
    char c = Serial.read();      // 读取一个字符
    if (c == '\n') {             // 读到换行,表示一条完整消息
      render(buf);               // 刷新到屏幕
      buf = "";
    } else {
      buf += c;                  // 否则继续累积
    }
  }
}

烧录后,它会持续重复这个过程:检查串口是否有数据、有则累积、累积满一行就显示。资源占用:芯片存储 19%、内存 23%,仍有较大余量。

这解释了前面的疑惑:固件与业务无关是有意为之的设计。让板子负责最简单、最稳定的工作(显示),把容易变化的逻辑(状态如何定义、如何汇总)放在电脑端------修改电脑端代码即可生效,无需反复烧录。

4.5 实现中遇到的问题

以下三个问题,比较能反映嵌入式开发的实际特点。

  • 打开串口会导致板子复位。 Arduino 有一个特性:电脑打开串口连接时,会触发 DTR 信号使板子自动复位。如果每次上报状态都重新打开串口,板子会反复重启,屏幕来不及显示。解决方法是让守护进程只打开一次串口并一直持有,后续数据都通过这个连接发送。

  • 后台进程无法读取脚本文件。 macOS 的隐私保护机制(TCC)默认禁止后台服务访问"下载、文稿、桌面"目录。脚本放在下载目录时,后台运行会报告"无权限"。解决方法是把脚本移动到未受保护的目录。这类问题在常规开发中较少遇到,但在做系统集成时较为常见。

  • 连接不稳定。 廉价 USB 线和杜邦线容易接触不良,移动板子时可能断连。解决方法是在守护进程中加入自动探测设备和断线重连------即使板子拔出重插、设备号变化,也能自行恢复。这体现了嵌入式开发中的一个常态:物理环境不可靠,需要在软件层面做容错。

4.6 最终效果

屏幕上每行对应一个 Claude 窗口:

Plain 复制代码
R sidecar          运行中 3min
W My-Quantify      等待输入 3second
D cc-monitor       已完成

扫一眼即可掌握全局,最初的需求得到解决。同时因为行数限制只会展示最新的四个任务进度。

5. 技术细节:跟着一次状态更新走一遍

前面讲的是"是什么",这一节回答"怎么做到的"。我们跟着一次真实的状态变化------比如某个 Claude 窗口刚刚跑完任务------看它如何一路变成屏幕上的一个 D

5.1 代码做了什么:三段接力

一次状态更新,依次经过三段代码:

  • status-hook.py(上报) :Claude 每次状态变化都会调用它。它只做一件事------把"当前窗口的标识、状态、项目名"拼成一行文本 sid|state|proj,写进一个管道(FIFO)。例如 a1b2|DONE|cc-monitor

  • monitor-daemon.py(汇总) :常驻后台,从管道里读到这些上报,维护一张"所有窗口 → 状态"的表。每收到一条就重新排序,取最近活跃的 4 个,格式化成 4 行文本(每行 状态字符 + 项目名),通过串口发给板子。

  • 板子固件 .ino(显示):收到一行文本,按分隔符切成 4 段,刷到 LCD 的 4 行上。

关键点:真正"知道" R 代表运行中、cc-monitor 是个项目名的,全是电脑端的 Python。 板子固件对这些一无所知,它只负责"收到文本就显示"。这就是第 4 节说的职责分离------把易变的逻辑放在好改的地方(电脑端),把稳定的显示放在难改的地方(板子)。

5.2 数据怎么到屏幕:从电脑到像素的旅程

monitor-daemon.py 把 4 行文本"发出去"之后、到屏幕亮起来之前,中间还隔着两段物理链路。第一段:电脑 → 板子,走串口(UART)。 串口的原理很朴素------用一根线,把数据一位一位地传过去(串行),事先约定好传输速度(波特率,本项目 9600,即每秒 9600 位)。

可以类比为:两个人用手电筒打摩尔斯电码,先约定每秒闪几次,再靠明灭传递信息。之所以不用 USB 协议栈或 HTTP,是因为串口足够简单、可靠,是沿用了几十年的工业标准,几乎所有单片机都原生支持。

.

这正体现了嵌入式"够用即可、越简单越可靠"的取向。第二段:芯片 → 屏幕,走 I2C 总线。 数据进了板子的主控芯片(MCU)之后,还要再传给 LCD 屏。LCD2004 本身有 16 个引脚,直接接会占满板子;本项目用的版本带 I2C 转接板,只需 4 根线(电源 2 根 + 数据 2 根)。

.

I2C 是一种总线协议:多个设备挂在同样两根线上,每个设备有一个地址(这块屏是 0x27),主控按地址寻址通信。可以类比为:一条走廊上有多个房间,每个房间挂着门牌号,按门牌号找人。把这两段串起来看,整个系统是典型的主机---从机 结构:电脑是主机(负责决策------采集、汇总、决定显示什么),板子是从机(负责执行------收到什么显示什么)。电脑与打印机、U 盘、鼠标之间,都是这种关系。理解了这一点,也就理解了板子为什么可以如此简单:复杂的判断本就该交给主机。

.

I2C 总线协议链接 https://zhuanlan.zhihu.com/p/678229227

5.3 为什么叫"烧录":代码是怎么写进芯片的

到这里有个一直没回答的问题:固件这段代码,最初是怎么"进到"板子里的?先澄清一点:代码并不是写到 PCB 电路板本身,而是写进板上那颗主控芯片(MCU)内部的存储区。PCB 只是承载芯片、连接各部件的载体,真正"记住"程序的是芯片里的 Flash 存储。整个写入过程分四步:

  1. 编译:你写的 .ino 源码,被编译成芯片能直接执行的机器码(.hex 文件,本质是一串二进制指令)。

  2. 传输:机器码经过 电脑 → USB → 板上的串口芯片(CH340)→ 送到 MCU。

  3. 写入:MCU 中预置了一小段引导程序(bootloader),由它接收机器码并写进 Flash。

  4. 驻留 :写完后,程序就一直留在 Flash 里------这正是下一节"为什么能立即起作用"的前提。那为什么叫"烧录"(burn)?这是个历史词。早期的只读存储器(PROM)写入时,是用较高电压把芯片内部的微型熔丝真的烧断,以此表示 0 和 1,而且不可逆------所以叫"烧"。后来的 Flash 改用电荷存储、可反复擦写,但"烧录"这个叫法沿用了下来。

5.4 为什么烧录一次,程序就能立即起作用

软件工程师容易有个直觉:代码总得先"运行起来"------启动进程、加载进内存、由操作系统调度。但板子上并非如此:烧录完,断电再上电,程序立刻就在跑,不需要任何"启动"动作。 原因有三层:

  • 断电不丢 :Flash 是非易失性存储,它的存储单元是一种特殊晶体管(浮栅晶体管),电荷被困在绝缘层包裹的"浮栅"里,即使没有供电也能长期保持。U 盘、SSD 用的是同类技术。所以程序烧进去,就"焊死"在那里了。

  • 上电即跑,没有操作系统这一层:Uno 是"裸机"运行,没有 OS、没有进程调度。一上电,MCU 复位后直接从 Flash 的固定位置开始执行。少了操作系统启动的那一整套流程,所以"通电 = 运行"。

  • 固件本身是个永不退出的循环 :它的结构是 setup() 跑一次(初始化屏幕、串口),然后 loop() 无限重复(检查串口有没有新数据、有就刷屏)。只要通着电,这个循环就一直转,屏幕也就一直在工作。

6. 嵌入式 C:几个让后端工程师意外的点

固件就是 C/C++,语法你都会。真正有点"水土不服"的,是下面这几处------都源自"芯片只有 2KB 内存、还得直接碰硬件":

  • 没有 main(),程序就是一个永远跑的循环。 入口是 setup()(上电只跑一次,做初始化)和 loop()(之后被无限重复调用)。你写的不是一段会结束的程序,而是一个永不退出的循环体。

  • delay(1000) 会让整块芯片干等一秒。 单核、没有线程,一 sleep 全停;想同时做几件事,得自己记时间戳(millis())判断到点没。

  • Serial.println 是你唯一的调试器。 没有控制台、没有日志文件,看不到现象时就往串口打印,靠它定位一切。

  • 几乎不用 malloc。 2KB 内存经不起堆碎片,惯例是全程用栈和固定大小数组,类型还得写死位宽(uint8_t 而不是随手 int),省一个字节都算数。

  • 直接往引脚写电平。 digitalWrite(13, HIGH) 就是给某根线通 5V------一盏灯、一个电机,最底层都是"这根线给不给电"。

C++ 复制代码
void setup() { Serial.begin(9600); }   // 只跑一次:初始化
void loop()  { /* 被一遍遍重复执行,永不退出 */ }

一句话:写后端是"资源管够、随便 sleep 随便 new";写嵌入式是"掐着字节过日子、一刻不能停"。约束逼出的,是另一套直觉。

7. 进阶与扩展

本项目使用的 Uno 适合入门。上手之后,换用性能更强的板子,可以做的事情会显著增加。

7.1 主控板选型(按对软件工程师的友好度排序)

  • ESP32 :双核 240MHz,内置 WiFi 和蓝牙,约 15--40 元。需要联网时的首选,性能和无线能力一步到位。

  • 树莓派 Pico:双核 ARM 133MHz,Pico W 版本带 WiFi,约 4--10 美元。支持 MicroPython,IO 灵活。

  • Arduino Uno:16MHz,无无线,约 20 元。适合入门教学。

一个重要的升级方向:从 Uno 换到 ESP32,设备就从"需要插 USB 线的桌面装置"变成"可联网的物联网设备"。本项目若用 ESP32 重做,就能去掉数据线、通过 WiFi 推送状态。

7.2 降低门槛的工具

对软件工程师而言,以下工具可以大幅降低嵌入式开发门槛,甚至不必编写嵌入式 C:

  • ESPHome:用 YAML 描述设备配置,自动编译烧录。只需声明"设备有哪些传感器、哪些开关",无需手写 C。

  • Tasmota:刷入 ESP 芯片的开源固件,刷写后通过网页界面配置,连编译都省去。

  • Home Assistant:开源的智能家居中枢,上述设备接入后几乎零配置,可统一管理和编写自动化。

  • MQTT:物联网设备通信的事实标准协议。对后端工程师而言概念上零门槛------本质是一个轻量级的发布/订阅消息总线,与消息队列类似。

概括:ESPHome / Tasmota 把"写固件"简化为"写 YAML / 配置网页",MQTT 让设备像微服务一样收发消息,Home Assistant 负责聚合管理。后端经验几乎可以平移过来。

7.3 可参考的开源项目

以下都是网上可以找到的、由软件工程师完成的开源项目:

  • 墨水屏天气站 / 日历(esp32-weather-epd,数千 star):ESP32 + 墨水屏,调用天气接口,一块电池可续航 6--12 个月。

  • 自动浇花(Plantwatery 等):ESP32 + 土壤湿度传感器 + 水泵 + 太阳能板,根据湿度自动浇水。ESPHome 版本可纯配置实现,无需编码。

  • 小米温湿度计刷机(pvvx/ATC_MiThermometer,明星项目):用浏览器把约 30 元的小米温湿度计刷成自定义固件,开放数据接入自有系统。无需焊接和编程,适合入门。

  • 智能门铃、自动喂食器、NAS 状态屏:都是 ESP 系列加一两个模块的组合,社区有现成方案。

7.4 端侧 AI:把"离线版小爱同学"做出来

这是最能打动人的方向------让设备在本地跑 AI,完全不上云:响应快、断网可用、数据不出设备。几个软件工程师够得着的例子:

  • 离线语音助手(类小爱同学):ESP32-S3 + 麦克风,在本地做唤醒词和有限指令识别("开灯""几点了"),不联网也能用,比商业音箱多了隐私和可定制。

  • 离线天气台:ESP32 + 墨水屏,联网时拉一次天气接口缓存下来,之后断网也持续显示;一块电池能撑半年到一年,往桌上一摆就是个独立设备,不依赖手机 App。

  • 离线视觉:ESP32-CAM 在板上跑人体 / 人脸检测,检测到人才点灯或开门,画面始终不离开设备;ESP32-S3 约 0.2 秒就能完成一次拍照加推理。

  • 工具链对软件工程师友好:Edge Impulse、Google Teachable Machine 支持在浏览器里"采集数据 → 训练 → 一键部署到芯片",不用从零写神经网络。

8. 软件工程师怎么玩:买开发板,别自己设计电路

玩嵌入式常见的第一个顾虑是:我得会画电路、会焊板子吗?完全不用。 从零设计电路是另一个专业,和我们想做的事可以彻底解耦。先看清硬件圈的金字塔,知道自己站在哪一层:

  • 高端硬件专家:从零设计电路------选 CPU / 内存 / 电源芯片,画 8~16 层高速 PCB,搞定信号完整性、电源完整性、射频天线、EMC 和车规温度寿命。显卡、服务器主板、5G 基站就出自他们手,门槛是半导体物理 + 微波 + 高等数学。

  • 中级熟练工:独立设计常见消费电子(智能手表、小家电),懂一点高速电路和电源。

软件开发工程师不碰电路设计,拼乐高就行。软件工程师的玩法就是拼乐高

  • 大脑买现成:ESP32(自带 Wi-Fi / 蓝牙,十几块)、STM32、树莓派 Pico,都是火柴盒大小的现成核心板。

  • 外设买"模块":要显示买 OLED 模块、测温湿度买 DHT11 模块、驱动电机买电机驱动模块------不用算电阻、不用焊贴片。

  • 免焊连接:一块面包板 + 一包杜邦线,像连线题一样把板子和模块插起来,插错随时拔了重来,不烫手、零成本。

  • 精力 100% 放在写代码:USB 一插,就回到你熟悉的领域------读传感器数据、驱动屏幕、或通过 Wi-Fi 发到服务器和手机。

一句话:把电路设计和 SMT 焊接留给专业硬件工程师;你只管买好积木、用代码给它注入灵魂。这是软件工程师效率最高、也最有成就感的嵌入式玩法。

9. 入门建议

如果有兴趣尝试,可以从以下方式低成本起步。入门套件(总价约 50 元以内)

  • 一块 ESP32 开发板(建议直接选可联网的,约 25 元)

  • 两个传感器(温湿度、土壤湿度,约 15 元)

  • 杜邦线和面包板(约 10 元)学习路径(由浅入深)

  1. 用 Arduino IDE 点亮一颗 LED(入门级,约 10 分钟)

  2. 接入传感器,把读数输出到串口

  3. 用 ESPHome(写 YAML)做一个联网温湿度计,接入 Home Assistant

  4. 进阶可尝试 Edge Impulse,在板子上运行 TinyML 模型第一个项目建议不必一开始就做复杂的项目。从"刷一个小米温湿度计"或"做一个桌面天气屏"入手即可------有即时反馈,容易建立信心。


10. 附录:术语表

按文中出现顺序整理,方便查阅:

  • 嵌入式系统:把计算单元嵌入设备、专门完成某个特定任务的系统。

  • MCU(微控制器):把 CPU、内存、存储、外设接口集成在一颗芯片上的"单芯片计算机",是嵌入式的核心。本项目 Uno 的主控就是一颗 MCU。

  • PCB(印刷电路板):承载芯片和各类元件、并用走线把它们连起来的板子。它本身不存储程序,只是"底座"。

  • 固件(Firmware):烧录进芯片、直接控制硬件运行的程序。介于硬件和软件之间,所以叫"固"件。

  • 烧录(Flashing / Burning):把编译后的机器码写入芯片 Flash 存储的过程,词源见 5.3。

  • Flash 存储:一种断电不丢数据的非易失性存储,U 盘、SSD 属于同类技术。

  • Bootloader(引导程序):芯片中预置的一小段程序,负责接收并写入新固件,相当于烧录时的"接待员"。

  • UART / 串口:一种把数据逐位传输的串行通信方式,简单可靠,是单片机的标准通信接口。

  • 波特率(Baud rate):串口的传输速度,单位是位/秒。本项目用 9600。

  • I2C:一种总线协议,多个设备共用两根线、按地址寻址通信。

  • GPIO / 引脚:芯片对外的通用输入输出接口,软件通过控制引脚的高/低电平与外部器件交互。

  • 电平:用电压高低表示数字信号,高电平代表 1、低电平代表 0。

  • DTR 信号:串口的一个控制信号,Arduino 用它实现"打开串口即复位",正是 4.5 中第一个问题的来源。

  • TCC:macOS 的隐私保护机制,限制程序访问敏感目录,是 4.5 中第二个问题的来源。

  • MQTT:物联网常用的轻量级发布/订阅消息协议。

  • TinyML:在单片机等资源受限设备上运行机器学习模型的技术。

  • AIoT:人工智能(AI)与物联网(IoT)的结合。


这个案例本身并不复杂,但它完整覆盖了嵌入式开发的几个核心概念:串口通信、固件与软件的分层、主机---从机协作。对软件工程师来说,用一个周末、一块入门板子,就能把这些原本停留在文档上的名词,变成手里可以运行的实物------这是了解嵌入式最高效的方式。本文涉及的代码和完整过程均可复现,有兴趣的同学可以交流。

相关推荐
xxwxx__1 小时前
51单片机定时器/计数器中断详解(T0和T1)——从入门到精通
c语言·单片机·嵌入式硬件·51单片机
飞猿_SIR2 小时前
RK3288 Android11平台移植RTL8733BU-WiFi模组
android·嵌入式硬件
国产化创客2 小时前
嵌入式视觉完整技术体系--ESP32/K230/RDK-X5/树莓派四层架构全解析
嵌入式硬件·物联网·架构·开源·智能硬件
cft56200_ln2 小时前
TDA4时间同步3 网卡添加虚拟时间戳
c语言·开发语言·arm开发·驱动开发·嵌入式硬件·网络协议
HAPPY酷2 小时前
STM32 两种烧录方式对比:Keil Load vs FlyMCU 串口下载
stm32·单片机·嵌入式硬件
清风6666662 小时前
基于单片机的汽车胎压与温度监控系统
单片机·嵌入式硬件·汽车·毕业设计·课程设计·期末大作业
济6172 小时前
ROS开发专栏---ROS2 机械臂应用入门(2)---机械臂自动抓取物品实验---适配Ubuntu 22.04
嵌入式硬件·嵌入式·ros2·机器人开发·机器人方向
济6172 小时前
ROS开发专栏---家庭服务机器人饮料递送实验---适配Ubuntu 22.04
嵌入式硬件·嵌入式·ros2·机器人方向
清风6666662 小时前
基于单片机的自动路灯监控系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业