一、系统概述与核心功能
1. 系统定位
基于STM32的电子钟与万年历以“精准计时-日期管理-人机交互-低功耗续航”为核心,实现实时时间(时/分/秒)、完整日期(年/月/日/星期)、闰年自动判断、闹钟提醒、温度监测(可选)及多模式显示,支持按键/旋转编码器设置,适用于家庭、办公室、教室等场景,替代传统石英钟/纸质日历,提供智能化时间管理方案。
2. 核心功能模块
| 模块 | 功能描述 |
|---|---|
| 时间基准 | 实时时钟(RTC)提供精准时间(年/月/日/时/分/秒/星期),支持断电走时(纽扣电池备份) |
| 日期管理 | 自动计算闰年、每月天数,支持农历转换(可选),显示节气/节日(扩展) |
| 显示输出 | OLED/LCD显示时间、日期、星期、温度(可选),支持多界面切换(时间/日历/闹钟) |
| 用户交互 | 按键/旋转编码器设置时间、闹钟,蜂鸣器提示(闹钟/操作反馈),LED状态指示 |
| 数据存储 | 存储闹钟设置、用户偏好(如亮度),支持掉电保存(EEPROM/Flash) |
| 低功耗设计 | 待机时关闭非必要模块(显示/传感器),STM32进入STOP模式,续航≥6个月(纽扣电池) |
二、硬件设计方案
1. 核心硬件选型
| 模块 | 型号 | 关键参数 | 接口方式 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6 | 72MHz Cortex-M3,64KB Flash,20KB RAM,I2C、SPI、UART,支持低功耗模式 | 核心控制器 |
| 实时时钟 | DS3231 | 精度±2ppm(±1分钟/年),I2C接口,内置温度补偿,纽扣电池(CR2032)备份 | I2C1(PB6=SCL,PB7=SDA) |
| 显示模块 | OLED 12864(I2C) | 0.96寸,128×64像素,自发光,低功耗(<10mA),显示时间/日期/温度 | I2C1(复用DS3231) |
| 输入模块 | 旋转编码器+轻触按键 | 编码器(调节时间/音量),按键(设置/确认/返回),上拉输入,消抖处理 | GPIO(PA0-PA2编码器,PC0-PC1按键) |
| 温度传感器 | DS18B20(可选) | 单总线接口,测温范围-55~125℃,精度±0.5℃,数字输出 | GPIO(PA1,单总线) |
| 电源模块 | CR2032纽扣电池+AMS1117 | 3V纽扣电池(RTC备份),5V Micro USB供电(主电源),AMS1117-3.3V稳压 | 双电源供电(主电源优先) |
| 辅助模块 | 蜂鸣器+LED | 有源蜂鸣器(5V,85dB),LED(红/绿双色,电源/闹钟状态) | GPIO(PB0=蜂鸣器,PB1=LED) |
2. 硬件电路设计要点
2.1 核心电路连接
- STM32最小系统:8MHz外部晶振+32.768kHz RTC晶振(DS3231共享),SWD调试接口(PA13/PA14),复位电路(10kΩ上拉+0.1μF电容)。
- DS3231 RTC:VCC=3.3V,SCL=PB6,SDA=PB7,INT/SQW引脚(PA3,闹钟中断输出),纽扣电池座(CR2032,并联二极管防倒灌)。
- OLED显示:VCC=3.3V,SCL=PB6,SDA=PB7(与DS3231复用I2C总线,地址区分:DS3231=0x68,OLED=0x3C)。
- 旋转编码器:A相=PA0,B相=PA1,Z相(按压)=PA2,上拉电阻10kΩ,检测旋转方向与步数。
2.2 低功耗设计
- 双电源切换:主电源(5V)正常时给系统供电并为纽扣电池充电(通过二极管隔离),主电源断开时自动切换至纽扣电池(仅维持RTC运行)。
- 模块电源控制:OLED、DS18B20通过MOS管(AO3400)控制供电,待机时关闭,按键/编码器中断唤醒后开启。
三、软件设计与核心代码
1. 系统架构(轮询+中断)
采用前后台系统(无RTOS),以主循环轮询为主,中断处理按键/编码器/闹钟事件,核心流程:
- 初始化:配置时钟、I2C、GPIO、RTC、显示模块。
- 主循环:读取RTC时间/日期→更新显示→扫描按键/编码器→处理设置/闹钟。
- 中断服务:外部中断(编码器旋转/按键)、RTC闹钟中断(触发蜂鸣器)。
2. 核心代码实现(基于标准库)
2.1 DS3231 RTC驱动(I2C通信)
#include"ds3231.h"#include"i2c.h"// DS3231寄存器地址#defineDS3231_SEC0x00// 秒#defineDS3231_MIN0x01// 分#defineDS3231_HOUR0x02// 时#defineDS3231_WEEK0x03// 星期#defineDS3231_DATE0x04// 日#defineDS3231_MON0x05// 月#defineDS3231_YEAR0x06// 年#defineDS3231_CTRL0x0E// 控制寄存器#defineDS3231_STATUS0x0F// 状态寄存器// 写DS3231寄存器voidDS3231_WriteReg(uint8_treg,uint8_tval){HAL_I2C_Mem_Write(&hi2c1,0x68<<1,reg,1,&val,1,100);}// 读DS3231寄存器uint8_tDS3231_ReadReg(uint8_treg){uint8_tval;HAL_I2C_Mem_Read(&hi2c1,0x68<<1,reg,1,&val,1,100);returnval;}// 设置时间(时/分/秒,BCD码)voidDS3231_SetTime(uint8_thour,uint8_tmin,uint8_tsec){DS3231_WriteReg(DS3231_SEC,sec);// 秒(BCD码,如30秒=0x30)DS3231_WriteReg(DS3231_MIN,min);// 分DS3231_WriteReg(DS3231_HOUR,hour);// 时(24小时制)}// 读取时间(返回BCD码,需转换为十进制)voidDS3231_ReadTime(uint8_t*hour,uint8_t*min,uint8_t*sec){*sec=DS3231_ReadReg(DS3231_SEC);*min=DS3231_ReadReg(DS3231_MIN);*hour=DS3231_ReadReg(DS3231_HOUR);}// 设置日期(年/月/日/星期,BCD码)voidDS3231_SetDate(uint8_tyear,uint8_tmonth,uint8_tdate,uint8_tweek){DS3231_WriteReg(DS3231_WEEK,week);// 星期(1-7,1=周日)DS3231_WriteReg(DS3231_DATE,date);// 日DS3231_WriteReg(DS3231_MON,month);// 月DS3231_WriteReg(DS3231_YEAR,year);// 年(后两位,如2023=0x23)}2.2 时间日期处理(闰年判断+星期计算)
// BCD码转十进制uint8_tbcd2dec(uint8_tbcd){return(bcd>>4)*10+(bcd&0x0F);}// 十进制转BCD码uint8_tdec2bcd(uint8_tdec){return((dec/10)<<4)|(dec%10);}// 闰年判断(返回1=闰年,0=平年)uint8_tIs_LeapYear(uint16_tyear){if((year%4==0&&year%100!=0)||year%400==0)return1;return0;}// 计算每月天数(考虑闰年2月)uint8_tDays_In_Month(uint16_tyear,uint8_tmonth){uint8_tdays[]={31,28,31,30,31,30,31,31,30,31,30,31};if(month==2&&Is_LeapYear(year))return29;returndays[month-1];}// 计算星期(基姆拉尔森公式,返回0-6=周日-周六)uint8_tCalc_Weekday(uint16_tyear,uint8_tmonth,uint8_tday){if(month<3){month+=12;year--;}return(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7;}2.3 OLED显示驱动(时间/日期界面)
#include"oled.h"#include"font.h"// 字库(6x8/8x16 ASCII)// OLED写命令/数据voidOLED_WriteCmd(uint8_tcmd){HAL_I2C_Mem_Write(&hi2c1,0x3C<<1,0x00,1,&cmd,1,100);}voidOLED_WriteData(uint8_tdata){HAL_I2C_Mem_Write(&hi2c1,0x3C<<1,0x40,1,&data,1,100);}// 清屏voidOLED_Clear(void){for(uint8_tpage=0;page<8;page++){OLED_WriteCmd(0xB0+page);// 页地址OLED_WriteCmd(0x00);// 列低4位OLED_WriteCmd(0x10);// 列高4位for(uint8_tcol=0;col<128;col++)OLED_WriteData(0x00);}}// 显示时间(时:分:秒,居中)voidOLED_ShowTime(uint8_thour,uint8_tmin,uint8_tsec){charstr[9];sprintf(str,"%02d:%02d:%02d",bcd2dec(hour),bcd2dec(min),bcd2dec(sec));OLED_ShowString(40,2,str,16);// 第2页(16x16字体),x=40居中}// 显示日期(年-月-日 星期X)voidOLED_ShowDate(uint8_tyear,uint8_tmonth,uint8_tdate,uint8_tweek){char*week_str[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};charstr[20];sprintf(str,"20%02d-%02d-%02d %s",bcd2dec(year),bcd2dec(month),bcd2dec(date),week_str[week]);OLED_ShowString(10,4,str,16);// 第4页}2.4 主程序框架(时间更新+显示+按键处理)
#include"stm32f1xx_hal.h"#include"ds3231.h"#include"oled.h"#include"key.h"// 按键/编码器驱动intmain(void){HAL_Init();SystemClock_Config();// 72MHzMX_I2C1_Init();// I2C1(DS3231+OLED)OLED_Init();// OLED初始化DS3231_Init();// RTC初始化(检查电池,设置初始时间)Key_Init();// 按键/编码器初始化OLED_Clear();uint8_thour,min,sec,year,month,date,week;while(1){// 1. 读取RTC时间日期DS3231_ReadTime(&hour,&min,&sec);DS3231_ReadDate(&year,&month,&date,&week);// 需补充DS3231_ReadDate函数// 2. 更新显示OLED_ShowTime(hour,min,sec);OLED_ShowDate(year,month,date,week);// 3. 按键处理(设置时间/闹钟)Key_Process();// 扫描按键,处理设置逻辑// 4. 低功耗处理(无操作5分钟后进入STOP模式)if(idle_time>300){// 5分钟=300秒OLED_Clear();HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);// 进入STOP模式SystemClock_Config();// 唤醒后重新配置时钟}HAL_Delay(200);// 200ms刷新一次}}参考代码 基于STM32的电子钟与万年历设计www.youwenfan.com/contentcst/133691.html
四、关键技术与优化
1. 时间精度保障
- DS3231温度补偿:内置温度传感器实时校准晶振频率,年误差<1分钟,无需频繁校时。
- 软件校时:通过GPS/网络(如ESP8266)获取标准时间,定期校准RTC(如每天一次)。
2. 显示优化
- 多界面切换:通过按键切换“时间界面”“日历界面”“闹钟设置界面”,日历界面显示月视图(高亮当天)。
- 亮度调节:旋转编码器控制OLED对比度(通过I2C发送指令
0x81, 0-255)。
3. 低功耗设计
- STOP模式配置:进入STOP模式前关闭OLED、I2C时钟,仅保留RTC和按键中断(PA0-PA2),唤醒后恢复时钟和外设。
- 纽扣电池管理:主电源断开时,DS3231自动切换至纽扣电池供电(电流<1μA),确保时间持续走时。
五、系统调试与扩展
1. 调试步骤
| 阶段 | 操作 | 工具 |
|---|---|---|
| 硬件调试 | 测量I2C信号(SCL/SDA)、DS3231电压(3.3V) | 示波器、万用表 |
| RTC校时 | 用串口打印DS3231时间,对比标准时钟 | 串口助手、标准时钟 |
| 显示测试 | 显示固定字符串,检查OLED是否缺画/花屏 | 肉眼观察、逻辑分析仪(I2C波形) |
| 低功耗测试 | 进入STOP模式,测量纽扣电池电流(应<1μA) | 万用表(电流档,串联测量) |
2. 扩展功能
- 农历显示:添加农历算法(如查表法),在日历界面叠加显示农历日期/节气。
- 世界时间:通过按键切换不同时区(如UTC+8、UTC-5),显示多城市时间。
- 蓝牙同步:添加HC-05模块,通过手机APP设置时间、闹钟,同步日程。
- 环境光感应:添加光敏电阻,自动调节OLED亮度(白天高亮,夜晚低亮)。