【2023星火计划】基于GD32F303与MPU6050的智能计时骰子设计与实现全解析

📅 发布时间:2026/7/10 22:10:54 👁️ 浏览次数:
【2023星火计划】基于GD32F303与MPU6050的智能计时骰子设计与实现全解析
从零复刻智能计时骰子GD32F303MPU6050实战全解析大家好我是老张一个喜欢捣鼓硬件的嵌入式工程师。前段时间在网上看到一个挺有意思的产品——一个能计时的骰子。你把它往桌上一放不同的面朝下就能触发不同时长的倒计时时间到了还会“滴滴”提醒。这玩意儿看着简单但创意十足特别适合厨房计时、健身休息间隔这些场景。我当时就想这功能不复杂啊咱们能不能自己动手做一个说干就干我花了几个月时间从画电路板、写代码到设计外壳完整走了一遍产品开发流程。今天我就把这个“智能计时骰子”项目的全过程拆开揉碎了讲给你听不管你是嵌入式新手还是想参加“星火计划”这类比赛的学生相信都能从中学到实实在在的东西。咱们这个骰子核心就三块GD32F303CGT6单片机做主控MPU6050姿态传感器感知骰子哪面朝下GC9A01圆形屏幕显示时间和动画。下面我就从硬件选型、电路设计、软件编程到外壳制作一步步带你复现这个项目。1. 硬件方案设计与核心器件选型做硬件项目第一步永远是“想清楚再动手”。咱们先分析一下这个计时骰子到底需要哪些功能模块。1.1 功能分解与核心需求这个骰子本质上是个带姿态识别的定时器。它的工作流程很简单姿态感知骰子静止时系统待机当你把它翻转让某个数字面朝下时它能识别出是哪个面。计时触发根据识别出的面对应不同的预设时间比如1分钟、5分钟启动对应时长的倒计时。信息显示屏幕上显示倒计时进度、电池电量等信息。用户交互可以通过按钮自定义其中一个面的时间计时结束蜂鸣器提醒。拆解下来硬件上我们需要大脑主控MCU处理传感器数据、运行图形界面、管理定时任务。眼睛姿态传感器实时感知骰子的三维朝向。脸显示屏圆形屏幕显示信息。耳朵和嘴巴按键与蜂鸣器接收用户输入和发出提示音。心脏电源系统锂电池供电、充电管理、稳压。1.2 关键器件选型心得选型就像配电脑既要性能够用也得考虑成本和开发难度。主控MCU为什么是GD32F303CGT6一开始我也在STM32和国产GD32之间犹豫。这个项目对引脚数量要求不高但“吃”资源的地方有两个图形界面LVGL要在240x240的屏幕上做出流畅的动画很消耗内存和CPU。姿态解算DMP库MPU6050官方的DMP库数字运动处理器能直接输出处理好的姿态角但库本身运算量不小。GD32F303CGT6用的是ARM Cortex-M4内核主频168MHz最关键的是它有1024KB的Flash和96KB的SRAM。大内存对于跑LVGL和DMP库太重要了能避免各种内存不足的坑。而且它性价比很高完全能满足需求。姿态传感器MPU6050成熟稳定的选择市面上姿态传感器很多有更先进的MPU9250带磁力计也有国产的型号。我最终选择经典的MPU6050原因就两个字生态。它的资料最多官方的DMP库非常成熟直接移植就能用不用自己从头写复杂的姿态融合算法融合加速度计和陀螺仪数据这对项目快速成型至关重要。显示屏GC9A01驱动的圆形SPI屏为了契合骰子的造型屏幕选了圆形的。GC9A01是一款很常见的LCD驱动芯片通过SPI接口通信240x240的分辨率显示图标和数字足够清晰。购买时注意选择带FPC软排线的方便后续安装。电源管理TP4059充电芯片项目用锂电池供电充电管理芯片我选了经典的TP4059。它电路简单外围元件少最大支持800mA充电电流通过调整PROG引脚电阻实现。如果追求更快充电可以换用TP4056支持1A电流。提示对于初次进行完整产品开发的朋友我的建议是优先选择资料丰富、社区支持好的成熟芯片这能帮你把精力集中在系统设计和功能实现上而不是和底层驱动搏斗。2. 电路设计详解与“踩坑”记录原理图是硬件的蓝图这里我把几个关键部分的电路设计和注意事项分享给你有些坑我已经踩过了你直接避过去就行。2.1 电源电路安全稳定的能量核心整个系统用一颗3.7V的锂电池供电单片机、屏幕、传感器都需要3.3V工作电压。所以电源部分要完成三件事降压、充电、供电切换。3.3V稳压电路我用了一颗南京微盟的ME611C33M5G-NLDO芯片。LDO就是低压差线性稳压器它的优点是电路简单、输出纹波小。这颗芯片最大能输出500mA电流对于咱们这个系统MCU屏幕传感器绰绰有余。// 电路设计很简单 // VIN (电池电压) - ME611C33M5G-N - VOUT (3.3V) // 输入输出各接一个10uF和0.1uF的电容滤波保证稳定。锂电池充电与供电自动切换这是个小亮点也是容易出问题的地方。我希望实现插USB时由USB给板子供电并同时给电池充电不插USB时由电池给板子供电。我设计的电路如下思路描述使用一个PMOS管如SI2301作为开关连接在电池VBAT和系统电源输入VIN之间。当USBVBUS没有电压时PMOS管导通电池电压顺利到达VIN。当插入USB时VBUS电压通过一个电阻使PMOS管的栅极为高电平PMOS管关闭从而切断电池到VIN的路径。此时VIN的电压来自VBUS经过一个二极管如B5819W。这个二极管的作用是防止电池电压倒灌回USB口。注意这里用的B5819W二极管正向压降约有0.55V。也就是说如果USB是5V经过它后到VIN就只有4.45V左右了再经过LDO降压效率有点损失。如果你介意这点压降可以换成肖特基二极管SS14压降约0.5V但体积会大一些。电池电量检测为了在屏幕上显示电池电量我们需要检测电池电压。简单又省电的方法就是用两个电阻串联分压。因为电池满电约4.2V超过单片机的3.3V ADC测量范围所以用电阻把电压分一半降到2.1V以内再用单片机的ADC引脚读取。// 例如R1 R2 100kΩ // ADC测到的电压值 VBAT * (R2 / (R1 R2)) VBAT / 2 // 然后在代码里将这个ADC值换算回真实的电池电压。2.2 主控与传感器电路设计要点GD32F303最小系统最小系统包括电源、复位、晶振、下载接口。有两点要特别留意外部晶振必须加我们这个产品是计时器对时间精度有要求。内部RC振荡器误差较大会导致计时不准。务必使用8MHz的外部无源晶振并配上合适的负载电容通常22pF。ADC电源隔离如果用到ADC比如测电池电压最好把ADC的供电引脚VDDA和参考地VSSA通过一个0Ω电阻或磁珠与数字电源VDD和数字地VSS隔离开。这样可以减少数字电路噪声对模拟采样的干扰提高测量精度。MPU6050传感器电路MPU6050或MPU6500是QFN封装引脚在芯片底部手工焊接难度极大堪称“新手噩梦”。我的经验是在PCB上同时画上QFN封装的焊盘和一个标准的2.54mm排母座。如果你能焊好QFN那最好体积小。如果焊不了直接买一个现成的MPU6050模块插在排母上非常方便。这就是为什么原理图上我画了两个位置。屏幕GC9A01接口屏幕通过FPC软排线连接。这里我踩过一个坑使用硬件SPI驱动GC9A01屏幕时SPI的时钟线SCK和数据线MOSI必须加上拉电阻通常4.7kΩ或10kΩ否则通信可能不稳定导致屏幕花屏或不显示。同样考虑到FPC座子也不好焊我也在旁边预留了一组排针备用。用户按键与蜂鸣器按键电路加了双向瞬态抑制二极管TVS防止静电或瞬间高压损坏单片机IO口这是个好习惯。 蜂鸣器我选了有源蜂鸣器意思是给它一个直流电压3.3V它就会响频率是固定的。这样只需要一个NPN三极管如S8050驱动即可单片机IO口输出高电平三极管导通蜂鸣器通电发声。比无源蜂鸣器需要单片机输出PWM信号驱动省事。3. 软件框架与核心功能实现硬件搭好了接下来就是让它“活”起来。软件部分主要围绕三个核心姿态识别、图形界面LVGL、定时器管理。3.1 工程搭建与MPU6050 DMP库移植首先你需要一个GD32F303的工程模板可以用官方的固件库或者GigaDevice的IDE来创建。移植MPU6050 DMP库这是姿态识别的关键。InvenSenseMPU6050的生产商提供了官方的“MotionDriver”库里面包含了DMP功能。获取库文件从官方或开源社区找到inv_mpu.c、inv_mpu_dmp_motion_driver.c、inv_mpu.h等核心文件。实现底层接口库需要你提供几个底层函数主要是i2c_write和i2c_read用于通过I2C总线读写MPU6050的寄存器。你需要根据GD32的I2C驱动来填充这两个函数。初始化与数据读取// 伪代码流程 mpu_init(); // 初始化MPU6050 dmp_load_motion_driver_firmware(); // 加载DMP固件 dmp_set_orientation(); // 设置传感器方向与你PCB安装方向对应 mpu_set_dmp_state(1); // 使能DMP // 然后在一个定时器中断或循环里 while(1) { if (dmp_read_fifo() 0) { // 读取DMP解算后的数据 dmp_get_euler_angles(euler); // 获取欧拉角俯仰角、横滚角、偏航角 // 根据欧拉角判断骰子哪个面朝下 } delay_ms(10); }DMP库直接输出稳定的姿态角欧拉角省去了我们自己写卡尔曼滤波或互补滤波的麻烦。3.2 使用LVGL构建圆形屏幕界面LVGL是一个轻量级、开源、效果华丽的嵌入式图形库非常适合用在资源有限的单片机上。移植LVGL到GD32添加LVGL源码将LVGL核心库、驱动组件等添加到工程。实现显示驱动写一个lvgl_port_disp_init函数里面初始化GC9A01屏幕通过SPI并实现一个disp_flush回调函数。这个函数负责将LVGL画好的图像缓冲区buffer数据搬运到屏幕的显存。实现输入设备驱动我们的按键需要映射为LVGL的输入。实现一个lvgl_port_indev_init函数并创建一个indev_read回调在里面检测按键状态并转换为LVGL的LV_KEY_ENTER等事件。配置心跳LVGL需要周期性的心跳lv_tick_inc()来处理动画和任务。把它放在一个1ms的定时器中断里最合适。创建骰子界面界面元素很简单一个大的数字显示剩余时间。一个环形进度条环绕在数字周围直观显示进度。底部的小图标电池电量、设置标志等。// 示例创建一个标签显示时间 lv_obj_t * time_label lv_label_create(lv_scr_act()); lv_label_set_text(time_label, 05:00); lv_obj_align(time_label, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_text_font(time_label, lv_font_montserrat_48, 0); // 示例创建一个环形进度条 lv_obj_t * progress_bar lv_bar_create(lv_scr_act()); lv_bar_set_range(progress_bar, 0, 100); lv_bar_set_value(progress_bar, 75, LV_ANIM_ON); // 设置当前值75% lv_obj_set_size(progress_bar, 220, 220); lv_obj_align(progress_bar, LV_ALIGN_CENTER, 0, 0); lv_bar_set_type(progress_bar, LV_BAR_TYPE_CIRCULAR); // 设置为环形3.3 核心逻辑状态机与姿态判断整个骰子的逻辑可以用一个状态机来清晰描述待机状态屏幕显示时钟或待机动画。持续读取MPU6050的欧拉角。姿态判断当检测到骰子被拿起、翻转并且最终某个面的角度持续稳定一段时间比如1秒后根据预设的俯仰角Pitch和横滚角Roll范围判断出是哪个数字面朝下。例如定义“1点”面朝下时Pitch角在-90度附近Roll角在0度附近。计时状态根据判断出的面启动对应的倒计时如1点1分钟。屏幕更新为大数字倒计时和环形进度条。提醒状态计时结束蜂鸣器响起屏幕闪烁直到用户按下任意键或翻转骰子回到待机状态。设置状态当在待机状态下长按某个键进入时间设置模式通过按键调整自定义面的时间。提示姿态判断的阈值需要在实际装配好后进行校准。你可以写一个简单的测试程序把骰子每个面朝下静止通过串口打印出此时的欧拉角记录下来作为判断依据。这样比理论计算更准确。4. 结构设计与组装心得硬件和软件都搞定了最后得给它们一个“家”。4.1 3D打印外壳设计原版产品用了金属和塑料的复合结构成本高。我选择全3D打印更便宜也更容易修改。设计工具使用Fusion 360或SolidWorks等软件。我的设计比较粗糙就是上下盖结构内部留出主板、副板屏幕和按键板、电池的位置。固定方式上下盖通过螺丝固定。内部用螺丝柱或卡扣固定PCB板。一定要留出USB充电口、蜂鸣器出声孔、屏幕视窗和按键的开口。文件分享我的3D打印外壳文件已经开源你可以直接下载使用或在此基础上修改。4.2 PCB布局与组装注意事项主板与副板为了走线方便和结构紧凑我设计了两块板子。主板在底部包含主控、电源、传感器等。副板在顶部只有屏幕和两个按键通过FPC排线与主板连接。焊接顺序先焊难度小的阻容元件再焊芯片。对于QFN封装的MPU6050如果没把握果断使用预留的排母插接模块。焊接FPC座子时烙铁温度不要太高用尖头烙铁仔细对位。组装测试不要急着把所有螺丝拧死。先连接好所有排线通电测试基本功能屏幕亮、按键灵、传感器有数据。确认无误后再最终组装。这个项目从灵感到实物涉及了嵌入式产品开发的完整链条需求分析、方案选型、电路设计、PCB绘制、固件开发、结构设计。过程中充满了挑战比如LVGL内存优化、MPU6050数据抖动处理、电源切换电路调试等。但每解决一个问题都是实实在在的成长。希望这篇详细的复盘能为你打开一扇窗看到一个小产品从想法到落地的全过程。最重要的是动手去做在调试中学习在失败中积累经验。项目的所有硬件设计文件、固件代码和3D外壳模型都已开源链接就在原项目页面欢迎取用和二次创作。如果你在复现过程中遇到任何问题也欢迎一起交流讨论。