跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组
皮肤
  • 浅色
  • 深色

折叠

半部电台

N

niuguanchong

@niuguanchong
administrators
取消关注 关注
关于
帖子
4
主题
4
分享
0
群组
1
粉丝
0
关注
0

帖子

最新 最佳 有争议的

  • 半部电台还能做什么?16 个应用创意(附实现路径,欢迎认领)
    N niuguanchong
    综合讨论 应用场景 半部电台 头脑风暴

    「半部电台」现在能做的事情已经不少了:附近消息、摩斯、十款桌游、电子宠物、遥控和扫描。但一块 ESP32-C6 + 128×32 OLED + 一颗旋钮 的小板子,能做的事远不止这些。

    这个帖子想干两件事:把能用的硬件和它的边界摊开,然后抛一批具体的创意——每条都写清楚用哪块资源、大概什么难度。看中哪条,直接在下面认领。


    先把"武器库"摊开

    创意的上限是硬件决定的,所以先看这张表。左列是能力,右列是必须先接受的限制——限制不是劝退,是筛选器。

    能力 能做什么 必须知道的边界
    BLE 广播收发 不建连接、不等配对,几十米内发消息 单包载荷 128 字节,广播间隔 100–300 ms,扫描 5 s / 100 ms 窗口
    私有协议 v3 18 种消息类型、回执、重试、会话 ID CRC 不是认证,抓包就能读,别放敏感内容
    频道 1–16 天然的"房间"划分 同频道才互相可见,跨频道要靠公告
    三跳中继 A→B→C 转发的自组网实验 实验特性,默认关闭,需三台同版设备实测
    128×32 OLED 四行、每行约 21 字符 中文用精简字库,别指望全字库
    旋钮 + 两键 A/B 正交编码 + 按下 / 返回 都是低电平有效,必须去抖,别把半步当一圈
    WS2812 + 压电蜂鸣器 颜色 + 4 kHz 短音 灯和屏共用 GPIO4 供电;蜂鸣器差分驱动,静音是两端都 LOW
    USB HID 键盘 / 媒体键、CDC 串口投屏 遥控期间 BLE 射频要暂停,主机和从机抢同一个天线
    4 MB Flash / NVS 存草稿、好友、最高分、宠物 没有 OTA 槽,更新只能插 USB
    深睡 5 s 周期 电池供电的长期在场 扫描占空比 2%,延迟最坏一个周期

    再看两件"硬件有、固件还没用"的东西:ESP32-C6 的 802.15.4 射频(Thread / Zigbee 那一套),和 Wi-Fi 6。它们不在当前功能里,但意味着这门硬件还有没打开的门。


    A. 校园与实验室

    1. 课堂匿名表决器 ★

    讲师手里一台开"主机",学生设备当终端。广播里塞 题目号 + 选项 A/B/C/D,回执方向反过来收统计。

    • 用到的:MESH_TYPE_COLLAB(协作类型)+ 回执机制
    • 关键设计:匿名——只发选项,不发 MAC,汇总时按计数而不是按人
    • 差异点:不用连校园网、不用扫码、不用手机

    2. 工位求助灯 ★

    一台设备挂工位。旋钮选「借仪器 / 找人 / 帮忙看看代码」,广播出去,附近所有电台的 RGB 同时变色 + 短响。

    • 用到的:广播 + RGB + 蜂鸣(都是现成的)
    • 比微信群强在哪:不需要对方在看手机,抬头就能看见
    • 加一条:收到的人按一下"我过去",发送端 OLED 显示"×× 在路上"

    3. 多台同步番茄钟 ★

    自习室里几台设备同时进入 25 分钟。有人提前走,其余设备显示"少了一人"。

    • 用到的:广播校时(session_id + 时间戳)
    • 难点不是计时,是漂移:每轮开始广播一次基准时间,剩下的靠本地计数
    • 彩蛋:结束前 1 分钟蜂鸣器变成慢滴答

    4. 答辩现场提词器 + 倒计时 ★★

    PPT 遥控(已有 HID)扩展成三合一:翻页、看剩余时间、超时震动/短响提醒。

    • 用到的:HID 遥控 + 本地倒计时 + 蜂鸣
    • 顺手解决真痛点:评委说"还有 1 分钟"的时候,台上的人根本听不见
    • 注意:HID 期间电台通信暂停,别指望边遥控边收消息

    5. 设备借用登记 ★★

    "万用表谁借走了?"——旋钮选设备(示波器 / 万用表 / 逻辑分析仪 / 开发板),按一下借出;归还时再按一下。

    • 用到的:NVS 记账 + 广播同步(谁在场谁记账)
    • 好处:不依赖网络,也不需要谁去维护一张表
    • 开放问题:冲突时以谁为准?建议"最后一次操作赢",并在 OLED 上明示时间

    6. 断网应急广播 ★★

    实验室 Wi-Fi 挂了、群里刷不出去的时候,一台设备写公告、其余设备滚动显示。

    • 用到的:ANNOUNCEMENT 标志(协议里已经有)
    • 这是"半部电台"这个名字最贴切的现代用法:当所有依赖基础设施的通道都失效时,点对点广播还在

    B. 玩与社交

    7. 物理漂流瓶 ★★

    写一句话,广播给最近的一台(hop = 1,只发一次)。收到的人可以再转发一次(hop + 1),形成一条真实的投递链。

    • 用到的:MESH_HOP_MASK + 只读转发
    • 妙处:你不知道它会飘到谁手上;hop 到 3 就停,天然有"寿命"
    • 必须说明:内容不加密,别写悄悄话

    8. 桌游"发牌器 + 裁判" ★★

    谁是卧底、狼人杀这类游戏,最麻烦的是主持人发牌和数票。让一台设备当裁判:它广播你的身份,只有你能长按查看。

    • 用到的:私密信息长按查看(现在已有)+ 投票类型
    • 价值:把手机从桌面上拿走,一桌人真的面对面
    • 边界:没有密码学防作弊,坐你旁边的人拆开抓包也能看到——这是自觉游戏

    9. 四声部无声合奏 ★★

    四台设备分低音 / 中音 / 高音 / 打击,指挥用旋钮打拍。所有人都戴耳机或干脆只听蜂鸣。

    • 用到的:灯光蜂鸣合奏(已有)+ 广播校时
    • 难点:蜂鸣器只有方波,音准靠分频,同步误差要压在几十毫秒内
    • 这是最"表演性"的一条,开放日/迎新晚会上很抓人

    10. 摩斯电报局(校史展项)★★

    两个人各拿一台,一人发报、一人抄收,中间可以加"加密本"(凯撒位移、简单替换表)。配一块展板讲 1931 年那半部电台。

    • 用到的:摩斯收发 + 好友定向
    • 为什么适合展览:它有故事。观众按下的不是按钮,是 90 多年前的通信方式
    • 加个成就:连续抄收 20 组不出错,屏幕放一小段"报务员认证"

    11. 宠物"面基"联赛 ★★

    两台设备靠近交换宠物名片(拜访已有),周末在实验室摆个擂台:相扑、顶球、赛跑三局两胜,结果上墙。

    • 用到的:宠物联机(已有)+ 本地排行榜
    • 唯一要新写的是"赛事流程":报名 → 配对 → 三局 → 记分 → 下一位

    12. 匿名"今天实验室有人吗" ★

    进门按一下,出门按一下。设备广播"3 楼有人",其余设备 OLED 显示人数和最早到的人。

    • 用到的:广播 + NVS
    • 限制:只是个粗略在场感,不做考勤,别拿它算工时

    C. 工具与实验

    13. 通用 HID 宏旋钮 ★★

    把旋钮做成电脑上的实体旋钮:调音量、切窗口、撤销/重做、Figma 里改数值、剪辑软件里逐帧。

    • 用到的:现有 HID 遥控(PPT / 媒体 / 拍照三套已经跑通了)
    • 为什么值得做:这是最容易被同学带走使用的一条——不玩电台的人也会想要一个旋钮
    • 注意:键位映射要可配置,否则只能给一个人用

    14. 实验室信号热力图 ★★

    拿着设备走一圈,按位置记 RSSI,USB 导出 CSV,最后画成一张覆盖图。

    • 用到的:BLE/RSSI 扫描 + CDC 串口
    • 必须写清楚的边界:RSSI 只表示信号冷热,不给方向、不给距离。 热力图是"走出来的",不是"测出来的"
    • 用途:找实验室哪里 BLE 死角、哪个角落 Wi-Fi 弱

    15. 三跳中继的实物教具 ★★★

    三台设备摆成 A—B—C,OLED 显示每一跳的转发次数和延迟。让学生亲眼看到"为什么多一跳就慢"。

    • 用到的:实验性自组网(已有,默认关闭)
    • 教学价值:把"自组网"从名词变成三块板子之间的距离
    • 诚实:这不是标准 Bluetooth Mesh,只是个三层转发的实验

    16. 802.15.4 低功耗传感节点 ★★★

    C6 芯片里有一套 802.15.4 射频,配个 I2C 温湿度传感器,做成每 5 分钟醒一次的信标。

    • 用到的:硬件的 802.15.4 + 深睡(当前固件完全没用到前者)
    • 这是"新开一扇门"的选项,不是改几行代码
    • 对比实验很有说服力:同样一块板,BLE 广播 vs 802.15.4,谁更省电

    D. 三条"需要先突破"的方向

    这三条不是不好,是卡在现有边界外,写出来是想看看有没有人愿意一起啃:

    1. 加密私聊。协议里 mesh_crypto.c 的位置已经留好了,但现在是明文广播。要做就得先想清楚密钥怎么换——两台的设备换密钥,本身就是个可以写论文的问题。
    2. OTA。现在只能插 USB 更新,因为 2 MiB 单应用槽吃掉了两个 OTA 槽。想恢复 OTA,得在"功能密度"和"可更新性"之间重新分配 Flash。
    3. 打电话给云端。Wi-Fi + 云同步已经有骨架,"线下见面 → 线上留痕"这件事(比如线下对战后自动上传排行榜)可以做得更顺,但要注意:云排行榜是设备自报的,不是防作弊比赛。

    怎么把一条创意变成能演示的东西

    不管选中哪条,建议都走这三步(也是我读官方手册时最认同的节奏):

    1. 先做一个外设,别做一整个应用。 比如做"工位求助灯",先只做"按一下,另一台的 RGB 变红"。能跑通再谈界面。
    2. 让 OLED 说实话。 状态、错误码、收到的原始包长度,全打在屏幕上。128×32 的四行字,是你唯一的调试窗口。
    3. 先两台,再三台。 两台之间通了只证明"能发",三台才证明"能转发"。

    另外给用 AI 写代码的同学一条:把引脚和边界写成契约再让它写。GPIO4 共享电源、I2C 0x3C、蜂鸣器差分、GPIO12/13 留 USB——这些说清楚了,生成的代码才不是"看起来像"。


    最后

    上面 16 条,难度从"一个下午"到"一个学期"都有。我个人的三个心头好是:

    • #6 断网应急广播 —— 它让这个名字重新变得有意义;
    • #10 摩斯电报局 —— 它把一个装置变成一段历史;
    • #13 通用 HID 宏旋钮 —— 它能让不玩电台的人也想要一台。

    欢迎在下面补充、认领、或者直接说"这条不行,因为××"——被否掉的创意也是有用的,至少省了下一个人一周。

    补充格式建议(方便以后整理):

    【创意名】一句话说明
    【用到的】哪些引脚 / 协议类型 / 现有功能
    【最小可行版】只做哪一件事就算成功
    【难点 / 边界】我卡在哪
    

    如果哪条你觉得该先做,投个票,或者直接开一贴贴代码。


  • 从空白工程点亮一块小电台:BLUE LONG 独立硬件开发手册导读
    N niuguanchong
    博客 ESP-IDF ESP32-C6 硬件开发 上手教程

    本文是《BLUE LONG 独立硬件开发手册》的导读与提炼。原手册 23 页,面向 Windows + VS Code + ESP-IDF 5.5.4,用四个例程把一台带外壳的小电台当成开发板来用。

    先说一个前提,这是整本手册反复强调的第一句话:

    这台带外壳的小电台,本身也是一块可以编程的开发板。 但你要驱动它,不需要启动原产品那套消息、好友、菜单和 Mesh 系统——从一个全新的空白 ESP-IDF 工程开始就够了。手册的副标题写得很清楚:"从空白工程开始,写下第一行自己的程序。"


    一、为什么"新开一个工程"比自己改原系统更好

    拿到一台能跑的产品设备,很多人的第一反应是"把源码改改再烧回去"。手册选择了相反的路:

    • 原产品的源码里有一整套业务:消息、好友、训练、Mesh、菜单、分区迁移。任何一行你还没读懂的业务代码,都是你第一次点亮屏幕时的噪音。
    • 独立工程只依赖板级硬件,编译产物小、启动路径短,出错时错误来源唯一。
    • 原产品是"三槽 OTA 分区",独立工程用的是普通开发分区。混着来的结果是:独立示例的 partition-table 和原版 app 拼在一起,谁也不认谁。

    所以手册的目录结构就是一条最短路径:先在 Windows 上把工具链跑通 → 建空白工程 → 编译 → 再谈烧录 → 最后逐个点亮外设。

    注意手册自己的说法:本册没有烧录。 文中所有"上板后预期"都是需要用户自己逐项核对的预期值,不是已完成的实机记录。这个态度值得先记住,后面还会反复出现。


    二、先分清三个"版本",这是新手最容易掉的第一坑

    VS Code 是编辑器;ESP-IDF 扩展 2.3.0 是编辑器里的操作界面;ESP-IDF 5.5.4 是真正参与编译的 SDK 和工具链。

    三件东西、三个版本号,互相独立:

    东西 版本 作用
    VS Code 随官方下载 编辑器
    官方 ESP-IDF 扩展 2.3.0 提供 ESP-IDF: 开头的命令、状态栏、Build/Flash 按钮
    ESP-IDF SDK 5.5.4 真正编译的 SDK 与 RISC-V 工具链

    装了扩展 ≠ 装了 SDK ≠ 当前工程选中了那个 SDK。 手册里那条对仗很好记:"扩展 2.3.0 不等于 SDK 2.3.0"。

    正确的顺序是四步:

    1. 装 VS Code,用"打开文件夹"打开一个新建的空目录(示例 C:\BLUE_LONG_DEV)。

    2. Ctrl+Shift+X 搜 @id:espressif.esp-idf-extension,核对发布者是 Espressif Systems,再 Install。要复现手册界面,在齿轮菜单里选 Install Another Version → 2.3.0。找不到图标时优先按 F1 搜命令名,而不是照抄别人的截图位置。

    3. F1 → ESP-IDF: Open ESP-IDF Installation Manager,走 New Installation → Custom Installation 向导,把版本固定成 v5.5.4、芯片选 ESP32-C6、安装位置 C:\Espressif、勾选 IDE 集成。

      这里有个细节:不要用 Easy Installation,它是"装最新稳定版"。手册要固定 5.5.4,因为后面所有"编译通过"的结论都只对这个版本成立。国内网络可以直接用管理器自带的 Espressif 官方下载源。

    4. 回到 VS Code:F1 → ESP-IDF: Select Current ESP-IDF Version 选中 5.5.4 → ESP-IDF: Doctor Command 看诊断 → 最后在 ESP-IDF: Open ESP-IDF Terminal 里敲一句 idf.py --version 独立确认。

    第 4 步那个 idf.py --version 非常重要:Doctor 说选对了不算数,命令行能跑出 ESP-IDF v5.5.4 才算数。 如果提示找不到 idf.py,说明你开的是普通 PowerShell 而不是 ESP-IDF 专用终端——环境变量根本没加载,这时候再怎么重装 SDK 都没用。

    还有一个很具体的坑:SDK 明明装了,但"选择版本"的列表里看不到。原因通常是扩展没读到 EIM(安装管理器)的登记文件。解法是让管理器重新识别该安装;还不行就在设置里搜 idf.eimIdfJsonPath,指向本机真实存在的 eim_idf.json。不要把版本号手填成路径,也不要照抄别人的用户目录。


    三、三条容易被忽略的硬约束

    1. 路径必须是纯英文、短

    手册把开发目录固定成 C:\BLUE_LONG_DEV,并且明确写了一条实测结论:

    如果资料包解压在中文目录,先把完整 examples 文件夹复制到 C:\BLUE_LONG_DEV\examples,再从那里打开编号工程。本轮 ESP-IDF 5.5.4 在中文源码路径出现过 ccache/objdump 路径错误。

    这不是玄学。ccache 和工具链的路径处理在 Windows 上对非 ASCII 字符一直不太稳,.bat 能双击跑通,不代表官方工具链能处理同一条中文路径。能省掉的排查,就别留给运气。

    2. 芯片要选 esp32c6,不是 esp32c61

    ESP-IDF: Set Espressif Device Target 的列表里两者相邻。手册特意给了放大图,标题就是"选择第一行 esp32c6,不是 esp32c61"。

    选错的后果不是"稍微有点问题",而是整个工具链换成另一颗芯片的,后面所有错误都会是假错误。而且换 target 会重配工程,所以顺序必须是:先选 target,再写代码,最后编译。

    3. 4 MB Flash + 原生 USB 控制台

    在 SDK Configuration Editor 里两处要改:

    • Serial flasher config → Flash size → 4 MB
    • Component config → ESP System Settings → Channel for console output → USB Serial/JTAG

    第二项决定了你的日志从哪里出来。手册补了一句很关键的边界:GPIO12/13 就是原生 USB 的 D-/D+,不要拿去点灯、接按键或当调试方波用。 烧录成功但 Monitor 一片空白时,先查控制台选项和 COM 是不是同一台设备,不要因此去改 USB 引脚。


    四、第一段代码:越短越好

    空白工程创建完(ESP-IDF: Create New Empty Project,项目名 blue_long_blank,父目录 C:\BLUE_LONG_DEV),手册让它先只做一件事——打日志:

    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "esp_log.h"
    
    void app_main(void) {
        unsigned count = 0;
        while (1) {
            ESP_LOGI("hello", "Hello BLUE LONG %u", count++);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
    

    两个细节:

    • app_main 是应用入口,不是 main。
    • vTaskDelay 是把 CPU 交还给系统,不是"睡一会儿"。用死循环空转等一秒,会把空闲任务饿死,看门狗和电源管理都会出问题。

    初学阶段最容易误判的一件事:红色波浪线不等于编译失败。 先把 SDK 和 target 选对,再以 Build 输出的第一条真实错误为准。


    五、引脚速查表:这张表决定了你后面所有代码

    功能 GPIO / 关系 开发时要记住
    OLED 与 RGB 供电使能 GPIO4,高电平使能 共享电源,先拉高等 150 ms 再用
    OLED I2C SDA GPIO5、SCL GPIO6 SSD1306,128×32,7 位地址 0x3C
    WS2812 RGB GPIO7 数字单线时序,不是普通 PWM RGB
    编码器 A / B GPIO2 / GPIO3 两路交错相位,完整旋转要解码
    编码器按下 GPIO18 按下为 LOW,独立事件 + 去抖
    独立返回键 GPIO19 按下为 LOW,先处理按下沿
    压电蜂鸣器 GPIO20 / GPIO21 差分输出,静音 LOW/LOW,只做短提示
    原生 USB D- / D+ GPIO12 / GPIO13 保留给 USB,不改普通 GPIO
    GPIO0 本轮禁止使用 不配置、不采样、不套旧板 BOOT 接法

    这张表里有三个设计点值得单独说:

    ① 为什么 GPIO4 是"共享电源使能"。 OLED 和 RGB 灯珠挂在同一路开关后面。所以只往 GPIO7 灌 WS2812 数据、却没开 GPIO4,屏幕不亮、灯也不亮——这不是代码错,是没通电。手册把"先 GPIO4 拉高,等 150 ms,再初始化 I2C 和发数据"写成了固定动作,150 ms 是给电源爬升和 OLED 内部复位留的余量。

    ② 为什么蜂鸣器是差分驱动。 压电片两端接 GPIO20/21,同相 = 不振动 = 静音,反相 = 有电位差 = 发声。静音时两端都是 LOW,所以千万不要把任意一端当成固定接地——那样你只有一个推挽脚,还得额外加直流偏置。差分的好处是驱动电压翻倍、无直流偏置、音量更大。手册要求"约 80 ms、4 kHz 短提示,长按不延长",是怕一直响把蜂鸣器烧了。

    ③ 为什么 GPIO0 被划成禁区。 老 ESP32 教程里"进下载模式就 GPIO0 接地"是个条件反射,但这块板上 GPIO0 不用。手册专门写了一句:下载模式连不上时,不要套用旧 ESP32 教程把 GPIO0 接地;先查数据线、USB 驱动和端口占用。

    还有一个概念要分清,手册第 10 章专门讲了:芯片 GPIO 编号 ≠ 模组焊盘号 ≠ 现有测试点(TP)。 功能图上的彩色标签是"软件信号",不是外壳边缘新增的排针。这套图说明的是现有硬件怎么用,不是一块新开发板的设计图。


    六、四个例程:把一个系统拆成四块积木

    手册最实用的部分是 examples/ 里四个互相独立的工程——不是四个源文件,是四份各自带 CMakeLists.txt、sdkconfig.defaults 和板级组件的完整工程。不要把四份 app_main 塞进同一个 main 一起编译。

    01_serial_hello:先看到一行自己的日志

    上板预期:每秒出现 HELLO BLUE LONG count=0、count=1……

    这个例程不点亮屏幕、不亮灯、不发声。所以显示器黑屏是正常的,不是失败。 它的唯一目的是验证"改代码 → 编译 → 写入 → 看到变化"这条最短路径。建议第一步就是把欢迎语改成自己的名字,确认改动真的来自你当前的工程,而不是旧镜像。

    02_oled_hello:共享电源,然后显示文字

    流程:GPIO4 拉高 → 等 150 ms → 初始化 I2C 与 SSD1306 → 写 128×32 区域。

    上板预期四行:

    HELLO BLUE LONG
    ESP-IDF 5-5-4
    128 X 32 OLED
    YOUR OWN PROGRAM
    

    两个坑写进了手册:

    • 屏幕不亮,先查 GPIO4 和电源,再查 SDA/SCL。"看到 SDA5/SCL6 就以为自己在查 I2C"——漏掉共享供电这一步,查多久都没用。
    • I2C 地址填 0x78 是把 8 位地址写法当成了 7 位参数。按例程接口应该写 0x3C。

    另外注意字库边界:这个最小工程用的是精简字库,只支持大写英文、数字和少量符号,每行最多 21 字符。直接把一串中文丢进去,显示不出来是预期行为——中文点阵字库是另一个话题(四 MB Flash 上并不便宜)。

    03_input_counter:知道是哪个操作件被触发

    旋钮 A/B 走 GPIO2/3,读两路交错相位判断旋转方向;旋钮按下 GPIO18、独立键 GPIO19,都是低电平有效。

    上板预期:屏幕显示 INPUT COUNTER、ROT:0、KNOB:0、KEY:0;转动改 ROT,短按旋钮和按独立键各自加计数。

    典型故障与正确解法:

    现象 正确做法 错误做法
    方向反了 确认实际旋钮手感与代码的方向约定 把 A/B 电平、半步、完整卡点混成一个事件
    按一次算很多次 查按下沿检测与去抖 无限加大延时

    手册还提醒了一条硬件边界:独立键还连着硬件电源开关通路。示例只用短按验证输入,没有接管电源控制芯片;"长按关机"的行为以实板为准,软件示例不承诺改变它。

    04_rgb_buzzer:颜色变化与明确的短提示

    RGB 数据脚 GPIO7,电源仍与 OLED 共用 GPIO4。按旋钮在 OFF → RED → GREEN → BLUE 之间切换;按独立键发一次 约 80 ms、4 kHz 的短提示音,然后停止;上电默认静音。

    两个"不要误解":

    • WS2812 是单线数字时序,不是三路 PWM 的模拟 RGB 灯。颜色不对先查数据格式、时序和颜色顺序,别去改 PWM 占空比。
    • 没有声音时先核对按键事件和差分输出。把"响一下"改成"一直响"不是修复,是把蜂鸣器往死里推。

    七、全册最值得抄的一段:把硬件约束写成提示词

    第 5 章装了 Codex(@id:openai.chatgpt,发布者 OpenAI),但真正有价值的是接下来这段——把硬件事实写成一段契约,整段贴给 AI:

    这是一个新的 ESP-IDF 5.5.4、ESP32-C6、4MB Flash 项目。
    我要直接开发 BLUE LONG 硬件,不依赖原小电台业务系统。
    先读当前 CMakeLists、main 和板级代码,再说明最小实现。
    OLED 是 SSD1306 128x32,7位I2C地址0x3C。
    GPIO4 是 OLED 与 RGB 的共享电源使能,先拉高并等150ms。
    I2C SDA=GPIO5,SCL=GPIO6;WS2812数据=GPIO7。
    旋钮A/B=GPIO2/3,按下=GPIO18;独立返回键=GPIO19。
    压电蜂鸣器由GPIO20/21差分驱动,默认关闭,只短响。
    GPIO0 不使用;GPIO12/13 留给原生USB,禁止重配成普通GPIO。
    不复制聊天、好友、Mesh、旧菜单或原产品分区。
    一次只实现一个外设;循环要让出CPU,输入要去抖。
    只改本项目,说明修改文件,编译并报告真实错误。
    不要自动连接串口、烧录、擦除Flash或更改eFuse。
    输出是初版代码;编译通过后由我决定是否上板验证。
    

    这段提示词好在哪:

    1. 先给事实,再给任务。 引脚、地址、时序都是硬约束,不能让模型"看外形猜"。
    2. 划定禁区。 GPIO0 不用、GPIO12/13 不许动、不碰原产品分区——把不可逆操作显式排除。
    3. 限定节奏。 "一次只实现一个外设",避免一次生成两百行跨模块代码。
    4. 要求真实错误。 "编译并报告真实错误",而不是编一个"应该可以了"。
    5. 保留决策权。 "由我决定是否上板验证"——AI 不获得烧录权限。

    配一条使用纪律:AI 改完先读 diff,确认没有多余功能、没有错引脚,再点 Build。 要让它修错,把第一条编译错误和对应代码给它,不要只说"还是不行"。

    安全上也有两句底线:只在官方认证页登录;不要把密码、验证码、API 密钥粘进项目、提示词或截图。


    八、命令列表里的"第几行",是个真问题

    F1 弹出的命令列表里有很多长得像的命令,手册几乎每一处都标了"选第几行":

    要做的事 选这条 不要选
    完整编译 ESP-IDF: Build Your Project(首行) 只构建 bootloader / partition table 的相近命令
    选串口 ESP-IDF: Select Port to Use(第二行) Select Monitor Port to Use(只改监视器端口)
    烧录 ESP-IDF: Flash (UART) Your Project(第三行) Encrypt and Flash Your Project(加密烧录,不是本教程)
    看日志 ESP-IDF: Monitor Device(第二行) Build, Flash and Start a Monitor(会顺带编译+烧录)

    搜索结果的蓝色默认项不一定是你要的那条。以完整名称为准,别按位置背。

    烧录前手册还要求停下来核对三件事:芯片是 esp32c6、Flash 是 4 MB、当前示例和 build 输出是这一份,并确认你手上有能恢复原产品的配套工厂固件。烧录本身用构建生成的完整烧录命令与偏移,不要从别人帖子里手抄一个固定 app 偏移。

    Monitor 想退出时,常见组合是 Ctrl+]。


    九、出错以后:用证据定位,不盲目擦除

    这张表是整本手册最"老工程师"的一页:

    现象 先做什么 不要误判
    列表里找不到 5.5.4 检查 EIM 登记与当前 SDK 选择,跑 Doctor 扩展 2.3.0 不等于 SDK 2.3.0
    idf.py 找不到 重开 ESP-IDF 专用终端 普通 PowerShell 没加载环境 ≠ SDK 丢了
    构建到最后一步失败 保存第一条实质错误,查依赖与路径 只把最后一行 ninja: build stopped 交给 AI,信息不足
    只有 COM1 换数据线、换 USB 口,看设备管理器 COM1 可能是电脑自带端口,只是排在列表最前
    COM 拒绝打开 关掉占用它的监视器、网页、烧录器 重装 SDK 不能释放别人占着的串口
    串口有日志但屏幕黑 先分清 01 本来就不用 OLED;02 查 GPIO4 USB 工作不代表屏幕电源已开
    按一次算很多次 查按下沿与去抖 几十毫秒轮询不等于几十次按下
    Flash 容量或芯片异常 保留完整工具日志,核验身份和读取步骤 不要关掉检查,也不要"猜"容量
    原小电台菜单不见了 这是独立固件替换产品程序后的预期 不是"开发程序必须含原系统才能跑"

    左下角那句尤其重要:全擦 Flash 不是排查手段,是最后的手段。 每次"擦一下试试",你都在丢掉现场证据。


    十、手册对自己的边界说得很清楚

    这部分我原样转述,因为它是这份文档最可信的地方:

    • 本次没有烧录。 所有"上板后预期"都待用户核对,不是已完成的实机验收。
    • 四个独立示例确实做过真实交叉编译:ESP-IDF 5.5.4 / esp32c6,四例退出码均为 0,宿主输入逻辑自检通过;源码、镜像校验值和 build.log 都留在各自 manifest 里。但四例编译通过不等于 OLED 方向、旋钮手感、RGB 颜色和声音被验收过。
    • 截图只代表对应界面被采集过,不能证明设备执行了程序。 绿色框、放大①是后加的引导层,原始截图独立保留。
    • 功能图是学习简化图,信号关系取自现有设计,但不能代替焊接定位、维修或 PCB 制造资料;图上的彩色端口不是焊点位置。
    • 不承诺跨分区无损恢复。 想回到原产品,用与实际硬件匹配的原版完整工厂发布包和它自带的烧录入口(该入口可能全擦并恢复出厂状态);恢复后名字、好友、消息、训练状态要重新核对。
    • 官方示例图(比如 Codex 面板那张 macOS 布局)会明确标注来源,不代表本机账户已登录或硬件已运行。

    十一、把整本手册压成一条路线

    装 VS Code + 官方 ESP-IDF 扩展 2.3.0
            ↓
    EIM 自定义安装 → 固定 ESP-IDF 5.5.4 / ESP32-C6 / C:\Espressif
            ↓
    Select Current ESP-IDF Version → Doctor → idf.py --version 独立确认
            ↓
    Create New Empty Project(blue_long_blank,纯英文短路径)
            ↓
    Set Target = esp32c6 · Flash = 4MB · Console = USB Serial/JTAG
            ↓
    Build Your Project(先只在电脑上闭环)
            ↓
    挨个过 01 → 02 → 03 → 04(每例独立编译、独立 build 目录)
            ↓
    自己决定是否 Flash (UART) + Monitor Device
    

    扩展外设时,手册给的下一个练习也很"教材化":在已经能显示、能读旋钮的工程里加一个六面骰子——短按开始,约 1 秒后显示 1 到 6,返回键中止;动画不阻塞按键,不用 IMU,不加网络和计分。

    这个练习的精髓不是骰子,而是:先让四个例程各自工作,再组合。 组合时如果坏了,你能确定是新加的那部分坏了。


    写在最后

    这份手册真正在教的,其实是三件事:

    1. 把"版本"和"层"分清——编辑器、扩展、SDK、target、COM、控制台,每一层都能单独坏。
    2. 把硬件约束写成文字——引脚表、时序、禁区,写清楚给人和给 AI 都一样有用。
    3. 把"没验证"说出来——没烧录就说没烧录,编译通过就只说编译通过。

    从空白工程到点亮一块 128×32 的屏幕,中间隔着几十个可以出错的地方。手册的价值,就是把那些地方一个个标出来,让你第一次就走在正确的路上。

    原手册:BLUE LONG 独立硬件开发手册(Windows / ESP32-C6 / ESP-IDF 5.5.4 / 2026.10,共 23 页)


  • 半部电台:用 ESP32-C6 做一台“附近通信”旋钮小设备——XidianFlipper 代码阅读笔记
    N niuguanchong
    博客 ESP32-C6 ESP-IDF BLE 嵌入式

    项目地址:qilaotie/XidianFlipper | 在线社区:半部小岛

    "半部电台起家"是西电校史里最常被提起的一句话。1931 年,红军第一部电台只能收、不能发,于是被叫作"半部电台"。这个项目借了这个名字,但它并不是一台真的无线电——它是一台基于 ESP32-C6 的旋钮小设备:靠 BLE 广播在几十米内和同伴互发消息、一起玩桌游、养一只电子宠物,顺便还能当 PPT 遥控器和 Wi-Fi 扫描器。

    本文是我读这个仓库源码后的笔记,重点放在它是怎么搭起来的,以及那些只有在真机上才会踩到的坑。


    一、硬件与工程基础

    项目 配置
    主控 ESP32-C6,4 MiB Flash
    屏幕 128×32 SSD1306 OLED(I2C,地址 0x78)
    交互 EC06 旋转编码器 + 独立按键 BACK
    声光 MCPWM 蜂鸣器、RMT 驱动 WS2812
    电源 GPIO4 集中管理负载开关 + ADC 电量检测
    工具链 ESP-IDF 5.5.4,CMake 工程

    工程按 firmware/(业务)与 components/(第三方与公共组件)两大块切分,业务目录再分为 app / config / drivers / protocol / radio / system / ui:

    firmware/
    ├── app/        # 消息、好友、Wi-Fi、无线工具、摩斯训练
    ├── config/     # constants.h / pins.h / defaults.h / log_config.h
    ├── drivers/    # ec06 编码器、rgb_led、rmt_ws2812、mcpwm_buzzer、adc_battery...
    ├── protocol/   # mesh_packet.c、mesh_crypto.c
    ├── radio/      # ble_radio.c、tool_hid.c
    ├── system/     # nvs_config、log_manager、power_mgmt、event_dispatcher
    └── ui/         # menu_pages、local_pages、party_pages、pet_page、dev_mode...
    components/
    ├── u8g2/                  # 图形库(含字模)
    ├── u8g2-hal-esp-idf/      # I2C bit-bang 回调
    └── oled_mirror/           # 把屏幕画面经 USB CDC 投到电脑
    

    初始化顺序是这份代码里最值得抄的部分

    firmware_init_all() 里每一步都有注释说明"为什么必须在这里",这不是装饰,是血泪:

    event_init();                 /* 1. 任何任务通信之前 */
    load_switch_init();           /* 1.5. GPIO4 总电源,任何外设之前 */
    log_manager_init();           /* 2.5. 事件之后、其他模块之前 */
    buzzer_init();  haptic_init();
    nvs_config_init();            /* 5. NVS 必须在 rgb_led 之前:
                                         否则 g_config 全零 → 亮度 0% */
    rgb_init();  rgb_led_init();
    ec06_init(&ec06_cfg);         /* 7. 编码器 ISR + 任务 */
    ...
    nvs_init();  ui_init();       /* OLED 提前亮,消除上电黑屏 */
    u8g2_Setup_ssd1306_i2c_128x32_univision_f(...);
    mesh_crypto_init();           /* 9. 加密必须在无线之前就绪 */
    ble_radio_init(mesh_notify_dispatch, NULL);  /* 10. NimBLE 主机任务 */
    quick_msg_init();  mesh_notify_init();
    

    几个细节:

    • 负载开关最先初始化。整块外设供电挂在 GPIO4 上,晚一步就是莫名其妙的 I2C 失败。
    • NVS 早于 RGB。配置从 Flash 读出来之前,结构体是零值,亮度按 0% 处理,用户看到的就是"灯不亮"。
    • OLED 抢先于 BLE。NimBLE 初始化会占用一截时间,先把屏幕点亮,用户感知到的开机时间就短了。
    • BLE 的致命错误有兜底:读 eFuse MAC 失败或设 BLE 地址失败时,红灯快闪 10 次、屏幕上画 FATAL ERR 0x01/0x02,然后死循环等看门狗。宁可停住,也不带着半残的协议栈跑。

    冷启动还有一段"开机图 2 秒 + 黑屏 1 秒"的过渡,而从 DeepSleep 按键唤醒时会跳过这段直接进 UI——g_wake_reason 判断一下就行,成本极低,体验差别很大。


    二、协议层:27 字节头 + 128 字节载荷

    firmware/protocol/mesh_packet.h 定义了整套私有协议 v3,线格式非常克制:

    #define MESH_MAGIC        0x4D45   /* 'M','E' */
    #define MESH_VERSION      3
    #define MESH_HEADER_SIZE  27
    #define MESH_PAYLOAD_MAX  128
    #define MESH_CRC_SIZE     2
    
    typedef struct {
        uint16_t magic;
        uint8_t  version;
        uint8_t  src_mac[6], dst_mac[6];   /* 用 MAC 直接寻址 */
        uint8_t  type, len, flags, channel;/* channel: 1~16 */
        uint32_t session_id, msg_id;       /* 会话 + 消息序号,做回执去重 */
        uint8_t  payload[MESH_PAYLOAD_MAX];
        uint16_t crc16;
    } mesh_packet_t;
    

    打包后最大 27 + 128 + 2 = 157 字节——刚好塞进 BLE 的传统广播/扩展广播里,不需要建连接。几个设计取舍:

    1. 用 MAC 当身份。src_mac/dst_mac 六字节,广播地址全 FF。好处是零配置、无路由表;代价是换设备就换身份,好友关系必须落 NVS(namespace = "mesh_cfg")。
    2. flags 一个字节塞了四件事:ACK_REQUEST、ROUTED、ANNOUNCEMENT、CUSTODY,再加两位跳数(MESH_HOP_MASK 0x0c,MESH_TOTAL_HOPS_MAX 3)。协议从"能通"进化到"能转发、能代存",头长度一字节没变。
    3. session_id + msg_id 撑起了回执与重试。发送状态机(已发 / 已收 / 超时)全靠这两个字段,MESH_TYPE_RECEIPT 就是回执报文。
    4. 18 种消息类型共享同一条管线:快捷消息、摩斯、好友请求、信标、回执、石头剪刀布、寻宝、反应赛、数字炸弹、宠物、协作、社交……加新玩法基本只是往枚举里加一个 MESH_TYPE_*。

    最值得称赞的是头文件第一行注释:

    /* BLE local messaging v3. Wire integers are little endian; CRC is not authentication. */

    CRC 不是认证。 这句话省掉了很多误解:这不是加密私聊,抓包就能读;游戏里也没有密码学防作弊。项目在 README、功能说明、工具说明里反复重申这一点——工程文档里肯把边界写清楚,比多堆十个功能更难得。


    三、通信载体:广播式"对讲",以及功耗的账

    设备之间不建 BLE 连接,全靠扫描广播收发。constants.h 里这几个数字决定了续航:

    #define SCAN_PERIOD_MS   5000   /* 扫描周期 5s */
    #define SCAN_WINDOW_MS   100    /* 扫描窗口 100ms → 2% 占空比 */
    #define COVER_ADV_MS     6000   /* 覆盖广播 6s ≥ 扫描周期 5s */
    #define BLE_ADV_INTERVAL_MIN_MS 100
    #define BLE_ADV_INTERVAL_MAX_MS 300
    
    • 扫描占空比只有 2%,所以平时几乎不耗电;代价是延迟——最坏要等一个扫描周期才收到消息。
    • COVER_ADV_MS > SCAN_PERIOD_MS 这条不等式是整个"对讲感"的关键:发送方要保证自己广播的持续时间覆盖住对方一整个扫描周期,否则就会出现"我明明发了对方没收到"的经典 bug。
    • DeepSleep 周期 5 秒,冷启动后留 15 秒宽限期禁止休眠——不然 USB 还没枚举完设备就睡了,串口工具上永远看不到设备。

    这套机制的能力边界也因此很明确:不需要路由器、SIM 卡或手机,但它也不是运营商短信,不是标准 Bluetooth Mesh。三跳中继是实验特性,默认关闭、重启不保留,要三台同版设备才能实测 A→B→C。


    四、界面:128×32 像素怎么装下一个系统

    屏幕只有 128×32,四行文字。项目直接移植了 WouoUI 的菜单框架(ui.layer / ui.state / ui.select[] / ui.fade),配合 u8g2 渲染。

    在这个尺寸上做 60 多个功能入口,靠的是三件事:

    • 分层菜单:主菜单按"消息 → 摩斯电台 → 学习 → 好友 → 趣玩 → 工具 → 设置 → 关于"排列,长描述走滚动。
    • 三套皮肤:经典像素、极简线框、终端,设置里切换、重启保留。
    • 中英双语开关:主菜单、设置、工具、趣玩全部双语,即时生效。中文用的是精简字库——128×32 的屏幕上,全量 CJK 点阵字模对 4 MiB Flash 来说并不划算。

    一个小而妙的组件:OLED Mirror

    components/oled_mirror 把每一帧画面通过 USB Serial/JTAG 发给电脑:

    usb_serial_jtag_driver_config_t usj_cfg = {
        .tx_buffer_size = 4096,   /* 整帧/日志/控制帧不被截断 */
        .rx_buffer_size = 256,
    };
    oled_mirror_begin(&u8g2, usb_cdc_send_callback);
    

    一帧 128×32/8 = 512 字节点阵,加 5 字节帧头正好 517 字节,所以 TX buffer 必须给到 4096 且写入超时只有 10 ms(USB 没插时静默丢弃,绝不阻塞渲染)。更妙的是它顺手 esp_log_set_vprintf() 接管了日志,让 ESP_LOGI 和画面走同一套帧格式——演示、答辩、录屏时不用举着放大镜看 128×32 的小屏。这个组件还单独做了 ENABLE_OLED_MIRROR 编译开关,不影响正式构建。


    五、功能盘点到什么程度

    不逐条罗列,只看"密度":

    • MESSAGES:快捷短语 10 条(单条上限 48 字符,见 QUICK_MESSAGE_MAX_LEN)、机身 ASCII 编辑、字符表情、六槽持久草稿箱、频道(1–16)、好友定向、收件箱与发送状态。
    • 摩斯:实时收发、自由练习、听音选字、跟练、听写。所有时序阈值都随 WPM 动态计算(morse_engine_set_wpm()),只保留固定值:20 ms 消抖、±30% 教学容差、600–900 ms 字母间隔、1500 ms 空闲自动发送、5000 ms TX 回 RX。
    • FUN 14 个入口:宠物、竖屏俄罗斯方块、贪吃蛇、答案之书、骰子、花旗骰、附近石头剪刀布、寻宝雷达、反应赛、数字炸弹、1–10 秒盲计时、玩法说明、灯光蜂鸣合奏、旅行护照。
    • 多人桌游 10 款:UNO、谁是卧底、达芬奇密码、骗子酒馆、情书、快艇骰子、阿瓦隆、一夜狼、狼人杀、井字棋。统一"创建 → 图形准备房间 → 开局进牌桌 → 结算回原房间重新准备"的流程,还支持多桌大厅、只读观战、邀请。
    • 宠物:四属性(饱食/心情/精力/清洁)、四阶段成长、三成年分支、七个内部小游戏、金币商店、背包装饰图鉴、双机拜访与对战、房间皮肤。没有死亡设定,喂食清洁睡觉全免费。
    • TOOLS 11 项:PPT/媒体/拍照 HID 遥控、Wi-Fi 连接、云同步、Wi-Fi 扫描、BLE/RSSI 扫描、内存状态、实验性自组网、网络诊断、队伍与社交。

    注意 HID 遥控期间电台通信会暂停——BLE 主机和外设角色抢同一套射频资源,这是硬约束,写在了手册里。


    六、最硬的一仗:分区迁移

    这是整个项目里我最想单独讲的部分,因为它是不可逆操作。

    原版固件的分区是老三槽布局,单个应用槽只有 1,245,184 字节。应用从 768,016 字节一路长到 1,527,808(当前发布包 1,739,152),三槽布局再也装不下:

    指标 冻结原版 迁移后
    单应用槽 1,245,184 B 2,097,152 B(2 MiB)
    应用镜像 768,016 B 1,739,152 B
    分区方案 旧三槽 + OTA factory-2m-usb-v1,取消两个 OTA 槽
    更新方式 OTA / USB 仅 USB

    关键约束是两处 NVS 的地址和大小绝对不能动:

    • nvs:0x9000 / 0x6000
    • nvs_sec:0x3b0000 / 0x6000

    因为它们存着 NVS v7 配置、storage ABI 1 的 UI 参数、宠物数据、游戏最高分和好友列表。工程里 docs/partition_migration.md 和 AGENTS.md 把流程钉死成几条:迁移前必须双读校验整片 Flash 备份 → 迁移工具必须验证设备身份、旧布局和备份 → 不能只刷分区表 → 完成后整片回读确认未授权区域没被写。

    结果也记录得很实在:COM9、COM10、COM15 三台设备分别完成双读整片备份、2 MiB 迁移和完整回读,确认 bootloader 未替换(COM15 因旧 bootloader 不同另行批准更新)、两处 NVS 及其他未授权区域不变。

    代价换取:没有 OTA 了。这很痛,但 factory 0x20000 / 0x200000 的单槽方案让应用可用空间从 1.2 MiB 涨到 2 MiB,功能密度才成为可能。工程在 README 里明确写了"迁移后仅支持 USB 更新,不支持 OTA",没有含糊。


    七、工程习惯:把"没验证"写进文档

    这份仓库最不像"学生作业"的地方,是它对自己的验收口径极其苛刻:

    • 构建产物带指纹:输出到 build/release/,包含 manifest.json、镜像、源码记录、validation/build.log 和 SHA-256,python tools/verify.py 独立核验。README 直接给应用哈希 21c39ff9...a916f3,不靠"我记得我编过"。
    • 模拟与实机分开报告:AGENTS.md 里那句"宿主模拟测试和实机验收分开报告;不得把模拟帧率、断电或回滚结果表述为实机通过",是很多项目缺的一条纪律。发布清单里 hardware_tested: false 一直保留着,哪怕已经上机测过一部分。
    • 能力边界逐条列出:RSSI 只表示信号冷热、不给方向距离;拿到 IPv4 不等于能上网;KEY SENT 不等于真的拍了照;云分享关闭不等于撤下,必须执行 REMOVE ONLINE。
    • 版本号不自作主张:扩展版固件字符串仍是 1.0.0-noautosleep,靠发行清单和 SHA-256 区分构建,明确"不把本扩展版误称为 V1.5"。

    顺带一个工程上的小坑:components/u8g2/csrc/u8g2_fonts.c 有 40 MB 源码,几万个字模。ESP-IDF 默认 -ffunction-sections -fdata-sections + 链接期 --gc-sections 会丢掉没引用的段,所以最终镜像不会爆炸,但编译时间和仓库体积是真的贵——这也是它把完整 u8g2 直接 vendor 进来要付的账。


    八、它不是什么

    作者写得很清楚,我照抄一遍,因为这几句比功能列表更有价值:

    • 没有 IR、NFC/RFID、Sub-GHz,不是完整 Flipper Zero 替代品;
    • 消息不是加密私聊,游戏没有密码学防作弊;
    • Wi-Fi 凭据未启用 NVS 加密,不要输入真实敏感信息;
    • 不是运营商短信,不是标准 Bluetooth Mesh,也不是互联网电台;
    • 云排行榜是设备自报的,不是防作弊比赛。

    一台 4 MiB Flash、128×32 屏幕、靠一颗旋钮操作的小设备,做到"附近能聊、能一起玩十款桌游、能养宠物、能当遥控器",靠的不是堆料,而是把每一字节的协议头、每一次扫描占空比、每一段 NVS 地址都算清楚。


    九、可以带走的三条经验

    1. 初始化顺序就是需求。事件系统、电源开关、NVS、屏幕、协议栈,谁在谁前面都有理由;写成注释,下一个人(或三个月后的你)会感谢自己。
    2. 协议头要预留成长空间。v3 的 27 字节头从"点对点消息"长到"三跳中继 + 代存 + 回执",头长度一次没变,全靠 flags 里的两位跳数和四种标记。前期省一点,后期就能改。
    3. 不可逆操作要有备份和验收清单。分区迁移那套"双读备份 → 验证身份/旧布局 → 只改授权区域 → 整片回读比对",比任何功能都更像一个真正的工程项目。

    如果对"半部电台"感兴趣,仓库里的 docs/ 有完整手册:功能简介、使用手册、宠物手册、桌游适配、分区迁移、发布与构建。也可以去半部小岛看看设备自报的排行榜和宠物展示柜。

    半部电台起家,靠的从来不是设备多好,而是有人愿意把能收的那一半,慢慢做成能发的那一半。


  • 半部电台的创意设计
    N niuguanchong
    综合讨论

    欢迎各位同学来进行补充!

  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组