基于STM32的桌面Mini时钟设计

一、系统概述与核心功能

1. 系统定位

基于STM32的桌面Mini时钟以"精准计时-环境感知-智能显示-低功耗续航"为核心,集成高精度RTC时钟、温湿度监测、自动亮度调节、闹钟提醒于一体,打造小巧精致、功能实用的桌面摆件,适用于卧室、书房、办公室等场景,替代传统电子钟,提供智能化时间管理体验。

2. 核心功能模块

模块 功能描述
精准计时 DS3231高精度RTC,±2ppm精度(年误差<1分钟),支持闰年自动判断、12/24小时制切换
环境感知 SHT30温湿度传感器,实时监测环境温度(-40125℃)和湿度(0100%RH)
智能显示 0.96寸OLED(128×64),支持时间/日期/温湿度同屏显示、自动亮度调节、屏保模式
闹钟提醒 3组可编程闹钟,支持贪睡功能(5/10/15分钟),蜂鸣器+LED闪光提醒
用户交互 3个触摸按键(设置/上调/下调),长按/短按组合操作,操作反馈震动提示
低功耗设计 待机电流<1mA,Micro USB供电+CR1220纽扣电池备份,断电不停走

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数 接口方式
主控MCU STM32F030F4P6 48MHz Cortex-M0,16KB Flash,4KB RAM,小封装TSSOP20,极致性价比 核心控制器
实时时钟 DS3231 ±2ppm精度,I2C接口,内置温度补偿,CR1220纽扣电池备份(断电走时3年) I2C1(PB6=SCL,PB7=SDA)
温湿度传感器 SHT30 ±0.3℃/±2%RH精度,I2C接口,16位分辨率,DFN封装(3×3mm) I2C1(复用DS3231总线)
显示模块 OLED 12864(I2C) 0.96寸,128×64像素,自发光,对比度10000:1,可视角度>160° I2C1(复用总线,地址0x3C)
交互模块 TTP223触摸按键×3 单通道触摸IC,低功耗(5μA),感应距离0-8mm,替代机械按键 GPIO(PA0-PA2,外部中断)
提醒模块 有源蜂鸣器+WS2812 LED 蜂鸣器(5V,85dB),WS2812(RGB全彩,单线控制),闹钟时闪光提醒 GPIO(PB0=蜂鸣器,PB1=LED)
电源模块 Micro USB+ME6211+HT7333 5V USB供电→ME6211降压至3.3V→HT7333稳压至3.3V(低纹波),CR1220电池备份 双电源供电(自动切换)

2. 硬件电路设计要点

2.1 核心电路连接(极致紧凑设计)
复制代码
STM32F030F4P6(TSSOP20)
├── I2C1总线(PB6=SCL,PB7=SDA)
│   ├── DS3231(RTC,地址0x68)
│   ├── SHT30(温湿度,地址0x44)
│   └── OLED(显示,地址0x3C)
├── GPIO输入(PA0-PA2)
│   ├── TTP223_1(设置键)
│   ├── TTP223_2(上调键)
│   └── TTP223_3(下调键)
├── GPIO输出(PB0-PB1)
│   ├── 蜂鸣器(闹钟提醒)
│   └── WS2812(RGB氛围灯)
└── 电源系统
    ├── Micro USB(5V输入)
    ├── ME6211(5V→3.3V)
    ├── HT7333(3.3V稳压)
    └── CR1220(RTC备份电池)
2.2 低功耗设计亮点
  • 双电源自动切换:主电源(USB 5V)正常时给系统供电并为纽扣电池充电;主电源断开时,DS3231自动切换至纽扣电池(仅维持计时,电流<1μA)。
  • 动态背光控制:OLED亮度根据环境光自动调节(通过SHT30温度数据间接推算环境光,或外接光敏电阻),夜间自动降低亮度。
  • 触摸唤醒:待机时STM32进入STOP模式(电流<10μA),触摸按键中断唤醒。

三、软件设计与核心代码

1. 系统架构(前后台系统)

采用前后台系统(无RTOS),以主循环为前台,中断为后台,核心流程:

  1. 初始化:配置时钟、I2C、GPIO、RTC、显示模块。
  2. 主循环
    • 读取RTC时间/日期 → 读取温湿度 → 更新OLED显示 → 检查闹钟触发。
    • 扫描触摸按键 → 处理设置/调整操作 → 更新系统状态。
  3. 中断服务:触摸按键中断(唤醒系统)、RTC闹钟中断(触发提醒)。

2. 核心代码实现(基于标准库)

2.1 DS3231 RTC驱动(I2C通信)
c 复制代码
#include "ds3231.h"
#include "i2c.h"

// DS3231寄存器地址
#define DS3231_SEC   0x00  // 秒
#define DS3231_MIN   0x01  // 分
#define DS3231_HOUR  0x02  // 时(Bit6=12/24小时制)
#define DS3231_WEEK  0x03  // 星期(1-7)
#define DS3231_DATE  0x04  // 日
#define DS3231_MON   0x05  // 月
#define DS3231_YEAR  0x06  // 年(后两位)
#define DS3231_ALARM1 0x07  // 闹钟1
#define DS3231_CONTROL 0x0E  // 控制寄存器

// BCD码与十进制互转
uint8_t bcd2dec(uint8_t bcd) { return (bcd>>4)*10 + (bcd&0x0F); }
uint8_t dec2bcd(uint8_t dec) { return ((dec/10)<<4) | (dec%10); }

// 设置时间(24小时制)
void DS3231_SetTime(uint8_t hour, uint8_t min, uint8_t sec) {
    uint8_t buf[3];
    buf[0] = dec2bcd(sec);
    buf[1] = dec2bcd(min);
    buf[2] = dec2bcd(hour) & 0x3F;  // Bit6=0(24小时制)
    HAL_I2C_Mem_Write(&hi2c1, 0x68<<1, DS3231_SEC, 1, buf, 3, 100);
}

// 读取时间
void DS3231_ReadTime(uint8_t *hour, uint8_t *min, uint8_t *sec) {
    uint8_t buf[3];
    HAL_I2C_Mem_Read(&hi2c1, 0x68<<1, DS3231_SEC, 1, buf, 3, 100);
    *sec = bcd2dec(buf[0]);
    *min = bcd2dec(buf[1]);
    *hour = bcd2dec(buf[2] & 0x3F);  // 屏蔽12/24小时制位
}

// 设置闹钟(每天定时)
void DS3231_SetAlarm(uint8_t hour, uint8_t min) {
    uint8_t buf[4];
    buf[0] = dec2bcd(min);          // 分
    buf[1] = dec2bcd(hour) & 0x3F; // 时(24小时制)
    buf[2] = 0x80;                  // 日(不关心)
    buf[3] = 0x80;                  // 星期(不关心)
    HAL_I2C_Mem_Write(&hi2c1, 0x68<<1, DS3231_ALARM1, 1, buf, 4, 100);
    
    // 使能闹钟中断
    uint8_t ctrl = 0x05;  // INTCN=1(中断输出),A1IE=1(闹钟1使能)
    HAL_I2C_Mem_Write(&hi2c1, 0x68<<1, DS3231_CONTROL, 1, &ctrl, 1, 100);
}
2.2 SHT30温湿度驱动(I2C通信)
c 复制代码
#include "sht30.h"
#include "i2c.h"

// SHT30测量命令(高重复精度)
#define SHT30_MEAS_HIGH 0x2400

// 读取温湿度
uint8_t SHT30_Read(float *temp, float *humi) {
    uint8_t cmd[2] = {SHT30_MEAS_HIGH>>8, SHT30_MEAS_HIGH&0xFF};
    uint8_t buf[6];
    
    // 发送测量命令
    if (HAL_I2C_Master_Transmit(&hi2c1, 0x44<<1, cmd, 2, 100) != HAL_OK)
        return 1;
    
    HAL_Delay(15);  // 等待测量完成(高重复精度需15ms)
    
    // 读取6字节数据(温度2B+CRC+湿度2B+CRC)
    if (HAL_I2C_Master_Receive(&hi2c1, 0x44<<1, buf, 6, 100) != HAL_OK)
        return 1;
    
    // 转换为物理量(参考SHT30 datasheet)
    uint16_t raw_temp = (buf[0]<<8) | buf[1];
    uint16_t raw_humi = (buf[3]<<8) | buf[4];
    *temp = -45 + 175 * (raw_temp / 65535.0f);  // ℃
    *humi = 100 * (raw_humi / 65535.0f);        // %RH
    
    return 0;  // 成功
}
2.3 OLED显示驱动(时间/温湿度同屏)
c 复制代码
#include "oled.h"
#include "font.h"  // 6x8/8x16 ASCII字库

// 显示时间(HH:MM:SS)
void OLED_ShowTime(uint8_t hour, uint8_t min, uint8_t sec) {
    char time_str[9];
    sprintf(time_str, "%02d:%02d:%02d", hour, min, sec);
    OLED_ShowString(32, 0, time_str, 16);  // 居中显示(128-64)/2=32
}

// 显示日期(YYYY-MM-DD 星期X)
void OLED_ShowDate(uint16_t year, uint8_t mon, uint8_t day, uint8_t week) {
    char date_str[20];
    char *week_str[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    sprintf(date_str, "20%02d-%02d-%02d %s", year, mon, day, week_str[week-1]);
    OLED_ShowString(8, 2, date_str, 12);  // 12号字体
}

// 显示温湿度
void OLED_ShowTempHumi(float temp, float humi) {
    char th_str[20];
    sprintf(th_str, "T:%.1fC H:%.1f%%", temp, humi);
    OLED_ShowString(16, 4, th_str, 12);  // 12号字体
}

// 显示闹钟图标(开启/关闭)
void OLED_ShowAlarmIcon(uint8_t alarm_on) {
    if (alarm_on) OLED_ShowChar(112, 0, '*', 16);  // 右上角显示*
    else OLED_ShowChar(112, 0, ' ', 16);           // 清空
}
2.4 触摸按键与闹钟提醒
c 复制代码
#include "touch_key.h"
#include "beep_led.h"

// 触摸按键扫描(PA0-PA2)
uint8_t TouchKey_Scan(void) {
    static uint8_t key_up = 1;  // 按键松开标志
    if (key_up && (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET ||
                   HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET ||
                   HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_SET)) {
        HAL_Delay(10);  // 消抖
        key_up = 0;
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) return 1;  // 设置键
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET) return 2;  // 上调键
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_SET) return 3;  // 下调键
    } else if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET &&
               HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET &&
               HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET) {
        key_up = 1;  // 所有按键松开
    }
    return 0;  // 无按键
}

// 闹钟提醒(蜂鸣器+LED闪烁)
void Alarm_Remind(uint8_t on_off) {
    static uint8_t led_state = 0;
    if (on_off) {
        // 蜂鸣器间歇响(0.5s响,0.5s停)
        static uint32_t beep_tick = 0;
        if (HAL_GetTick() - beep_tick > 500) {
            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);  // 蜂鸣器翻转
            beep_tick = HAL_GetTick();
        }
        // LED闪烁
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);  // WS2812翻转
        HAL_Delay(200);
    } else {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);  // 关闭蜂鸣器
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);  // 关闭LED
    }
}
2.5 主程序框架
c 复制代码
#include "stm32f0xx_hal.h"
#include "ds3231.h"
#include "sht30.h"
#include "oled.h"
#include "touch_key.h"
#include "beep_led.h"

// 系统状态
typedef enum {
    SYS_NORMAL = 0,    // 正常显示
    SYS_SET_HOUR,     // 设置小时
    SYS_SET_MIN,      // 设置分钟
    SYS_SET_ALARM    // 设置闹钟
} SysState;

SysState sys_state = SYS_NORMAL;
uint8_t alarm_on = 0;  // 闹钟开关
uint8_t alarm_hour = 7, alarm_min = 30;  // 默认闹钟7:30

int main(void) {
    HAL_Init();
    SystemClock_Config();  // 48MHz
    
    // 初始化外设
    MX_I2C1_Init();       // I2C1(DS3231/SHT30/OLED)
    MX_GPIO_Init();        // GPIO(触摸按键/蜂鸣器/LED)
    OLED_Init();          // OLED初始化
    DS3231_Init();        // RTC初始化(首次上电设置默认时间)
    SHT30_Init();         // 温湿度传感器初始化
    
    uint8_t hour, min, sec;
    uint8_t year, mon, day, week;
    float temp, humi;
    
    while (1) {
        // 1. 读取RTC时间日期
        DS3231_ReadTime(&hour, &min, &sec);
        DS3231_ReadDate(&year, &mon, &day, &week);
        
        // 2. 读取温湿度
        SHT30_Read(&temp, &humi);
        
        // 3. 更新OLED显示
        OLED_Clear();
        OLED_ShowTime(hour, min, sec);
        OLED_ShowDate(year, mon, day, week);
        OLED_ShowTempHumi(temp, humi);
        OLED_ShowAlarmIcon(alarm_on);
        
        // 4. 检查闹钟触发
        if (alarm_on && hour == alarm_hour && min == alarm_min && sec == 0) {
            Alarm_Remind(1);  // 触发闹钟
        } else {
            Alarm_Remind(0);  // 关闭闹钟
        }
        
        // 5. 触摸按键处理
        uint8_t key = TouchKey_Scan();
        switch (sys_state) {
            case SYS_NORMAL:
                if (key == 1) sys_state = SYS_SET_HOUR;  // 进入设置模式
                if (key == 2) alarm_on = !alarm_on;       // 开关闹钟
                break;
            case SYS_SET_HOUR:
                if (key == 2) hour = (hour + 1) % 24;    // 小时+1
                if (key == 3) hour = (hour + 23) % 24;   // 小时-1
                if (key == 1) sys_state = SYS_SET_MIN;     // 切换到分钟设置
                DS3231_SetTime(hour, min, sec);          // 保存时间
                break;
            case SYS_SET_MIN:
                if (key == 2) min = (min + 1) % 60;     // 分钟+1
                if (key == 3) min = (min + 59) % 60;    // 分钟-1
                if (key == 1) sys_state = SYS_NORMAL;     // 退出设置
                DS3231_SetTime(hour, min, sec);          // 保存时间
                break;
        }
        
        HAL_Delay(200);  // 200ms刷新一次
    }
}

参考代码 基于STM32的桌面mini时钟设计 www.youwenfan.com/contentcst/133652.html

四、关键技术与优化

1. 极致低功耗设计

  • STM32 STOP模式:无操作时进入STOP模式(电流<10μA),触摸按键中断唤醒,实测续航:CR1220电池可维持RTC走时3年以上。
  • OLED动态刷新:仅在时间/温湿度变化时刷新OLED,静止时关闭显示(屏保模式),触摸唤醒后恢复。
  • 传感器间歇工作:SHT30每10分钟采集一次温湿度(非连续工作),降低功耗。

2. 用户体验优化

  • 触摸按键反馈:短按/长按区分功能(短按切换设置项,长按保存退出),操作时LED微闪提示。
  • 自动亮度调节:根据SHT30温度数据间接推算环境光(温度越高环境越亮),自动调节OLED对比度(白天高亮,夜间低亮)。
  • 闹钟贪睡功能:闹钟响时短按任意键暂停5分钟,连续按3次彻底关闭闹钟。

五、系统调试与扩展

1. 调试步骤

阶段 操作 工具
硬件调试 测量DS3231纽扣电池电压(≥2.8V),I2C信号质量 万用表、示波器(SCL/SDA波形)
RTC校准 对比手机时间,调整DS3231老化偏移量 串口打印时间,对比标准时间
显示测试 显示固定字符,检查OLED是否有坏点/残影 肉眼观察,逻辑分析仪(I2C时序)
低功耗测试 待机时测量整机电流(应<1mA) 万用表(串联在电源回路)

2. 扩展功能

  • 温湿度历史曲线:添加EEPROM(AT24C02)存储24小时温湿度数据,OLED绘制简易曲线。
  • 天气图标显示:根据温湿度显示晴天/多云/雨天图标(如☀️/☁️/🌧️)。
  • USB自动校时:通过USB接口连接电脑,自动同步电脑时间到RTC(需开发PC端工具)。
  • 无线对时:添加BLE模块(如CC2541),通过手机APP设置时间/闹钟。

六、总结

基于STM32的桌面Mini时钟通过DS3231高精度RTC确保计时精准,SHT30温湿度传感器提供环境监测,OLED+触摸按键实现简洁交互,极致低功耗设计保障长久续航。

相关推荐
电化学仪器白超2 小时前
小乌龟Git全程图形化操作指南:嵌入式本地版本管理与Gitee私有云备份实战
git·python·单片机·嵌入式硬件·物联网·gitee·自动化
yong99904 小时前
基于STM32 Nucleo板的彩色LED照明灯设计(纯CubeMX开发)
stm32·单片机·嵌入式硬件
独小乐4 小时前
019.ADC转换和子中断|千篇笔记实现嵌入式全栈/裸机篇
linux·c语言·驱动开发·笔记·嵌入式硬件·mcu·arm
lingzhilab4 小时前
零知派——STM32驱动INA219电流功率监测计实现高精度电源管理
stm32·单片机·嵌入式硬件
QH139292318807 小时前
KEYSIGHT N9030B PXA信号/频谱分析仪
科技·嵌入式硬件·集成测试
Shang180989357268 小时前
T31ZX 君正/INGENIC智能视频处理器T31ZX可提供软硬件资料T31Z采用先进的低功耗设计
嵌入式硬件·fpga开发·音视频·t31zx智能视频处理器
ahccqw8 小时前
CAN总线通信入门及实例代码(stm32f4系列)
stm32·单片机·嵌入式硬件
云栖梦泽9 小时前
Linux内核与驱动:13.从设备树到Platform平台总线
linux·运维·c++·嵌入式硬件
振南的单片机世界9 小时前
电源、复位、时钟:单片机的“生存三要素”
单片机·嵌入式硬件