
1. 拆解 Chouchin-CH899 这个项目到底在做什么Chouchin-CH899 这个名字听起来像某个小众硬件型号实际上它是一台 Wi-Fi 时钟的固件改进项目。原厂固件功能比较基础联网校时、显示时间、偶尔同步一下天气基本就这些。我拿到手之后发现几个明显的问题断网之后时间会慢慢漂移重新联网的恢复逻辑很笨偶尔还会卡死在配网界面。所以这个项目的核心目标很明确——在保留原有硬件架构的前提下把固件从头梳理一遍让它变成一个真正稳定、可长期运行的 Wi-Fi 时钟。这个项目适合谁看如果你手上有类似的 Wi-Fi 时钟产品或者你正在用 HC32L130 这类低功耗 MCU 做物联网小设备再或者你对 TXW813 这种 Wi-Fi 模组的固件开发感兴趣那这篇内容应该能给你不少参考。整个改进过程涉及硬件分析、固件架构重新设计、网络状态机重写、低功耗优化这几个大块我会尽量把每个环节的思考过程和实操细节都讲清楚。先说一下硬件底子。Chouchin-CH899 的主控是 HC32L130这是华大半导体的一款 Cortex-M0 内核 MCU主频 48MHzFlash 64KBRAM 8KB。这个配置放在今天看确实不算富裕但对于一个时钟来说够用了。Wi-Fi 部分用的是 TXW813 模组支持 2.4GHz 频段通过 UART 和主控通信。显示是一块 4 位共阳数码管带冒号分隔另外还有几个状态指示灯。整机供电是 5V DC 输入内部有一颗 LDO 降到 3.3V 给 MCU 和 Wi-Fi 模组供电。原厂固件的问题根源在于架构太简单。它用一个超级循环super loop把所有事情串在一起初始化、连 Wi-Fi、NTP 校时、刷新显示、处理按键全部在一个 while(1) 里面顺序执行。这种写法在小项目里能跑但一旦网络出现异常整个循环就会被阻塞显示刷新也会跟着卡住。更麻烦的是原厂没有做任何时间保持机制一旦断网RTC 就走不准重新联网后又要等很久才能校准。我决定重写固件的时候给自己定了几个硬指标第一断网后依靠内部 RTC 至少能保持一周误差不超过 10 秒第二网络恢复后 30 秒内完成校时第三配网流程要简化最好能做到上电自动重连失败才进配网模式第四整机功耗要控制住不能因为 Wi-Fi 常连导致发热明显。这几个指标后面会逐一展开怎么实现。注意HC32L130 的 Flash 只有 64KB写代码的时候要时刻关注空间占用。我一开始没注意加了个 OTA 模块之后直接爆了后来砍掉了很多冗余逻辑才压回来。2. 固件架构重新设计与核心模块拆解2.1 为什么放弃超级循环改用时间片轮询原厂的超级循环最大的问题是阻塞。比如 Wi-Fi 连接函数里面有个 while 循环等握手如果路由器没响应它就一直在那儿等显示刷新和按键扫描全部停摆。我改成时间片轮询之后每个任务按固定周期执行互不阻塞。具体做法是用 SysTick 做一个 1ms 的系统滴答然后维护几个软件定时器分别给显示刷新5ms、按键扫描10ms、Wi-Fi 状态机100ms、时间同步1000ms这些任务分配时间片。这种架构的好处是响应快、逻辑清晰。显示刷新永远不会被网络操作卡住按键也能及时响应。代价是需要仔细管理每个任务的执行时间不能让某个任务占用太长时间片。我实测下来HC32L130 在 48MHz 下跑这些任务绰绰有余CPU 占用率大概在 15% 左右。2.2 Wi-Fi 状态机的设计思路TXW813 模组本身提供了一套 AT 指令集原厂固件就是简单粗暴地发指令、等回复没有状态管理。我重新设计了一个五状态的状态机IDLE、CONNECTING、CONNECTED、DISCONNECTED、RECONNECTING。每个状态有明确的进入条件、退出条件和超时处理。举个例子上电后状态机从 IDLE 开始先读取 Flash 里保存的 SSID 和密码如果有就进入 CONNECTING发送连接指令后启动一个 15 秒的超时定时器。如果 15 秒内收到 CONNECTED 事件就转到 CONNECTED 状态开始 NTP 校时。如果超时或者收到错误码就转到 DISCONNECTED然后根据重试次数决定是继续重连还是进入配网模式。这个状态机的好处是逻辑清晰不会出现原厂那种“卡在某个 while 循环里出不来”的情况。而且每个状态的超时时间都可以独立调整方便根据实际网络环境做优化。2.3 时间保持与 RTC 校准策略HC32L130 内部有一个 RTC 模块但精度一般常温下大概每天误差在 2-3 秒左右。对于时钟来说这个精度不够所以我做了两级校准。第一级是 NTP 校时联网后从 NTP 服务器获取标准时间然后计算本地 RTC 的偏差把这个偏差值保存到 Flash 里。第二级是温度补偿HC32L130 内部有温度传感器我每隔一小时读一次温度根据温度查表修正 RTC 的走时速率。具体实现上我在 Flash 里开辟了一个小区域专门存校准参数包括上次 NTP 校时的时间戳、RTC 偏差值、温度补偿系数。每次上电后先加载这些参数然后 RTC 就按照补偿后的速率走。实测下来断网一周误差能控制在 5 秒以内比原厂好太多了。2.4 显示刷新与按键处理的细节显示部分用的是 4 位共阳数码管通过 HC32L130 的 GPIO 直接驱动段选和位选都是普通 IO。原厂用的是定时器中断刷新但中断频率设得太高导致 CPU 负载偏大。我改成 5ms 刷新一位四位轮流点亮利用人眼视觉暂留形成稳定显示。这样中断频率降到 200HzCPU 负担小了很多。按键处理我加了消抖和长按检测。短按切换显示模式时间/日期/温度长按 3 秒进入配网模式。消抖用软件计数实现连续 3 次采样一致才认为是有效按键。长按检测用一个计数器每 10ms 加一达到 300 就触发长按事件。提示数码管的限流电阻一定要算好。我一开始用 220Ω亮度够了但电流偏大后来换成 470Ω亮度稍微降了一点但整机功耗下来了长时间运行也更稳定。3. 实操过程与关键环节实现3.1 开发环境搭建与工具链配置我用的开发环境是 Keil MDK 5.38配合 HC32L130 的官方器件支持包。调试器用的是 J-Link OB便宜好用。TXW813 模组的固件不需要自己烧它出厂就带 AT 指令固件我们只需要通过 UART 发指令就行。工具链配置有几个坑要注意。第一HC32L130 的 Flash 算法要选对官方包里有对应的 FLM 文件选错了会烧不进去。第二调试接口默认是 SWD但原厂固件可能把 SWD 引脚复用了第一次烧录的时候需要按住复位键再点下载或者用串口 ISP 模式擦除全片。第三串口波特率我设的是 115200和 TXW813 通信没问题但要注意电平匹配HC32L130 是 3.3VTXW813 也是 3.3V直接连就行。代码管理我用 Git虽然是个小项目但版本控制还是很有必要。每次改完一个功能就提交一次方便回滚。编译出来的 hex 文件我会用脚本自动加上版本号和日期烧录的时候一眼就能看出是哪个版本。3.2 Wi-Fi 配网流程的简化实现原厂的配网流程是上电后如果没连上 Wi-Fi就进入 AP 模式手机连上之后打开一个网页配置。这个流程本身没问题但原厂实现得太粗糙网页加载慢配置保存也经常失败。我简化后的流程是这样的上电后先尝试用上次保存的 SSID 和密码连接超时 15 秒。如果失败再尝试一次再失败才进入 AP 模式。进入 AP 模式后TXW813 会广播一个热点我用手机连上去访问 192.168.4.1页面上只有两个输入框SSID 和密码和一个保存按钮。保存后模组自动重启重新连接。这个流程的关键在于 AP 模式下的网页要尽量轻量。我用了一个极简的 HTML 页面总共不到 2KB加载速度很快。配置保存用 POST 请求模组收到后写入 Flash然后重启。实测下来从进入 AP 模式到配置完成整个过程不超过 30 秒。3.3 NTP 校时与时间同步的完整实现NTP 校时我用的是一种简化实现不依赖完整的 NTP 库直接发 UDP 包到 pool.ntp.org 的 123 端口。发送的包是 48 字节的标准 NTP 请求格式收到回复后解析出时间戳然后换算成本地时间。具体步骤是这样的首先构造 NTP 请求包第一个字节设为 0x1BLI0, VN3, Mode3其余字节填零。然后通过 TXW813 的 UDP 透传功能发出去。收到回复后从第 40 字节开始取 4 字节的 Transmit Timestamp这是自 1900 年 1 月 1 日以来的秒数。减去 2208988800 得到 Unix 时间戳再加上时区偏移东八区加 28800 秒就是本地时间。校时完成后我会计算本地 RTC 和 NTP 时间的差值把这个差值保存到 Flash 里。下次上电时RTC 从保存的时间开始走再加上这个差值补偿就能得到一个比较准确的时间。注意NTP 请求的超时时间不要设太短我一开始设 3 秒结果经常超时。后来改成 8 秒成功率就上去了。另外NTP 服务器最好用域名而不是 IP因为 IP 可能会变。3.4 低功耗优化与实测数据低功耗这块我做了几个优化。第一Wi-Fi 模组在不通信的时候进入省电模式通过 AT 指令控制。第二MCU 在空闲的时候进入 Sleep 模式靠 SysTick 中断唤醒。第三数码管刷新频率从 200Hz 降到 100Hz亮度稍微降了一点但功耗明显下降。实测数据原厂固件整机功耗大概在 1.2W 左右优化后降到 0.8W。别小看这 0.4W对于一个 7x24 小时运行的设备来说一年下来能省不少电。而且功耗降低之后整机温度也下来了原来摸上去有点温现在基本是凉的。这里有个细节要注意HC32L130 进入 Sleep 模式后GPIO 的状态会保持但如果你有外部上拉电阻可能会有漏电流。我检查了一遍原理图把不必要的上拉都去掉了只保留了 I2C 和 UART 必须的那几个。4. 常见问题与排查技巧实录4.1 Wi-Fi 连接不稳定怎么办这是最常见的问题表现是设备偶尔掉线或者连上了但很快又断开。排查思路是这样的先看信号强度TXW813 的 AT 指令可以查询 RSSI如果低于 -75dBm说明信号太弱需要考虑换个位置或者加个天线。如果信号强度没问题再看路由器设置有些路由器开启了 AP 隔离或者 MAC 过滤会导致设备连不上。我遇到过一次比较诡异的情况设备在实验室连得好好的拿到客厅就连不上。后来发现是客厅的路由器开了 5GHz 优先而 TXW813 只支持 2.4GHz。把路由器的 2.4GHz 和 5GHz 分开设置之后就好了。还有一个坑是 DHCP 租期。有些路由器默认租期很短比如 1 小时租期到了之后设备需要重新续约如果续约失败就会掉线。我后来在固件里加了静态 IP 的选项如果用户不想用 DHCP可以手动设置 IP这样就稳定多了。4.2 时间走不准的排查方法时间走不准通常有两个原因RTC 本身精度不够或者校准参数没生效。排查的时候先看 RTC 是否在走用调试器读一下 RTC 的计数器寄存器如果数值在变说明 RTC 在工作。然后看校准参数是否加载成功在 Flash 里读一下保存的偏差值如果全是 0xFF说明没写入成功。我遇到过一次校准参数写入失败的情况原因是 Flash 写操作没有对齐。HC32L130 的 Flash 写入要求按字4 字节对齐我一开始按字节写结果写进去的数据全是乱的。后来改成按字写入问题就解决了。另外温度补偿的效果和温度传感器的精度有关。HC32L130 内部温度传感器精度大概是 ±2°C对于 RTC 补偿来说够用了。但如果你发现补偿后反而更不准可能是补偿系数符号搞反了正温度系数和负温度系数要分清楚。4.3 显示闪烁或缺划怎么处理显示问题一般出在硬件上但固件也有优化的空间。如果是个别段缺划先检查对应的 GPIO 是否配置正确有没有被其他功能复用。如果是整体闪烁可能是刷新频率太低或者中断优先级设置有问题。我遇到过一种情况显示偶尔会闪一下特别是 Wi-Fi 通信的时候。后来发现是 Wi-Fi 模组的 UART 中断优先级比显示刷新中断高导致显示刷新被延迟。把显示刷新的中断优先级调到最高之后问题就消失了。还有一个细节是数码管的驱动电流。如果限流电阻太小段电流太大会导致 MCU 的 GPIO 压降显示会变暗。如果限流电阻太大亮度又不够。我试了几个值最后选了 470Ω在亮度和功耗之间取了个平衡。4.4 固件升级与版本管理虽然这个项目不涉及 OTA但固件版本管理还是很重要的。我在 Flash 的末尾留了一个区域专门存版本信息包括版本号、编译日期、Git 提交哈希。每次上电的时候如果检测到某个按键被按住就进入版本显示模式把版本信息滚动显示在数码管上。这样做的好处是当你手上有多个设备的时候一眼就能看出哪个是哪个版本不用拆机看芯片。而且如果发现某个版本有问题也能快速定位。提示Flash 末尾的区域要算好地址不要和程序空间重叠。HC32L130 的 Flash 是 64KB我一般把程序限制在 60KB 以内剩下的 4KB 用来存参数和版本信息。4.5 常见问题速查表问题现象可能原因排查方法解决方案Wi-Fi 连不上信号弱、密码错、路由器限制查 RSSI、确认密码、检查路由器设置调整位置、重新配网、关闭 AP 隔离时间走不准RTC 精度差、校准未生效读 RTC 寄存器、检查 Flash 参数重新校时、检查写入对齐显示闪烁刷新频率低、中断优先级冲突示波器看刷新波形、检查中断配置提高刷新频率、调整中断优先级按键不灵敏消抖参数不合适、GPIO 配置错示波器看按键波形、检查 GPIO 模式调整消抖计数、改为上拉输入功耗偏高Wi-Fi 未省电、GPIO 漏电测整机电流、检查上拉电阻开启 Wi-Fi 省电、去掉多余上拉配网失败AP 模式未启动、网页加载失败看模组指示灯、手机能否搜到热点检查模组供电、简化网页这个表是我在实际调试中慢慢积累的基本上覆盖了 90% 以上的常见问题。每次遇到新问题我都会往表里加一行时间长了就成了一本自己的排查手册。5. 一些实操心得和后续可扩展的方向这个项目做下来我最大的体会是小设备固件开发稳定性比功能数量重要得多。原厂固件功能其实不少但稳定性差用户体验就很糟糕。我重写之后功能没有增加甚至砍掉了一些不常用的但稳定性上来了用起来就舒服很多。另一个心得是关于调试手段的。串口打印是最简单也最有效的调试方式我在固件里保留了一个调试串口可以通过 AT 指令开关日志输出。平时关掉出问题的时候打开能看到状态机的切换、NTP 的校时结果、按键的事件排查问题效率很高。后续如果还想继续折腾有几个方向可以扩展。一是加一个简单的天气显示功能通过 HTTP 请求获取天气数据在数码管上轮流显示温度和天气图标。二是做 OTA 升级虽然 Flash 空间紧张但如果把程序优化一下腾出 8KB 做双区备份还是有可能的。三是加一个锂电池备份断电之后 RTC 继续走再来电就不用重新校时了。不过这些都是后话当前这个版本我已经用了几个月每天 24 小时开着没出过什么问题。对于一个 Wi-Fi 时钟来说能做到“忘了它的存在”就算是成功了。