ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于HC32L130与TXW813的Wi-Fi时钟固件改造:RTC守时与低功耗设计

基于HC32L130与TXW813的Wi-Fi时钟固件改造:RTC守时与低功耗设计 1. 拆解 Chouchin-CH899 固件改造的核心命题1.1 这个项目到底在折腾什么Chouchin-CH899 是一台 Wi-Fi 时钟原厂固件能用但用久了你会发现几个让人难受的点对时逻辑粗糙、断网之后时间漂移、界面刷新有肉眼可见的撕裂感而且几乎没有任何可配置空间。所谓 “Improved Wi-Fi Clock Firmware”本质上就是把这台时钟的主控固件重写或大幅改造让它在网络对时、显示刷新、低功耗管理这三个维度上表现得更像一个“正经产品”而不是一个能亮就行的玩具。这个项目的核心关键词是 Chouchin-CH899、Wi-Fi、Firmware、HC32L130、TXW813。把这几个词拆开看信息量其实很大。HC32L130 是一颗基于 ARM Cortex-M0 的低功耗 MCU主打的就是电池供电场景下的长时间待机TXW813 则是一颗 Wi-Fi 收发芯片负责联网对时这条链路。也就是说这台时钟的硬件底子是“低功耗 MCU 独立 Wi-Fi 模块”的组合而不是那种把 Wi-Fi 集成进主控的 SoC 方案。这个硬件结构直接决定了固件改造的思路MCU 负责显示、计时、电源管理Wi-Fi 芯片负责联网两者之间通过串口或 SPI 通信固件要做的事情就是把这套协作关系理顺。适合看这篇内容的人有三类。第一类是手里正好有这台时钟、想自己刷固件折腾的玩家第二类是在做类似低功耗联网设备、想参考对时和电源管理思路的嵌入式开发者第三类是对 HC32L130 或 TXW813 这类器件感兴趣、想看看真实项目里怎么用的人。不管你属于哪一类下面这些内容都是从实际改造角度出发的不是 datasheet 的复读。1.2 为什么原厂固件让人想重写原厂固件的问题不是“不能用”而是“用着别扭”。我把它归纳成四个典型症状这四个症状也正好对应了改造的四个方向。第一个症状是对时策略太粗暴。很多原厂 Wi-Fi 时钟的做法是开机连网对一次时间然后就不管了。结果就是设备运行几天之后晶振的温漂和老化累积起来时间可能偏了几秒甚至十几秒。对于看时间的设备来说这个误差是能感知的。改进方向是引入周期性对时比如每 6 小时或每 24 小时重新同步一次同时用 RTC 做本地守时。第二个症状是断网即失准。Wi-Fi 断了之后如果固件没有做好本地时钟的兜底时间就会停或者乱跳。改进方向是让 RTC 独立运行Wi-Fi 只负责“校准”而不是“驱动”时间显示。第三个症状是刷新撕裂。段码屏或者点阵屏在刷新时如果和计时逻辑耦合得太紧会出现某一位数字闪一下或者半亮的情况。改进方向是把显示刷新和计时解耦用定时器驱动刷新主循环只更新显示缓冲区。第四个症状是功耗失控。HC32L130 本身是低功耗器件但如果固件里该睡的时候不睡、Wi-Fi 模块一直保持连接电池续航会很难看。改进方向是让 Wi-Fi 模块按需上电对时完成后进入深度睡眠。把这四个症状想清楚固件改造的骨架就出来了RTC 守时 周期对时 解耦刷新 按需联网。后面所有章节都是围绕这四件事展开的。1.3 硬件底子决定了软件天花板在动手写代码之前必须先把硬件关系摸清楚否则你写的固件会和硬件打架。Chouchin-CH899 这套方案里HC32L130 和 TXW813 是两个独立器件这一点非常关键。HC32L130 的资源大概是这样Cortex-M0 内核主频几十 MHz 级别Flash 和 RAM 都比较紧凑外设方面有 RTC、多个定时器、UART、SPI、ADC 等。它的强项是低功耗深度睡眠电流可以做到微安级别。TXW813 是 Wi-Fi 收发芯片通常通过 UART 或 SPI 和主控通信支持 station 模式连接路由器内部有自己的协议栈。这种“双芯片”结构带来的第一个约束是通信带宽有限。你不能指望像 ESP32 那样在主控里跑一个完整的 TCP/IP 栈再配个 HTTP 客户端对时数据的获取要走 AT 指令或者厂商私有协议数据量要尽量小。第二个约束是Wi-Fi 芯片的功耗要单独管理。HC32L130 睡得再死如果 TXW813 一直醒着整机功耗也下不来。所以固件里必须有一个明确的“Wi-Fi 上电—联网—对时—断电”的状态机。提示在改固件之前先用万用表或者功耗分析仪测一下原厂固件在“联网待机”和“断网待机”两种状态下的电流。这个基线数据是你后面判断改造是否成功的唯一依据没有基线就没有优化。理解了硬件约束你才能理解为什么这个项目的固件不能照搬 ESP32 那套写法。ESP32 方案是“一颗芯片全包”而 Chouchin-CH899 是“分工协作”固件的复杂度其实更高因为你要自己协调两个芯片的节奏。2. 固件架构设计与关键器件选型逻辑2.1 为什么用 RTC 而不是软件计时这是整个固件改造里最重要的一个决定时间到底由谁来守。原厂固件很多是用 SysTick 或者普通定时器做软件计时主循环里累加秒数。这种做法在设备一直醒着的时候没问题但一旦进入低功耗模式定时器停了时间就断了。HC32L130 内部有独立的 RTC 外设可以由外部 32.768kHz 晶振驱动在深度睡眠模式下继续走时。这就是正确的守时方案。RTC 的好处有三个第一睡眠时依然计时唤醒后直接读寄存器就能拿到当前时间第二精度由晶振决定比软件累加可靠第三有独立的闹钟中断可以用来触发周期对时。具体做法是系统上电后先初始化 RTC如果 RTC 里没有有效时间比如后备电池没电就标记为“时间无效”等 Wi-Fi 对时成功后再写入。之后所有的时间显示都从 RTC 读取软件层不再自己累加秒数。这个改动看起来简单但它把“时间”这个核心状态从易失的 RAM 搬到了带后备的 RTC 里是整个固件稳定性的地基。2.2 Wi-Fi 对时链路的协议选择对时协议的选择直接影响到时精度和实现复杂度。常见的有三种NTP、SNTP、以及厂商提供的 HTTP 时间接口。NTP 是完整实现精度高但代码量大对于 HC32L130 这种资源紧张的 MCU 来说偏重。SNTP 是 NTP 的简化版去掉了复杂的时钟滤波和统计逻辑只保留基本的请求响应精度通常在几十毫秒到几百毫秒对于一台挂钟来说完全够用。厂商 HTTP 接口则是最省事的直接请求一个 URL返回里带时间戳解析一下就行但依赖厂商服务器。我的建议是优先用 SNTP。理由是它不依赖特定厂商服务器可以指向公共时间源或者你自己的内网时间服务器实现上只需要构造一个 48 字节的 UDP 包解析返回包里的 transmit timestamp 字段即可精度对于挂钟场景绰绰有余。如果 TXW813 的固件只支持 TCP 不支持 UDP那就退而求其次用 HTTP 接口。这里有个实操细节SNTP 返回的是 UTC 时间你需要自己做时区转换。别在固件里硬编码时区偏移而是把时区偏移做成一个可配置参数存在 Flash 里。这样以后改时区不用重新烧录固件。2.3 显示刷新与计时解耦的设计显示撕裂的根源是“计时逻辑和刷新逻辑跑在同一个节奏里”。比如主循环里先算时间再刷屏如果刷屏过程中时间变了就会出现半新半旧的显示。解耦的做法是引入一个显示缓冲区。计时逻辑RTC 读取、时间格式化只负责把“当前应该显示什么”写进缓冲区刷新逻辑定时器中断或者 DMA只负责把缓冲区的内容搬到屏幕上。两者通过一个标志位或者双缓冲机制同步互不干扰。具体到 HC32L130可以用一个定时器产生固定频率的中断比如 100Hz 或者 200Hz在中断里逐位或者逐段刷新显示。主循环则每隔一秒读一次 RTC更新缓冲区。这样即使主循环因为处理 Wi-Fi 数据卡了一下显示也不会闪因为刷新是定时器在保证的。注意如果用的是段码屏刷新频率不能太低否则会有闪烁感也不能太高否则增加功耗。一般 100Hz 到 200Hz 是比较舒服的区间。点阵屏的话还要考虑行扫描和列驱动的配合避免鬼影。2.4 电源状态机的设计思路电源管理是这个项目里最能体现“改造价值”的部分。原厂固件往往是“一直联网”而改进固件应该是“按需联网”。我设计的状态机大概是这样几个状态深睡态、唤醒态、联网态、对时态、回睡态。深睡态下 HC32L130 进 STOP 或 DEEP SLEEP 模式RTC 继续走TXW813 断电。RTC 闹钟或者外部按键触发唤醒进入唤醒态MCU 全速运行给 TXW813 上电。联网态等待 Wi-Fi 连接成功然后进入对时态发 SNTP 请求。对时成功后更新时间、写回 RTC然后进入回睡态关闭 Wi-FiMCU 重新进睡眠。这个状态机的关键参数是“对时间隔”。太频繁费电太稀疏精度差。对于普通晶振一天漂移几秒是正常的所以一天对时一到两次比较合理。如果你用的是高精度 TCXO可以放宽到几天一次。这个参数也应该做成可配置的。3. 核心环节的实操实现与参数计算3.1 开发环境搭建与烧录链路动手之前先把工具链准备好。HC32L130 是国产 MCU官方一般提供基于 Keil MDK 或者 IAR 的器件支持包也有基于 GCC 的开源工具链方案。如果你习惯 Keil装好器件包之后新建工程选对型号配置好下载器通常是 SWD 接口的 J-Link 或者 DAP-Link就能烧录。烧录链路这块有个坑要注意有些 Chouchin-CH899 的板子把 SWD 引脚复用成了别的功能或者干脆没引出调试口。这种情况下你需要先找到板子上的测试点或者通过串口 ISP 的方式烧录。我遇到过一块板子SWD 的 SWCLK 被拉去做按键扫描了最后是从 TXW813 的 UART 口进 bootloader 才刷进去的。所以动手前先确认烧录通道别拆了半天发现刷不进去。工具链版本方面建议用较新的器件包因为早期版本对 HC32L130 的低功耗模式支持可能有 bug。编译优化等级建议用 -O2 或者 -Os兼顾速度和体积。调试阶段可以用 -O0 方便单步但最终固件一定要用优化版本重新编译并测试功耗。3.2 RTC 初始化与时间写入的关键代码RTC 初始化是整个固件的地基这里把关键步骤拆开讲。首先是时钟源配置HC32L130 的 RTC 一般用外部 32.768kHz 晶振需要先使能晶振、等待起振稳定再切换 RTC 时钟源。起振时间跟晶振和负载电容有关通常几百毫秒到几秒代码里要有超时保护起振失败就降级用内部 RC 或者报错。// RTC 时钟源配置示意基于常见 HC32L130 库函数风格 void rtc_clock_config(void) { // 使能外部低速晶振 CLK_LSE_Enable(); // 等待起振带超时 uint32_t timeout 0xFFFFF; while (CLK_LSE_Ready() ! SET) { if (--timeout 0) { // 起振失败处理可降级或报错 break; } } // 切换 RTC 时钟源为 LSE CLK_SetRTCClockSource(CLK_RTC_CLK_LSE); // 使能 RTC 外设时钟 CLK_RTC_Enable(); }时间写入这块SNTP 拿到的是 Unix 时间戳从 1970 年起的秒数而 RTC 寄存器通常是年月日时分秒的 BCD 或者二进制格式。你需要写一个转换函数把 Unix 时间戳转成日历时间。这个转换不复杂但要注意闰年规则。我一般直接用一个查表加循环的写法代码量小不容易出错。写入 RTC 的时候要注意先进入配置模式写完再退出否则写入可能不生效。另外如果 RTC 有写保护要先解锁。这些细节在参考手册里都有但很容易漏。3.3 SNTP 请求构造与时间解析SNTP 请求包是 48 字节格式固定。第一个字节是标志位客户端请求一般填 0x1BLI0, VN3, Mode3。后面 47 字节大部分填 0只有 transmit timestamp 字段可以填当前时间也可以填 0服务器不强制要求。// SNTP 请求包构造示意 uint8_t sntp_req[48] {0}; sntp_req[0] 0x1B; // LI0, VN3, Mode3 (client) // 其余字节保持 0 // 通过 TXW813 的 UDP 通道发送到时间服务器 123 端口收到响应后重点解析第 40 到 43 字节这是 transmit timestamp 的秒数部分大端序。把它读出来减去 22089888001900 到 1970 的秒数差就得到 Unix 时间戳。这里有个容易踩的坑网络字节序是大端而 HC32L130 是小端读多字节字段的时候一定要做字节序转换否则时间会差出天文数字。我见过有人直接把四个字节拼起来用结果时间跑到了 2038 年之后。提示SNTP 服务器建议配置两个一个主用一个备用。请求失败时自动切换提高对时成功率。公共时间源虽然方便但稳定性和延迟不可控有条件的话在内网搭一个时间服务器更靠谱。3.4 显示缓冲区的双缓冲实现双缓冲的核心是准备两块缓冲区一块是“前台缓冲”正在被刷新逻辑读取一块是“后台缓冲”正在被计时逻辑写入。写完之后交换指针刷新逻辑下一轮就读到新内容。在 HC32L130 上RAM 比较紧张双缓冲会占用双倍显示内存。如果显示内容不多比如就几位数字这点开销可以接受。如果 RAM 实在紧张可以用“脏标志”方案只有内容变化时才更新刷新逻辑检测到标志才重新搬数据。刷新定时器的配置要注意优先级。如果刷新中断优先级太低被 Wi-Fi 通信中断长时间抢占显示还是会闪。建议把刷新定时器中断设成较高优先级但中断服务函数要尽量短只做数据搬运不做复杂计算。3.5 功耗实测与对时间隔的权衡计算功耗优化不能拍脑袋要算账。假设 HC32L130 深睡电流是 2 微安TXW813 工作时平均电流是 80 毫安每次对时过程持续 10 秒。如果一天对时一次那么平均电流大约是深睡时间约 86390 秒电流 2 微安对时时间10 秒电流 80 毫安平均电流 (86390 × 2 10 × 80000) / 86400 ≈ (172780 800000) / 86400 ≈ 11.3 微安如果改成一天对时四次平均电流会上升到大约 39 微安。看起来差别不大但如果你的设备是用纽扣电池供电这个差别就是续航从一年变成几个月的区别。所以对时间隔要根据电池容量和可接受的精度来定。我的经验值是普通晶振一天一次精度能保持在正负两秒以内如果要求更高可以一天两次但要做好功耗预算。如果用的是带温度补偿的晶振可以放宽到三天一次。4. 常见问题排查与避坑经验实录4.1 对时失败但 Wi-Fi 显示已连接这是最常见的问题之一。Wi-Fi 连上了但 SNTP 请求发出去没响应。排查顺序是这样的先确认 TXW813 是否真的拿到了 IP 地址有些模块“连接成功”只是链路层连上了网络层还没就绪再确认 DNS 是否可用如果你用的是域名而不是 IPDNS 解析失败也会导致请求发不出去最后确认 UDP 端口是否被模块固件限制有些 Wi-Fi 模块默认只开放 TCPUDP 需要额外配置。我遇到过一次模块连上了路由器但路由器那边做了客户端隔离导致 UDP 包出不去。换了个路由器就好了。所以排查的时候不要只盯着设备网络环境也要考虑。4.2 时间写入 RTC 后读数不对这个问题通常是字节序或者 BCD 转换搞错了。HC32L130 的 RTC 寄存器有的是 BCD 格式有的是二进制格式不同系列可能不一样一定要看手册。如果你写入的是二进制读的时候按 BCD 解析结果就会很离谱。另一个可能是写保护没解除。有些 RTC 寄存器在写之前要先写一个特定的解锁序列写完再上锁。如果漏了这一步写入会被静默忽略读出来还是旧值。4.3 显示偶尔闪烁或出现鬼影闪烁多半是刷新频率不对或者刷新中断被抢占。鬼影则通常是段码屏的消隐没做好或者点阵屏的行列驱动时序有问题。对于段码屏检查刷新中断里有没有做“先关显示再切换段码再开显示”的消隐处理。对于点阵屏检查行扫描和列数据的建立时间是否足够太快会导致上一行的残影留在下一行。还有一个容易被忽略的点如果刷新和 Wi-Fi 通信共用同一个定时器或者中断Wi-Fi 数据量大时刷新会被拖慢。解决办法是给刷新单独分配一个定时器别和通信混用。4.4 低功耗模式下电流降不下来这是最让人头疼的问题。明明 MCU 进了睡眠电流还是几百微安甚至毫安级。排查思路是逐个关外设先关 Wi-Fi 模块的电源看电流有没有降再关显示驱动的电源再检查有没有悬空的 GPIO悬空引脚漏电也会增加功耗。我踩过的一个坑是某个 GPIO 配置成了输入但没使能内部上拉/下拉引脚悬空导致输入级一直在翻转多耗了几十微安。把不用的引脚都配置成模拟输入或者输出低电平电流立刻就下来了。还有一个常见原因是调试接口没关。SWD 引脚在睡眠时如果还使能着调试器又连着功耗会偏高。量产固件里应该把调试接口关掉。4.5 常见问题速查表现象可能原因排查方法解决方向对时失败DNS 不可用ping 时间服务器域名改用 IP 或修 DNS对时失败UDP 被限制抓包看请求是否发出改用 TCP 或换模块配置时间写入无效写保护未解除读回寄存器对比加解锁序列时间数值离谱字节序错误打印原始字节做大端转换显示闪烁刷新频率低示波器看刷新信号提高频率或优先级显示鬼影消隐不足观察残影规律加消隐延时功耗偏高GPIO 悬空逐个测引脚配置为模拟输入功耗偏高调试口未关断开调试器测固件关闭 SWD唤醒后死机时钟未稳定看唤醒后时钟状态加起振等待唤醒后时间错RTC 未同步对比唤醒前后唤醒后重读 RTC4.6 几个只有踩过才知道的细节第一个细节TXW813 上电后需要一定的启动时间才能接受 AT 指令如果你上电就发命令它会丢。正确做法是上电后延时几百毫秒或者等它主动发出 ready 信号再通信。第二个细节SNTP 请求的源端口可以随便选但目标端口必须是 123。有些 Wi-Fi 模块的 socket 实现要求你先 bind 一个本地端口别忘了这一步。第三个细节RTC 闹钟中断唤醒后中断标志要及时清除否则会反复触发。而且清除标志和重新设置闹钟的顺序有讲究先清标志再设闹钟避免竞态。第四个细节Flash 存储配置参数时要注意擦写寿命。不要每次对时都写 Flash只在参数真正变化时才写。可以把参数放在 RAM 里定期或者关机前才落盘。5. 改造后的验证与长期运行观察5.1 功能验证清单固件改完之后别急着装回去先做一轮完整验证。我一般按这个清单走上电后 RTC 是否正常起振、Wi-Fi 是否能连上、SNTP 是否能拿到时间、时间是否正确写入 RTC、显示是否与 RTC 一致、断网后时间是否继续走、重新联网后是否自动对时、按键如果有是否正常、低功耗模式下电流是否达标。每一项都要有明确的通过标准。比如“时间正确”不是看一眼差不多就行而是要跟标准时间源对比误差在可接受范围内才算过。5.2 长期漂移观察方法短时间测试看不出漂移需要跑一段时间。我的做法是改造完成后让设备连续运行一周每天同一时间记录一次显示时间与标准时间的偏差。一周下来你就能看出这颗晶振的实际漂移率从而决定对时间隔设成多少合适。如果发现漂移特别大比如一天差十几秒那可能是晶振负载电容不匹配或者晶振本身质量不行。这种情况下光靠软件对时治标不治本需要考虑换晶振或者加温度补偿。5.3 固件升级通道的预留改造固件的时候最好预留一个升级通道。哪怕现在用不上以后想改点东西不用拆机重新烧录会方便很多。最简单的做法是在固件里留一个串口命令收到特定指令后进入 bootloader 模式通过串口接收新固件。复杂一点可以用 Wi-Fi 做 OTA但对 HC32L130 来说资源开销比较大要权衡。我个人倾向于留串口升级实现简单可靠性高。把升级引脚或者命令藏好避免误触发就行。5.4 我在这类项目上的个人体会折腾过几台类似的 Wi-Fi 时钟之后我最大的体会是低功耗联网设备的固件难点从来不在“联网”而在“不联网的时候怎么办”。联网对时本身不难难的是断网之后设备还能不能像个正常的钟一样工作难的是电池能不能撑住难的是显示会不会因为通信而受影响。所以如果你也在做类似的项目我的建议是先把“离线守时”这条链路做扎实再去搞联网。RTC 走稳了显示刷新解耦了电源状态机清晰了剩下的联网部分就是锦上添花。反过来如果地基没打好联网功能做得再花哨设备用起来还是不省心。另外别迷信“一次对时管很久”。晶振这东西受温度影响很大夏天和冬天表现可能完全不一样。与其纠结怎么把对时间隔拉长不如把对时过程做得足够快、足够省电这样即使对时频繁一点整体功耗也可控。这个思路上的转变是我踩了不少坑之后才想明白的。
返回列表