尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用STM32F103C8T6复刻开源手表WATCHX-NWATCH:从B站视频到桌面摆件的DIY全记录

用STM32F103C8T6复刻开源手表WATCHX-NWATCH:从B站视频到桌面摆件的DIY全记录 用STM32F103C8T6打造个性化桌面电子钟从开源项目到定制化改造实战在B站偶然刷到那个英国极客制作的NWATCH-WATCHX视频时我正对着桌面上闲置的STM32开发板发呆。视频里那个能玩游戏、显示时间的迷你手表突然让我意识到——或许该给这些吃灰的硬件第二次生命。不同于原项目的可穿戴设备定位我更想把它改造成一个兼具实用与趣味性的桌面电子钟既能展示时间又能成为工作间隙的小玩具。这就是本次DIY旅程的起点用最常见的STM32F103C8T6开发板复刻并重塑一个开源电子钟项目。1. 项目准备与硬件选型1.1 核心硬件配置解析手头的STM32F103C8T6开发板俗称蓝莓派是这个项目的基础它的资源对于电子钟应用绰绰有余MCUSTM32F103C8T672MHz主频64KB Flash20KB RAM显示屏0.96寸OLEDSSD1306驱动SPI接口输入设备5向导航按键上、下、左、右、确认电源USB供电或3.7V锂电池通过TP4056充电模块提示如果使用不同型号的OLED屏可能需要调整驱动中的初始化参数特别是分辨率和通信协议I2C/SPI。1.2 开源代码获取与初步评估原项目的STM32移植版托管在GitHubWatchX-Nwatch-stm32仓库包含F1和F4两个版本。对于C8T6这类F1系列芯片我们重点关注以下核心文件/src ├── drivers # 硬件驱动层 │ ├── oled.c │ ├── buttons.c │ └── rtc.c ├── apps # 应用功能模块 │ ├── clock.c │ ├── stopwatch.c │ └── game.c └── system # 系统核心 ├── main.c └── scheduler.c代码结构采用模块化设计每个功能都是独立的app通过注册机制与核心系统交互。这种架构的最大优势是扩展性强——添加新功能时无需改动原有代码。2. 硬件适配与代码精简2.1 针对C8T6开发板的修改原代码基于正点原子Mini板RCT6芯片编写与我们的C8T6板存在一些差异功能模块原板配置C8T6适配方案RTC时钟外部DS1302芯片使用芯片内部RTC蜂鸣器PA1引脚移除相关代码OLED屏接口SPI硬件接口软件模拟SPI节省硬件资源按键布局独立5个GPIO改用ADC按键节省引脚关键的硬件初始化调整如下system_init.c// 修改后的初始化流程精简版 void hardware_init() { HAL_Init(); SystemClock_Config(); // 初始化内部RTC替代外部时钟芯片 RTC_Init(); // 软件模拟SPI初始化OLED OLED_Init(OLED_MODE_SPI); // ADC按键初始化使用PA1 ADC_Key_Init(); // 系统定时器用于事件调度 SysTick_Init(); }2.2 功能模块的取舍艺术不是所有原项目功能都适合桌面场景我的筛选原则是保留核心功能时间显示支持12/24小时制日期和星期显示简单动画效果如秒针跳动移除冗余功能计步器桌面设备不需要心率监测无传感器支持复杂菜单层级简化为3级新增实用特性USB充电状态指示自动亮度调节通过光敏电阻待机时钟模式低功耗显示3. 系统架构深度优化3.1 事件驱动模型重构原代码采用轮询方式检测按键和更新显示这在桌面场景下会造成不必要的功耗。我将其改造为事件驱动低功耗休眠的混合模式// 新的事件处理核心逻辑 while(1) { if(KEY_EventOccurred()) { // 按键唤醒 Event_t event KEY_GetEvent(); App_HandleEvent(currentApp, event); // 当前应用处理事件 Display_Refresh(); // 局部刷新界面 Reset_SleepTimer(); // 重置休眠倒计时 } else if(SleepTimer_Expired()) { Enter_LowPowerMode(); // 进入深度休眠 __WFI(); // 等待中断唤醒 } }这种设计使得系统在无操作时电流从25mA降至3mA特别适合长期插电使用的场景。3.2 显示效果的进阶优化0.96寸OLED虽然小巧但通过以下技巧可以显著提升视觉体验抗锯齿字体渲染使用4级灰度算法处理斜线边缘动态缓存常用字符的渲染结果平滑动画实现// 秒针动画示例每500ms更新一次 void drawSecondHand(int prev_angle, int new_angle) { for(int iprev_angle; i!new_angle; isign(new_angle-prev_angle)) { OLED_ClearSection(sec_hand_area); // 局部清除 drawHand(i, HAND_TYPE_SECOND); // 绘制新位置 HAL_Delay(20); // 动画间隔 } }主题系统设计 定义结构体存储不同显示风格typedef struct { uint16_t bg_color; uint16_t text_color; uint8_t font_id; bool show_second; } Theme_t; const Theme_t themes[] { {BLACK, WHITE, FONT_6x8, true}, // 经典黑白 {WHITE, BLACK, FONT_8x16, false}, // 简约风格 {0x00F0, 0xFFFF, FONT_8x8, true} // 蓝底黄字 };4. 外壳设计与成品制作4.1 3D打印外壳实战为了让这个电子钟真正成为桌面的亮点我设计了分体式外壳前盖开孔尺寸42mm×32mm对应OLED可视区域45度倒角处理减少反光磁吸式固定结构底座15度仰角设计符合人眼自然视角隐藏式走线槽USB电源线配重块槽位可加装硬币调节重心注意使用PLA材料打印时建议设置0.15mm层高和100%填充率以确保结构强度。4.2 组装技巧与排错实际组装时遇到的几个典型问题及解决方案问题现象可能原因解决方法显示闪烁电源干扰在VCC与GND间添加100μF电容按键响应延迟ADC采样频率过低将ADC时钟提高到14MHzRTC时间走时不准外部晶振负载电容不匹配调整晶振两侧的22pF电容待机后无法唤醒唤醒中断未正确配置检查EXTI线是否连接到按键GPIO最终的成品虽然比原项目的手表形态大了许多但放在显示器旁却意外地和谐。每当工作间隙轻触按键切换到俄罗斯方块游戏或是看着那个模拟机械表盘上流畅走动的秒针都能感受到从代码到实物的创造乐趣。或许这就是硬件DIY的魅力——它让数字世界的逻辑以最物理的方式触手可及。
返回列表