Funpack5-4 -基于FRDM-MCXN236的电子时钟实现
该项目使用了FRDM-MCXN236,实现了电子时钟的设计,它的主要功能为:1、RTC 实时走时 2、OLED 显示(时、分、秒、日期、中文星期) 3、按键时间调整 4、串口时间输出 5、掉电后时间保持。。 该项目使用了工程基于 MCUXpresso IDE v25.6 开发,,实现了C 语言编写,源码分为 main.c、ssd1306.c/h 与 board_config.h 四个文件,SDK 外设驱动(LPSPI、LPFLEXCOMM 等)的设计,它的主要功能为:undefined。
标签
Funpack活动
破伞
更新2026-10-19
4

FRDM-MCXN236电子时钟
项目总结报告

目 录

1  项目介绍

2  方案框图与设计思路

3  硬件介绍

4  调试软件介绍、软件流程图及关键代码

4.1  调试软件

4.2  软件流程图

4.3  关键代码介绍

5  功能展示图及说明

6  项目中遇到的难题及解决方法

7  心得体会

1  项目介绍

本项目基于NXP FRDM-MCXN236开发板设计并实现了一款具备掉电保持能力的电子时钟系统。系统以芯片内置IRTC实时时钟为时基,采用0.96英寸SSD1306 OLED显示屏实时显示当前时间、日期与星期,通过两个按键完成年、月、日、时、分、秒的逐项校时,并通过串口以115200波特率输出时间信息。为保证掉电后时间不丢失,系统将时间备份到开发板板载W25Q64 SPI NOR Flash,上电后自动恢复。

系统功能包括:

1、RTC实时走时

2、OLED显示(时、分、秒、日期、中文星期)

3、按键时间调整

4、串口时间输出

5、掉电后时间保持。

工程基于MCUXpresso IDE v25.6开发,采用C语言编写,源码分为main.c、ssd1306.c/h与board_config.h四个文件,SDK外设驱动(LPSPI、LPFLEXCOMM等)随工程拷贝,便于在IDE中直接导入编译。

2  方案框图与设计思路

系统整体方案如图1所示:MCX N236作为控制核心,向上读取内置IRTC获取时间;向下驱动SSD1306 OLED完成显示;按键SW2、SW3提供人机交互输入;LPUART4串口负责调试信息与时间输出;W25Q64 SPI Flash承担掉电备份存储。

 image.png

图1  系统方案框图

设计思路遵循模块化与分层原则:应用层只负责时间逻辑、按键状态机与显示策略,驱动层封装IRTC、I2C、SPI、串口等外设操作,二者通过board_config.h中的引脚与参数宏解耦,便于移植。

掉电保持采用“主动备份+上电恢复”策略:设置时间成功后立即保存一次,此后每1分钟周期保存一次,将时间写入W25Q的固定扇区;上电时先读IRTC,若读出的时间无效(超出合法范围,如复位初值2111-15-31 31:63:63),则从Flash恢复最近一次保存的时间。为提高系统健壮性,运行中还加入了无效时间过滤(连续5秒无效才重新恢复)与OLED I2C通信失败自动重初始化兜底,保证显示异常时系统仍能自动恢复。

3  硬件介绍

系统所用硬件以FRDM-MCXN236开发板为核心,外接OLED显示模块与按键,复用板载SPI Flash与串口,硬件接线示意图如图2所示。OLED模块支持5 V供电,所以OLED电源与地线取自mikroBUS J5的Pin7(P5V0,5 V!)与Pin8(GND),其I2C信号SCL为J5引脚5(P4_1)、SDA为引脚6(P4_0),通过LPI2C2(FC2)工作于400 kHz,地址0x3C。W25Q64挂在LPSPI6(FC6)上,P3_20(SDO)、P3_21(SCK)、P3_22(SDI)、P3_23(PCS0)分别连接Flash的DI、CLK、DO、CS引脚,SPI通信速率为4 MHz。按键、串口与Flash等外设按3.3 V电平接入。

image.png 

图2  系统硬件接线示意图

硬件清单如表1所示。

表1  硬件清单

器件

型号/参数

用途

主控开发板

FRDM-MCXN236(MCX N236,Cortex-M33,150 MHz)

系统控制与逻辑处理

实时时钟

IRTC(芯片内置,独立低频时钟)

秒级走时与时基

OLED显示屏

SSD1306,0.96英寸,128×64,I2C地址0x3C

时间、日期、星期显示

按键

SW2(P0_20)、SW3(P0_6),按下为低

校时模式切换与数值调整

串口

LPUART4,115200-8-N-1

调试日志与时间输出

SPI Flash

W25Q64JVSSIQ(U12,8 MB,SPI NOR)

掉电时间备份与恢复

4  调试软件介绍、软件流程图及关键代码

4.1  调试软件

开发与调试在MCUXpresso IDE v25.6中进行。该IDE集成了代码编辑、编译、烧录与调试功能,本项目通过LinkServer将生成的hex固件下载到开发板;编译采用IDE headless命令行模式验证,构建结果为0 errors、0 warnings。串口调试使用通用串口助手,以115200-8-N-1参数监视启动日志与时间输出,用于定位运行期问题。

4.2  软件流程图

软件主流程如图3所示。上电后依次完成时钟与引脚、IRTC、SPI Flash、时间恢复、OLED的初始化,随后进入主循环:喂看门狗、扫描按键并处理校时状态机、每秒更新时钟(读IRTC、过滤无效时间、串口输出、周期保存),检测到OLED通信异常时自动重初始化。

image.png 

图3  软件主流程示意图

4.3  关键代码介绍

(1)RTC实时走时。系统以MCXN236内置IRTC作为时基,初始化时将内部16 kHz FRO时钟接入VBAT域,即使主电源掉电、VBAT供电时RTC仍可独立计时;同时使能IRTC秒级报警中断作为看门狗,主循环每秒喂狗,一旦卡死超过1秒立即自动复位自愈。主循环每秒通过IRTC_GetDatetime读取时间,读回值经IsTimeValid合法性校验,无效值(复位初值、读毛刺)直接丢弃并沿用上次有效时间,代码如下。

static void Board_InitRtc(void)

{

    irtc_config_t cfg;

    /*内部16k FRO接入VBAT域,掉电后RTC继续走时*/

    CLOCK_SetupClk16KClocking(kCLOCK_Clk16KToVbat | kCLOCK_Clk16KToMain);

    IRTC_GetDefaultConfig(&cfg);

    (void)IRTC_Init(RTC, &cfg);

}

 

void RTC_IRQHandler(void)   /*秒中断:主循环超过1秒未喂狗即复位自愈*/

{

    if ((IRTC_GetStatusFlags(RTC) & kIRTC_AlarmFlag) != 0U)

    {

        IRTC_ClearStatusFlags(RTC, kIRTC_AlarmFlag);

        if (!s_wdFeed) NVIC_SystemReset();

        s_wdFeed = false;

        ArmWatchdogAlarm();          /*重新arm 1秒后的alarm */

    }

}

(2)OLED显示(时、分、秒、日期、中文星期)。显示刷新由UpdateDisplay完成,显示屏为SSD1306(I2C 0x3C,128×64)。如图4所示,第0行以2倍字模居中显示日期YYYY-MM-DD;第2行x=5、y=22以2倍字模显示HH:MM:SS,其右侧x=110用8×8中文字模2倍显示中文星期(星期由CalcWeekDay按年月日自动算出,不提供手动修改);状态行(RUN、SET YEAR等)2倍字模居中显示,校时过程中正在调整的字段每500 ms闪烁提示;屏幕左下角显示I加I2C失败次数、右下角显示F加1 Hz心跳计数,便于在线排查,代码如下。

/*第0行:日期YYYY-MM-DD,2倍字模居中(x=4, y=0)*/

SSD1306_DrawString(4U, 0U, dateStr, 2U);

/*第2行:HH:MM:SS(x=5, y=22)+中文星期(x=110)*/

SSD1306_DrawString(5U, 22U, t, 2U);

SSD1306_DrawCN(110U, 22U, (uint8_t)(CalcWeekDay(s_now.year, s_now.month, s_now.day) - 1U), 2U);

/*状态行:2倍字模水平居中*/

SSD1306_DrawString((uint8_t)((128U - (uint8_t)(len * 12U)) / 2U), 42U, pStatus, 2U);

image.png 

图4  OLED实际显示效果

 

(3)按键时间调整。SW2(MODE,P0_20)与SW3(ADJ,P0_6)经软件消抖扫描后进入校时状态机:RUN → SET YEAR → SET MONTH → SET DAY → SET HOUR → SET MINUTE → SET SECOND,每按一次SW2切换一个字段;SW3将当前字段加一(年2026~2100、月1~12、日按当月天数并处理闰年、星期根据年月日自动换算,时0~23、分/秒0~59)。设置完秒后再次按SW2确认退出校时,立即调用RtcCommit将时间写回IRTC并保存Flash备份,串口输出time set OK,代码如下。

case MODE_SET_SEC:

    if (BtnPressed(SW3)) s_now.second = (s_now.second + 1U) % 60U;

    if (BtnPressed(SW2)) {        /*确认退出校时*/

        RtcCommit();              /*写回IRTC + Flash备份*/

        s_mode = MODE_RUN;

        UartPuts("[CLOCK] time set OK\r\n");

    }

break;

 

校时状态机如图5和图6所示运行态下按SW2依次进入年、月、日、时、分、秒的设置,SW3对当前字段加一,设置完成后再次按SW2确认并立即保存时间。

image.png 

图5  校时按键状态机示意图

image.png 

图6按键设定

(4)串口时间输出。通过LPUART4(FC4)以115200 bit/s输出调试信息。UartPuts采用轮询TX寄存器方式逐字符发送,内置超时保护,硬件异常时自动重新初始化外设自愈,绝不永久卡死主循环;每秒由SerialLogTime格式化输出一行时间心跳YYYY-MM-DD W HH:MM:SS I<n> F<n>,其中W为星期、I为I2C失败次数、F为1 Hz心跳计数,如图7所示,代码如下。

static void SerialLogTime(void)

{

    char buf[34]; uint8_t i = 0U;

    /*年月日、星期、时分秒逐位手动补零,避免库函数开销*/

    buf[i++] = (char)('0' + (s_now.year / 1000U) % 10U);

    buf[i++] = (char)('0' + wd);

    buf[i++] = (char)('0' + s_now.hour / 10U);

    buf[i++] = (char)('0' + s_now.second % 10U);

    buf[i++] = ' '; buf[i++] = 'I';

    buf[i++] = (char)('0' + SSD1306_GetI2cFailCount());

    buf[i++] = ' '; buf[i++] = 'F';

    buf[i++] = (char)('0' + s_diagFrame);

    buf[i++] = '\r'; buf[i++] = '\n'; buf[i] = '\0';

    UartPuts(buf);

}

       image.png

图7串口显示数据

 

(5)掉电后时间保持。时间通过板载W25Q64 SPI Flash持久保存:FlashSaveTime将时间打包写入最后一个4 KB扇区的16个256 B槽位(带magic校验),写满16槽才擦除一次,兼顾Flash擦写寿命;上电时RtcLoad检测到IRTC时间无效(如无VBAT电池导致RTC域未初始化)即从Flash反向扫描恢复最新有效备份并写回IRTC,如图8;正常运行每60秒自动备份一次,如图9;校时确认时立即备份,如图10,因此掉电最多丢失1分钟,代码如下。

/*周期备份:RUN模式每60秒写一次Flash,掉电最多丢1分钟*/

if ((uint32_t)(s_msTicks - s_lastSaveTick) >= 60000U)

{

    s_lastSaveTick = s_msTicks;

FlashSaveTime();

 

}

image.png 

 

图8上电读取W25Q64 数据

 

image.png 

图9  每60秒自动备份时间到W25Q64

image.png 

图10 校时确认时立即备份

5  功能展示图及说明

图11为OLED显示效果示意图(按128×64点阵等比例还原,黑底蓝字像素风):第一行(x=4, y=0)显示日期;第二行以2倍字号显示“时:分:秒”(x=5, y=22),右侧x=110显示2倍中文星期;y=42处以2倍字号居中显示状态行RUN(运行)或SET(校时,如SET HOUR);左下角I0为I2C通信计数、右下角F7为Flash保存计数,便于现场观察通信状态。 图4为OLED实际显示效果实拍图,蓝色像素点亮显示日期、时间、星期、状态行与I/F诊断计数。

image.png 

图11  OLED显示效果示意图

系统通过LPUART4(FC4)以115200 bit/s向串口输出运行信息:开机自检提示、每秒时间心跳(含I2C失败计数与Flash保存计数)、按键校时状态提示、时间保存与设置成功日志等,便于实时观察程序运行与调试。图12为XCOM V2.2串口助手实测输出界面,图中以不同颜色区分开机自检、时间心跳、校时提示与保存日志。

image.png 

图12  串口显示信息示意(终端日志)

主要功能展示说明如下:

(1)正常走时:上电初始化后每秒更新一次显示,秒位跳动,串口同步输出“2026-10-15 19:06:15 I0 F2”格式日志;

(2)按键校时:短按SW2依次进入SET YEAR、SET MONTH、SET DAY、SET HOUR、SET MINUTE、SET SECOND,SW3对当前字段加一,当前字段以0.5 s周期闪烁提示;设置完成回到RUN并立即保存;

(3)掉电保持:拔电再上电后,IRTC读出无效时间时自动从W25Q恢复最近保存值,时间连续不丢;

(4)自动恢复:OLED通信因线缆接触不良中断时,程序检测到连续I2C失败后自动重初始化,恢复后约2 s内重新点亮。

6  项目中遇到的难题及解决方法

开发过程中遇到的典型问题及解决方法如表2所示。

表2  典型难题与解决方法

难题

现象

原因

解决方法

OLED显示乱码

字符镜像、缺笔画

5×7字模列/行序被改写

重排字模,恢复标准列行顺序

校时到秒后卡死

SET SECOND后界面停顿约3 s

内部Flash编程命令受保护,等待超时(FSTAT=0x900)

改用板载W25Q保存时间,弃用内部Flash

W25Q读ID全FF

读不到芯片ID,无法保存

LPSPI每8位帧间PCS拉高,命令被丢弃

使能kLPSPI_MasterPcsContinuous连续模式

串口出现脏时间

复位后偶现2111-15-31 31:63:63

IRTC计数寄存器复位初值

增加IsTimeValid过滤,无效值沿用上次有效值

OLED运行中黑屏

程序正常但显示中断

杜邦线接触不良导致I2C失败

I2C失败计数达9次自动重初始化并重画

复位进入HardFault

访问PORT3时报总线错误

时钟门控顺序与安全/非安全地址混淆

调整门控顺序并统一使用NS别名地址

以“校时卡死”为例,该问题曾持续困扰多轮调试:现象为设置到最后一位秒后界面不再刷新。通过串口日志与心跳计数确认程序并未死机,而是执行了耗时约3 s的Flash编程等待;进一步检查FSTAT寄存器值为0x900,其CMDPRT位表明内部Flash命令保护出厂配置为“安全特权访问”,非安全应用程序的擦写命令永远不会完成。查明原因后,将时间备份改走板载W25Q SPI Flash,问题彻底解决,并顺带获得了更大的存储空间与更灵活的保存策略。

7  心得体会

通过本项目的完整开发,我对嵌入式系统设计有了更深入的体会。一是分层调试是排查问题的利器:例如W25Q读不到ID时,先确认芯片接线与供电,再用GPIO位带模拟(bit-bang)软SPI读取,得到正确的芯片ID(EF 40 17),从而把问题精确锁定在LPSPI的片选时序配置而非硬件,最终一眼定位到PCS连续模式缺失。二是健壮性设计要落到代码:无效时间过滤、通信失败计数与自动重初始化、看门狗等“软件兜底”,看似增加代码量,却让系统在真实环境(线缆松动、上电毛刺)下依然可靠,这正是嵌入式产品与实验板程序的重要区别。三是在方案层面要学会权衡:内部Flash虽方便,但受保护限制与擦写寿命约束,改用板载外部Flash并设计“设置确认+ 1分钟周期”的保存策略,在数据安全与Flash寿命之间取得了平衡。四是善用工具链:IDE headless命令行编译、串口日志打点、心跳计数观察,让每一轮修改都能快速验证,显著提升了调试效率。

附件下载
MCXN236_RTC_Clock_v15.zip
完整代码文件
团队介绍
破伞
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号