FRDM-MCXN236 RTC 电子时钟项目总结报告
一、项目介绍
本项目基于 NXP FRDM-MCXN236 开发板,实现了一个使用片上 RTC 外设的电子时钟系统。项目最初来源于 NXP 提供的多平台 Demo,但原 Demo 面向多个开发板并包含 Mikroe 旋钮模块相关功能,和本项目目标并不一致。因此在开发过程中对工程进行了清理,只保留 FRDM-MCXN236 相关工程配置和必要驱动文件,删除原有旋钮模块逻辑,将软件功能重新设计为一个独立的 RTC 电子时钟应用。
项目最终实现的功能包括:使用 MCXN236 片上 RTC 获取系统日期和时间;通过串口实时显示年月日、时分秒;使用开发板自带的 SW2、SW3 两个用户按键进入设置模式并调整时间;支持年、月、日、时、分、秒逐项设置;支持加一和减一两个调整方向;在串口终端中使用控制字符将时间显示固定在同一行刷新,避免每秒打印一行造成刷屏;同时保留必要的启动和控制日志,便于观察系统运行状态。
本项目的设计目标是尽量不依赖外部模块,只使用 FRDM-MCXN236 板载资源完成电子时钟功能。对于掉电保持功能,软件已经使用 RTC 的 VBAT 域时钟和时间寄存器;硬件上如果需要在开发板断开 USB 或主电源后时间仍然继续运行,需要给 MCU 的 VDD_BAT/VDD_VBAT 网络增加独立备份供电,例如纽扣电池。当前板子未安装电池时,拔掉主供电后 RTC 无法继续走时。
二、使用到的硬件介绍
本项目使用的主要硬件如下:
- FRDM-MCXN236 开发板
FRDM-MCXN236 是 NXP 面向 MCX N 系列 MCU 的开发板,板载 MCXN236 微控制器、MCU-Link 调试器、USB 串口、用户按键、RGB LED 以及 Arduino、mikroBUS 等扩展接口。本项目只使用主控 MCU、板载调试下载接口、虚拟串口和两个用户按键,不使用外接旋钮模块。 - MCXN236 片上 RTC
MCXN236 内部带 RTC 外设,具备日期和时间寄存器,可保存秒、分、时、日、月、年偏移等信息。本项目通过直接访问 RTC 寄存器完成时间读取和写入,并使用 RTC 的 16 kHz 时钟源保持计时。 - 板载 SW2 和 SW3 用户按键
两个按键用于人机交互。由于按键数量有限,项目采用“模式选择 + 方向切换 + 数值调整”的设计:SW2 用于进入设置、选择字段和切换加减方向,SW3 用于调整当前字段。 - 板载 USB 虚拟串口
开发板通过 MCU-Link 提供 USB CDC 虚拟串口,本项目使用 LPUART4 作为调试串口,波特率为 115200。用户可通过 VS Code Serial Monitor、Tera Term、MobaXterm 等串口工具观察当前时间和操作状态。 - RTC 备份电源接口
根据 FRDM-MCXN236 原理图,目标 MCU 的VDD_BAT引脚连接到VDD_VBAT网络,默认通过R76 0R与VDD_MCU相连。因此默认情况下 VBAT 来自主 3.3V 电源。若要实现真正断电保持,需要断开 R76,并给VDD_VBAT单独接入 3V 纽扣电池或其他合规备份电源,电池负极接 GND。


三、方案框图和设计思路
系统整体框图如下:
+---------------------------+
USB 供电/调试 -> | FRDM-MCXN236 |
| |
| +---------------------+ |
SW2 ----------> | | GPIO 按键扫描 | |
SW3 ----------> | | 消抖/长按/连发识别 | |
| +----------+----------+ |
| | |
| v |
| +---------------------+ |
| | 时间设置状态机 | |
| | RUN/SET_YEAR/... | |
| | UP/DOWN | |
| +----------+----------+ |
| | |
| v |
| +---------------------+ |
| | RTC 读写 | |
| | 年月日时分秒 | |
| +----------+----------+ |
| | |
| v |
| +---------------------+ |
| | LPUART 串口输出 | ----> PC 串口终端
| +---------------------+ |
+---------------------------+
可选备份电源:
CR2032 + -> VDD_VBAT
CR2032 - -> GND
R76 断开,避免电池反向给整板供电
设计思路分为四部分。
第一部分是 RTC 初始化。系统启动后初始化板级引脚、系统时钟、调试串口和按键 GPIO,然后打开 RTC 时钟门控,释放 RTC 复位,并将 16 kHz 时钟同时送到 VBAT 域和主域。这样 RTC 外设在正常运行时能够访问,在后续增加备份电池后也具备掉电保持的硬件基础。
第二部分是时间读取和显示。主循环不断读取 RTC 当前时间,当秒值变化时刷新一次串口时间行。时间格式为 YYYY-MM-DD HH:MM:SS,在运行模式显示 [RUN],在设置模式显示当前字段和调整方向,例如 [SET_MIN UP] 或 [SET_DAY DOWN]。
第三部分是按键交互。SW2 和 SW3 经过软件消抖,并支持短按、长按和长按连发。最终交互方式如下:
SW2 长按:在 RUN 模式下进入 SET_YEAR,方向默认为 UP
SW2 短按:选择设置项,顺序为 YEAR -> MONTH -> DAY -> HOUR -> MIN -> SEC -> RUN
SW2 长按:在设置模式下切换 UP/DOWN
SW3 短按:按当前方向调整当前字段一次
SW3 长按:按当前方向连续调整当前字段
第四部分是串口显示优化。普通串口日志使用换行保留历史信息;时间显示使用 \r 回到行首,并使用 ANSI 控制序列 ESC[2K 清除当前行,再输出新的时间。这样时间每秒刷新时只占一行,不会形成大量重复日志。若设置过程中有控制日志输出,程序会先清除当前时间行,再输出日志,然后重新显示时间行。
四、调试软件介绍、软件流程图及关键代码介绍
本项目主要使用的软件工具包括:
- VS Code 和 NXP MCUXpresso 插件
用于导入、配置和构建 MCUX CMake 工程。开发过程中遇到过 SDK 关联、CMake Presets、Debug 目录缓存、链接脚本路径等问题,最终将工程整理为可由 MCUX 插件直接识别和构建的 FRDM-MCXN236 单板工程。
安装了如下几个插件:MCUXpresso SDK Developer,Arm GNU Toolchain,LinkServer,SEGGER J-Link,PEmicro
- ARM GNU Toolchain
使用arm-none-eabi-gcc编译 Cortex-M33 裸机程序。当前工程可以通过 CMake/Ninja 构建生成frdm-mcxn236-rtc-clock.elf。 - NXP LinkServer
用于通过板载 MCU-Link 调试器下载程序到 MCXN236。下载后使用 hard reset 让程序从用户 Flash 正常启动。 - 串口终端工具
使用 115200 波特率观察启动日志、RTC 状态和当前时间。由于项目使用 ANSI 控制字符刷新同一行,推荐使用支持 ANSI 的串口终端。
软件主流程如下:
开始
|
v
初始化引脚、时钟、调试串口
|
v
初始化 SW2/SW3 GPIO、LED
|
v
初始化 RTC
|
+-- RTC 无效?-- 是 --> 写入默认时间 2026-01-01 12:00:00
| |
| 否
v
读取 RTC 当前时间并显示
|
v
主循环
|
+--> 扫描 SW2/SW3,识别短按、长按、连发
|
+--> SW2 长按:
| RUN 模式进入 SET_YEAR
| 设置模式切换 UP/DOWN
|
+--> SW2 短按:
| 切换设置字段,最后回到 RUN
|
+--> SW3 按下:
| 根据当前字段和方向修改 RTC 时间
|
+--> RTC 秒变化:
刷新串口时间行
关键代码主要集中在 Common/main.c。
RTC 初始化函数 ClockRtc_Init() 负责开启 RTC 访问权限、打开 RTC 时钟门控、释放 RTC 复位、配置 16 kHz 时钟,并判断 RTC 时间是否有效。如果 RTC 状态无效,则写入默认时间;如果 RTC 保持有效,则输出 RTC retained time is valid,说明当前时间来自 RTC 保持域。
RTC 读取函数 ClockRtc_Get() 从 RTC 寄存器读取 SECONDS、HOURMIN、DAYS 和 YEARMON,解析为 clock_datetime_t 结构体中的年、月、日、时、分、秒字段。RTC 写入函数 ClockRtc_Set() 根据用户调整后的时间重新计算星期,然后写入 RTC 日期和时间寄存器。
由于 RTC 有写保护机制,项目实现了 ClockRtc_SetWriteProtection(),通过官方示例中的 8 位写序列关闭 RTC 写保护,解决了早期调试中“时间显示临时变化,但 RTC 实际寄存器未写入,随后又跳回原时间”的问题。
按键处理函数 Buttons_Update() 实现了消抖、短按、长按和长按连发识别。主循环通过 Button_ConsumeShortPress()、Button_ConsumeLongPress() 和 Button_ConsumeRepeatPress() 消费按键事件,使按键行为清晰可控。
时间设置状态机由 clock_mode_t 表示,包括 RUN、SET_YEAR、SET_MONTH、SET_DAY、SET_HOUR、SET_MINUTE 和 SET_SECOND。调整方向由 adjust_direction_t 表示,包括 UP 和 DOWN。Clock_AdjustSelectedField() 根据当前状态决定修改哪个字段,并调用 Clock_WrapAdjust() 或 Clock_WrapAdjustYear() 实现环形加减。例如小时从 23 继续加会回到 0,从 0 继续减会回到 23;月份从 12 加回到 1,从 1 减回到 12;日期会根据当前年月自动限制在合法天数内。
串口显示函数 Clock_Display() 使用控制字符刷新同一行:
"\r\033[2KTime %04u-%02u-%02u %02u:%02u:%02u [%s]"其中 \r 表示回到行首,\033[2K 表示清除整行。这样电子时钟在串口终端里表现为固定位置不断更新,更接近真实时钟显示效果。
五、功能展示图及说明
项目运行后,串口终端启动信息如下:
FRDM-MCXN236 RTC electronic clock
Firmware build: Jul 27 2026 xx:xx:xx
SW2 short: select year-month-day-hour-minute-second-run, SW2 long: enter set/toggle up-down
SW3 short: adjust selected field, SW3 long: repeat adjust
RTC retained time is valid
Time 2026-07-27 13:25:08 [RUN]
进入设置模式后,长按 SW2 可以从运行模式进入年份设置:
Time 2026-07-27 13:25:08 [SET_YEAR UP]
短按 SW2 可以依次切换设置项:
Time 2026-07-27 13:25:08 [SET_MONTH UP]
Time 2026-07-27 13:25:08 [SET_DAY UP]
Time 2026-07-27 13:25:08 [SET_HOUR UP]
Time 2026-07-27 13:25:08 [SET_MIN UP]
Time 2026-07-27 13:25:08 [SET_SEC UP]
在任意设置项中长按 SW2,可将方向从 UP 切换为 DOWN;此时短按或长按 SW3 会执行减一操作。例如分钟字段处于 DOWN 时,按 SW3 后分钟会减少:
Time 2026-07-27 13:24:08 [SET_MIN DOWN]
继续短按 SW2,状态机会回到 RUN 模式:
Time 2026-07-27 13:24:08 [RUN]
板载 RGB LED 也用于辅助提示设置字段:设置小时、分钟、秒时分别点亮不同颜色;设置年、月、日时使用不同颜色组合。这样即使不看串口,也能大致判断当前处于运行模式还是设置模式。
六、项目中遇到的难题及解决方法
第一个问题是原始 Demo 工程结构复杂。NXP 原 Demo 支持多个平台,并且包含外接 Mikroe 旋钮模块逻辑。项目目标只需要 FRDM-MCXN236 电子时钟,因此需要删除其他板卡工程和旋钮相关代码,重新整理 CMake、MCUX 工程配置和源码路径。清理后工程更简单,也更适合在 VS Code 中维护。
第二个问题是 VS Code MCUX 插件导入工程时无法识别 SDK 或找不到源码。早期工程中 Common/main.c 是引用路径,导入到新目录后 CMake 仍然指向旧的公共目录,导致配置时报错。解决方法是将源码真正纳入当前工程目录,并完善 CMakePresets、mcux_include 和工程配置,使工程具有明确的目标 MCU、板卡和 SDK 关联。
第三个问题是按键无效。最初串口打印显示 Button raw levels: SW2=0 SW3=0,按键长按和短按都没有反应。经过检查发现 SW2/SW3 的 GPIO 宏定义和实际 pin_mux 不一致,同时 GPIO 时钟未正确打开。修正 SW2/SW3 引脚映射,并在按键初始化中开启 GPIO0、GPIO4 时钟后,按键恢复正常。
第四个问题是 RTC 初始化卡死。程序在配置 16 kHz RTC 时钟时停止运行。参考 NXP 官方 RTC 示例后发现,时钟需要同时送到 VBAT 域和 MAIN 域,即使用 kCLOCK_Clk16KToVbat | kCLOCK_Clk16KToMain。修改后 RTC 初始化可以正常完成,串口开始稳定输出时间。
第五个问题是 RTC 写保护。调试中按 SW3 修改分钟或秒时,串口显示临时增加,但随后又跳回原时间,并打印 RTC write protected, set ignored。原因是 RTC 寄存器写保护未正确解除。后续根据官方示例使用 8 位写序列解除写保护,RTC 写入才真正生效。
第六个问题是两按键交互设计。只有 SW2、SW3 两个按键,但需要完成进入设置、选择字段、加、减和连续调整。最终采用长短按复用:SW2 长按在 RUN 下进入设置,在设置模式下切换方向;SW2 短按选择字段;SW3 负责调整数值。这个方案不需要外接按键,操作逻辑也比较统一。
第七个问题是串口显示刷屏。最初每秒打印一行时间,长时间运行后串口窗口会充满重复信息。最终使用 ANSI 控制字符将时间固定在同一行刷新,同时保留启动和控制日志,显示效果更接近电子时钟。
七、心得体会
通过本项目可以体会到,嵌入式开发并不只是写应用逻辑,很多时间花在工程配置、板级资源确认和外设细节调试上。一个看似简单的 RTC 电子时钟,实际涉及 CMake 工程整理、SDK 关联、GPIO 时钟、引脚复用、RTC 时钟源、写保护、安全访问规则、串口输出和用户交互设计等多个方面。
本项目比较有价值的一点是充分利用了开发板已有资源,没有为了时间调整额外增加扩展按键,而是通过短按、长按和状态机完成完整交互。这种设计在实际产品中也很常见:硬件资源有限时,软件交互逻辑需要更加清晰,用户操作也要尽量避免歧义。
另一个收获是对 RTC 掉电保持有了更明确的认识。软件使用 RTC 外设并不等于天然具备断电保持能力,关键还要看 VBAT 域是否有独立供电。FRDM-MCXN236 默认将 VDD_VBAT 接到主 MCU 电源,方便普通开发调试;如果要实现真正断电走时,就必须增加备份电池,并注意不能让电池反向给整板供电。
最终,项目完成了从原始多平台 Demo 到单板 RTC 电子时钟应用的转换,实现了时间显示、时间设置、串口单行刷新和 RTC 保持能力验证。整个过程也说明,在做开发板项目时,先读原理图、再看 SDK 示例、最后结合实际板子调试,是比较可靠的开发路径。