Skip to content

StevenWin818/GD32F30xClock

Repository files navigation

GD32F30xClock 固件说明

本项目为基于 GD32F30x 系列 MCU 的电子钟固件。内容涵盖钟表主界面、秒表、倒计时、闹钟与设置等子应用。项目以 Keil/MDK 项目为主,使用 ST7920 LCD(并基于帧缓冲)显示位图字模和图标,采用 DS3231 RTC 作为主要时钟源,并支持通过 GPS(GT-U8)授时。代码组织清晰,模块分层,便于扩展与移植。


目录与快速浏览

  • Project/ - Keil/MDK 工程文件(MyGD32F30X.uvprojx 等)
  • User/ - 应用层源代码(包括 UI、子应用、驱动、外设、字体与持久化)
    • 关键文件:
      • main.c - 程序入口与应用切换
      • clock_app.c / clock_app.h - 主钟面与交互逻辑
      • display.c / display.h - ST7920 显示驱动与帧缓冲绘制
      • keypad.c / keypad.h - 按键输入(去抖、短/长按)
      • buzzer.c / buzzer.h - 蜂鸣器控制
      • rtc_ds3231.c / rtc_ds3231.h - DS3231(软件 I2C)RTC 驱动
      • gps_gtu8.c / gps_gtu8.h - GPS(GT-U8, NMEA RMC)解析
      • stopwatch_app.c, countdown_app.c, alarm_app.c, settings_app.c - 各子应用
      • flash_storage.c / flash_storage.h - Flash 持久化(双槽原子写入)
      • status_bar.c - 顶部状态栏(时间/温度/标题)
  • Firmware/ - 底层外设抽象层 (GD32 系列 HAL、库)
  • build/Objects/Project/build/ - 编译产物

功能特性

  • 实时时钟显示(支持 DS3231 RTC),同步周期:默认每 1s(可配置)
  • GPS 授时支持(NMEA RMC 解析),可在设置中开启/关闭
  • 顶部状态栏:时分、小字温度显示与当前页面标题
  • 主界面:日期/时间显示、功能区(秒表、倒计时、闹钟、设置)
  • 秒表:开始/停止、圈次(lap)与圈次视图
  • 倒计时:编辑、预置快捷启动、暂停/取消、结束提示
  • 闹钟:设置闹钟时间、启/停、闹铃响铃与确认
  • 设置页:整点报时(hourly chime)、GPS 授时开关
  • 持久化:当/关/闹钟配置写入 Flash,使用双槽原子更新策略
  • 人机交互:4 个按键(K1..K4)支持短按/长按/长按重复
  • 蜂鸣器提示:短/长按音、闹钟和倒计时警报(支持连续方波)

硬件清单与引脚映射

注:该映射由代码中对应驱动文件里定义的 GPIO 引脚决定(见 display.c, rtc_ds3231.c, gps_gtu8.c, keypad.c, buzzer.c)。

  • MCU:GD32F30x(请使用与 Project/MyGD32F30X.uvprojx 匹配的芯片型号)
  • LCD:ST7920 或兼容的图形 LCD,接口为并行 8-bit(代码驱动)
    • 数据线:GPIOB PB0..PB7
    • RS: PB8
    • RW: PB9
    • E: PB10
    • PSB: PB11
    • RST: PB12
  • DS3231 RTC (软件 I2C,bit-banged)
    • SCL: PB13
    • SDA: PB14
  • GPS (GT-U8, UART)
    • USART0 TX: PA9, RX: PA10GPS_USART = USART0
  • Keypad(4个按键)
    • K1: PA0
    • K2: PA1
    • K3: PA2
    • K4: PA3
  • 蜂鸣器(Buzzer)
    • PA8
  • 其它:按需接线(例如 VCC 与 GND, I2C 上拉电阻等)

硬件电气注意事项:

  • DS3231 使用开漏 I2C 引脚;若外部模块未提供上拉,则需要外部上拉电阻。
  • GPS 波特率 9600,需将其串口 TX -> MCU RX (PA10) 连接。
  • LCD 初始化与时序基于 ST7920,若换屏请检查命令序列与电源复位脉冲。

人机交互(HMI)说明

四个按键(K1..K4)带有短按(SHORT)与长按(LONG)能力:

通用按键行为(在不同页面略有差别):

  • K1:短按选择/进入编辑/开始/确认;长按用于特殊操作或退出编辑
  • K2:在编辑模式中增值;在查看模式中移动/切换功能(向左/向上)
  • K3:在编辑模式中减值;在查看模式中移动/切换功能(向右/向下)
  • K4:短按切换光标行(日期->时间->功能区);长按进入表盘页或取消/退出

各应用中按键分配(摘录主要行为):

  • 主界面(clock_app

    • K1 短按:进入编辑(日期或时间)或在功能区启动选中功能
    • K1 长按:与短按相同(编辑/启动); 编辑时长按保存并退出
    • K2:在编辑时增加字段;查看时移动功能选择
    • K3:在编辑时减少字段;查看时移动功能选择
    • K4 短按:光标在日期 -> 时间 -> 功能区 循环;编辑时退出编辑(不保存)
    • K4 长按:进入表盘页(CLOCK_FACE)
  • 秒表(stopwatch_app

    • K1 短按:开始/停止;K1 长按:重置
    • K2 短按:在非 lap_view 时添加圈次;在 lap_view 时翻页
    • K3 切换 lap_view / 返回主秒表界面
    • K4 退出秒表页回到主界面
  • 倒计时(countdown_app

    • K1:短按进入/推进编辑/开始;长按快速开始或退出编辑
    • K2/K3:在编辑中调整当前位;在查看中改变预设或控制选择
    • K4 退出或隐藏页面
  • 闹钟(alarm_app

    • 支持编辑闹钟小时/分钟、启用/禁用闹钟
    • 闹钟到时会触发响铃(蜂鸣器),任意按键可关闭响铃;K4 可同时退出页面
  • 设置(settings_app

    • K2/K3: 上/下选择项目
    • K1: 切换当前选项(ON/OFF),同时保存到 Flash(与闹钟/设置信息一并)
    • K4: 退出设置页

功能与人机交互(详细说明)

下面对各个模块的行为、UI 交互和关键流程做更详细的说明,帮助开发者与测试人员理解状态转换、按键响应、和与外设(RTC/GPS/Flash)交互的期望行为。

总体 UI / 刷新策略

  • 屏幕基于帧缓冲(s_lcd_buffer)设计,绘图操作写入缓冲后通过 display_flush_rows(row_start, row_end) 将行数据写入 LCD。仅刷新需要更新的行以降低开销。
  • 状态栏顶部绘制(时间/标题/温度)以较短时间间隔采样;子应用在刷新时继续调用 status_bar_render(now_ms, title) 来维护一致显示。
  • 主界面、功能页与子应用切换通过 main.c 的状态机实现(APP_MODE_*)——主循环调用 loop()background_tick(),处理页面间的进入/退出。

状态栏(status_bar)

  • 每 500ms 采样一次 RTC 时间用于小字时间更新(显示 MM:SS),每 5s 采样一次温度。
  • 仅当时间/温度/标题变化或被标记为 force redraw 时才刷新(节约 IO)。

主界面(clock_app)

  • 布局:顶部状态栏;日期行(16 px 高);时间区(大字 12x24 或 8x16 带冒号);底部功能行(4 个图标,16x16 或 24x24)。
  • 进入方式:程序启动默认进入主时钟界面;按 K4 可在日期→时间→功能 行间切换光标。
  • 光标与编辑:
    • 初始:光标默认在日期行(CURSOR_LINE_DATE),不可见直到任何键操作触发光标可见。
    • 光标闪烁:编辑模式下每 400ms 切换一次;若 5 秒无按键活动,光标超时并隐藏,回到默认(日期)位置。
    • 进入编辑:光标在日期/时间时按 K1 进入编辑。K1 还用于推进编辑步(从日的个位向更高位推进,或从秒向分/时推进)。
    • 编辑保存/撤销:K1 长按(或在编辑过程中走完最后一步)保存并应用编辑;K4 短按在编辑模式下退出并不保存(K4 长按同样退出不保存)。
    • 时间/日期限制:通过 days_in_monthis_leap_year 等函数保证范围有效,增减支持环绕(例如小时 23 + 1 → 0)并会在修改分钟时同步调整日期(如跨天)。

功能区(底部图标)

  • 可选功能:秒表、倒计时、闹钟、设置(图标顺序以 kFeatureIcons 定义)。
  • 查看模式在功能区时,K2/K3 用于左右切换选中图标,K1 短按进入选中功能,K1 长按同样进入。K4 短按在功能区循环回到日期(上一级)。

秒表(stopwatch_app)

  • 状态:Stopped / Running / Paused。UI 支持主显示时间与圈次视图。
  • K1:短按开始/停止;长按重置到 0。
  • K2:短按记录 Lap(在主屏),在 Lap View 中用于向前翻页;长按在主屏用于清空所有圈次。
  • K3:切换 Lap View(查看圈次列表)/返回主秒表界面。
  • K4:退出秒表界面返回主时钟。

倒计时(countdown_app)

  • 支持 6 位编辑(hh:mm:ss 的拓展 / 以秒为单位),4 个预设(1 小时、30 分钟、10 分钟、3 分钟)。
  • 状态:Idle / Running / Finished。
  • K1:短按进入编辑/推进编辑或在运行状态下暂停/恢复;K1 长按在 Idle 可快速开始或在编辑时保存并开始。
  • K2/K3:左右切换或增加/减少当前位;在选择预设时 K1 可直接触发预设快速开始。
  • 倒计时完成音响并显示 Finish UI,任意键停止声音;若隐藏页面(K4)则可继续倒计时/结束动作仍然会触发警报。

闹钟(alarm_app)

  • 支持编辑 hour:min 与启用/禁用,保存会写入 flash_storage(与 settings 一并保存)。
  • 当达到闹钟时间(秒 == 0)且开启时,如果未在当日触发(last_trigger_token 并发保护),会进入 Ringing 状态并启动蜂鸣器连续方波。任意按键停止响铃并返回配置界面;K4 键还会触发退出事件。

设置(settings_app)

  • 支持项:整点报时(Hourly Chime),GPS 授时(GPS Sync)。
  • 通过 K2/K3 改变选中行,K1 短按切换 ON/OFF 并保存(写入 flash)并将闹钟/设置信息同步写入持久化槽。

RTC(DS3231)与 GPS(GT-U8)

  • RTC 采用软件 bit-banged I2C(PB13/PB14),读写时间与温度(温度返回值以 0.01°C 为单位)。
  • GPS 解析 RMC 报文并仅提取 UTC 时间(应用层可决定是否做时区偏移)。GPS 授时由 settingsgps_sync 开关控制,且在 clock_app 中每 2 小时以 g_next_gps_sync_ms 驱动查询/同步。
  • clock_app 中,RTC 同步优先在 g_next_rtc_sync_ms 周期进行,失败则按重试间隔处理。

Flash 持久化(flash_storage)

  • 采用双槽(A/B)策略:探测 flash 尺寸、页大小后分配两个槽;写入时先擦除备用槽并写入带 CRC 校验的 blob,确保原子更新。
  • flash_storage_blob_t 中保存:magicversioncrchourly_chimegps_syncalarm_houralarm_minutealarm_enabled 等字段。

按键驱动(keypad)实现要点

  • 按键使用轮询采样(KEYPAD_SAMPLE_MS = 2ms),消抖(KEYPAD_DEBOUNCE_MS = 10ms),短按最小值(20ms),长按判定(300ms)并支持长按重复(500ms 重复周期)。
  • 按键事件通过 keypad_take_events(KEYPAD_Kn) 取出并清零,事件标志 KEYPAD_EVENT_SHORT/KEYPAD_EVENT_LONG 并支持重复长按事件上报。

蜂鸣器(buzzer)

  • 支持短时蜂鸣(timed)和连续方波(continuous square wave)。
  • 定时或方波的持续/停止由 buzzer_task(now_ms) 驱动;闹铃或倒计时警报使用连续方波,短按提示音使用定时蜂鸣。

使用示例(快速操作)

  • 设置当前时间(本地调整)
    1. K4 多次短按使光标切换到“时间”行
    2. K1 短按进入时间编辑
    3. K2/K3 调整当前高/低位(K1 每次短按推进到下一位)
    4. K1 长按或在最后一位随后 K1 提交编辑(保存并写入 RTC);K4 在编辑时短按可放弃编辑
  • 设置闹钟
    1. K4 多次短按使光标切换到 Feature 区,并用 K2/K3 选中 Alarm 图标
    2. K1 进入闹钟 App,K1 再次进入编辑;K2/K3 增减小时/分钟;K1 提交保存并写入 Flash
    3. 在闹钟触发时,任意按键停止响铃;K4 在触发时会同时触发退出

模块说明(源文件要点)

以下是项目中主要模块与职责:

  • main.c:系统初始化、APP 入口、模式切换(APP_MODE_*)、全局 background tick 与事件循环
  • bsp_systick.c:系统定时(毫秒级)用于按键去抖、动画、tick 等
  • display.c:ST7920 LCD 的驱动与帧缓冲,提供绘制 API(像素/位图/字形等),并实现 display_flush_rows 刷写函数
  • fonts.c:字模资源(8x16、12x24、16x16、4x16 等),主要用于界面绘制
  • keypad.c:按键去抖、短长按识别与事件队列(按键事件由 keypad_take_events 取走)
  • buzzer.c:基于 GPIO 的蜂鸣器(支持短时维持与方波)
  • rtc_ds3231.c:DS3231 的 bit-banged I2C 驱动(PB13, PB14);支持读取/写入时间、温度
  • gps_gtu8.c:通过 USART0 解析 NMEA(RMC)消息,提取 UTC 时间(应用层自行做时区/本地化)
  • flash_storage.c:双槽原子写入策略,保存 flash_storage_blob_t(包含 hourly_chime, gps_sync, alarm info)
  • 子应用 (*_app.c):每个应用实现自己的 init, enter, loop, exit, background_tick 接口,便于主循环切换。

构建与烧写(快速上手)

项目默认使用 Keil/MDK 构建 (Project 文件位于 Project/):

  1. 打开 Project/MyGD32F30X.uvprojx(Keil uVision5)
  2. 选择目标芯片(GD32F30x)并配置工具链
  3. 编译(按 F7 或 Build)
  4. 烧录:使用 Keil flash 配置或你使用的设备(例如 ST-Link、J-Link)

VS Code / EIDE 任务:

  • Workspace 中包含 VSCode 任务(可通过 Terminal -> Run Task):
    • build:构建工程
    • flash:烧录到设备
    • build and flash:编译并烧录
    • rebuild:clean + build
    • clean:清理构建

注意:Keil 工程(.uvprojx)里定义了 Target/Linker/Upload 设置;若要使用命令行编译,请使用 Keil 提供的 nrf 或 armcc 工具链/包装。

使用 EIDE / VS Code 构建(推荐)

本仓库使用 EIDE(或 EIDE 插件)作为默认的构建工具链,工程在 build/ 目录下包含用于 EIDE 的 builder.paramscompile_commands.json 等配置文件:

  • 打开 VSCode 工作区(GD32F303Clock.code-workspace)。
  • 通过 Terminal -> Run Task 运行以下预定义任务(在工作区中):
    • build:仅编译项目
    • flash:把编译产物烧录到设备
    • build and flash:编译并烧写
    • rebuild:重新构建(clean + build)
    • clean:清理生成文件

注意:Project/*.uvprojx 提供 Keil/MDK 兼容性(如果你要在 Keil 中打开工程)。在本项目中 uvprojx 文件通常没有必要显式配置头文件包含路径,因为 EIDE 的构建参数(builder.paramscompile_commands.json)负责包含目录、宏等构建环境。换言之,uvprojx 对于 EIDE 构建不是必需的(但保留做兼容与 Keil 工具链使用)。

若你想在 Keil 中编译,请按需在 uvprojx 中手动配置 include 目录与编译宏。


持久化(Flash)与配置保存

  • flash_storage.c 提供 flash_storage_init / flash_storage_load / flash_storage_save 接口。
  • 保存内容为 flash_storage_blob_t(定义在 flash_storage.h),包含:magic、version、hourly_chime、gps_sync、alarm_hour、alarm_minute、enabled、crc 等字段。
  • 采用双槽(A/B)策略实现原子更新,支持回滚。

调试建议与开发说明

  • 调试串口:当前项目未包含通用日志输出接口。若需要打印调试信息,请使用 usart(例如 USART1)或板上调试器。
  • 修改配置(例如时区或默认闹钟)可在 clock_app.c 中更改 TIME_ZONE_OFFSETalarm_app 默认时间。
  • 增加图标或语言:fonts.c 提供字模数组,若要添加汉字或图标请在 fonts.cfonts.h 中添加相应的数据。
  • 如果遇到 LCD 花屏/不刷新的情况,请先检查 display_init 中的复位与 GDRAM 清屏序列。
  • DS3231 I2C 时序使用软件 bit-banged;若需要改用硬件 I2C,请将底层实现替换到 rtc_ds3231.c 或添加条件编译。

贡献说明与开发流程

  • 代码风格:模块化、每个应用拥有自己的 init/enter/loop/exit;无需绕过主循环
  • 提交:请在提交中写清变更点,尽量在每个子模块上添加注释与单元测试(若可行)
  • 新特性:添加新的 UI 页或外设时,建议遵循现有模块化接口与 UI 事件模型

常见问题 & FAQ

Q: 为什么显示模糊/图标残留?

  • 检查 display_flush_rows 是否正在刷新对应区块;如需强制刷新使用 display_flush_rows(0, DISPLAY_HEIGHT - 1)

Q: DS3231 读取失败或时间不对?

  • 检查 PB13/PB14 是否正确连接到 RTC;并确保 I2C pull-up 电阻存在。
  • GPS 授时依赖 config.gps_sync 开关。

Q: 如何修改默认时间/闹钟?

  • 修改 alarm_app 的默认值(alarm_reset_state)或使用 settings_app 的保存机制在运行时做配置。

联系与致谢

  • 作者/维护者:Steven
  • 硬件参考:GD32F30x 数据手册、ST7920 LCD、DS3231 RTC、GT-U8 GPS 模块
  • 感谢 zhdzhd 提供的字模取模软件 PCtoLCD2018
  • 感谢 Gemini 提供技术支持和问题分析

附录:按键映射(按应用) 🔎

以下表格总结了在不同页面下 K1..K4 的典型行为:

应用 K1 K2 K3 K4
主界面(Clock) 短按:进入编辑/启动选中功能;长按:提交编辑 视情况:编辑增加/选择功能左移 视情况:编辑减少/选择功能右移 短按:切换光标行(日期→时间→功能);长按:进入表盘
秒表(Stopwatch) 短按:开始/停止;长按:重置 短按:在非 lap_view 时添加圈次;在 lap_view 时翻页 切换 lap_view / 返回主秒表界面 退出页面
倒计时(Countdown) 短按:进入/推进编辑/开始;长按快速开始或退出编辑 编辑时增加位/预置左(或切换) 编辑时减少位/预置右(或切换) 隐藏页/退出
闹钟(Alarm) 短按:进入编辑/切换启用;长按:用于退出编辑 编辑时增加当前位/切换 编辑时减少当前位/切换 短按:退出/确认;长按:退出并返回
设置(Settings) 切换选项(ON/OFF,并保存) 上移选项 下移选项 退出设置

小贴士:K1 为“确认/进入/切换”的惯用键,K2/K3 为“增/减或左/右”的操作,K4 为“返回/切换行/进入表盘”。

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors