STM32的电子钟功能实现

一、系统架构设计

1.1 硬件组成框图

graph TD A[STM32F103C8T6] --> B[OLED0.96] A --> C[按键矩阵] A --> D[蜂鸣器] B --> I2C总线 C --> EXTI中断

1.2 核心模块划分

  • 时间管理:SysTick定时器中断(1ms精度)
  • 显示驱动:SSD1306 OLED中文显示
  • 用户交互:4x4矩阵键盘+外部中断
  • 电源管理:低功耗模式(待机模式)

二、硬件配置实现

2.1 时钟配置(SystemClock_Config)

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  // 72MHz
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInit, FLASH_LATENCY_2);
}

2.2 OLED驱动配置(I2C接口)

// SSD1306初始化
void SSD1306_Init(void)
{
    SSD1306_WriteCommand(0xAE); // 关闭显示
    SSD1306_WriteCommand(0x20); // 设置内存地址模式
    SSD1306_WriteCommand(0x00); // 水平地址模式
    SSD1306_WriteCommand(0xB0); // 设置页起始地址
    SSD1306_WriteCommand(0xC8); // 设置COM输出扫描方向
    SSD1306_WriteCommand(0x00); // 设置低位列地址
    SSD1306_WriteCommand(0x10); // 设置高位列地址
    SSD1306_WriteCommand(0x40); // 设置起始行地址
    SSD1306_WriteCommand(0x81); // 设置对比度
    SSD1306_WriteCommand(0xFF); // 对比度最大值
    SSD1306_WriteCommand(0xA1); // 设置段重定向
    SSD1306_WriteCommand(0xA6); // 正常显示
    SSD1306_WriteCommand(0xA8); // 设置多路复用率
    SSD1306_WriteCommand(0x3F); // 1/64 duty
    SSD1306_WriteCommand(0xD3); // 设置显示偏移
    SSD1306_WriteCommand(0x00); // 无偏移
    SSD1306_WriteCommand(0xD5); // 设置显示时钟分频
    SSD1306_WriteCommand(0x80); // 建议比值
    SSD1306_WriteCommand(0xD9); // 设置预充电周期
    SSD1306_WriteCommand(0xF1); // 预充电周期值
    SSD1306_WriteCommand(0xDA); // 设置COM硬件引脚配置
    SSD1306_WriteCommand(0x12); // 配置值
    SSD1306_WriteCommand(0xDB); // 设置VCOMH
    SSD1306_WriteCommand(0x40); // VCOMH电压值
    SSD1306_WriteCommand(0x8D); // 设置电荷泵
    SSD1306_WriteCommand(0x14); // 启用电荷泵
    SSD1306_WriteCommand(0xAF); // 开启显示
}

三、时间管理系统

3.1 SysTick中断服务程序

volatile uint32_t ms_ticks = 0;

void SysTick_Handler(void)
{
    HAL_IncTick();
    ms_ticks++;
}

// 时间结构体
typedef struct {
    uint8_t hours;
    uint8_t minutes;
    uint8_t seconds;
} TimeTypeDef;

TimeTypeDef current_time = {0, 0, 0};

// 时间更新函数
void Update_Time(void)
{
    if(ms_ticks >= 1000) {
        ms_ticks = 0;
        current_time.seconds++;
        if(current_time.seconds >= 60) {
            current_time.seconds = 0;
            current_time.minutes++;
            if(current_time.minutes >= 60) {
                current_time.minutes = 0;
                current_time.hours++;
                if(current_time.hours >= 24) {
                    current_time.hours = 0;
                }
            }
        }
    }
}

四、OLED中文显示实现

4.1 GB2312字库加载

// 定义字库数组(示例:0x00-0x0F为数字和字母)
const uint8_t Font_GB2312[] = {
    0x00, 0x7E, 0x11, 0x11, 0x11, 0x7E, // 0
    0x38, 0x44, 0x44, 0x44, 0x38, 0x00, // 1
    // ... 其他字符数据
};

// 显示字符串函数
void OLED_ShowString(uint8_t x, uint8_t y, char* str)
{
    while(*str) {
        OLED_DisplayChar(x, y, *str++);
        x += 8;
    }
}

// 显示中文字符(需扩展字库)
void OLED_DisplayChinese(uint8_t x, uint8_t y, uint16_t code)
{
    uint8_t page, col;
    for(page=0; page<8; page++) {
        OLED_SetCursor(x, y+page);
        OLED_WriteData(Font_GB2312[code*16 + page]);
    }
}

五、按键交互系统

5.1 矩阵键盘扫描

#define KEY_MATRIX_ROWS 4
#define KEY_MATRIX_COLS 4

GPIO_TypeDef* row_ports[4] = {GPIOA, GPIOA, GPIOA, GPIOA};
uint16_t row_pins[4] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3};

GPIO_TypeDef* col_ports[4] = {GPIOB, GPIOB, GPIOB, GPIOB};
uint16_t col_pins[4] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3};

// 扫描函数
char Matrix_Key_Scan(void)
{
    for(uint8_t col=0; col<4; col++) {
        // 拉低当前列
        HAL_GPIO_WritePin(col_ports[col], col_pins[col], GPIO_PIN_RESET);
        
        for(uint8_t row=0; row<4; row++) {
            if(HAL_GPIO_ReadPin(row_ports[row], row_pins[row]) == GPIO_PIN_RESET) {
                while(HAL_GPIO_ReadPin(row_ports[row], row_pins[row]) == GPIO_PIN_RESET); // 消抖
                return (col<<4) | row; // 返回键值
            }
        }
        HAL_GPIO_WritePin(col_ports[col], col_pins[col], GPIO_PIN_SET);
    }
    return 0xFF; // 无按键
}

5.2 外部中断配置

// EXTI回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == KEY_ADJUST_PIN) {
        // 进入时间调整模式
        time_adjust_mode = 1;
        adjust_counter = 0;
    }
}

六、主程序流程

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    SSD1306_Init();
    
    // 初始化时间
    current_time.hours = 12;
    current_time.minutes = 0;
    current_time.seconds = 0;
    
    while(1)
    {
        // 时间更新
        Update_Time();
        
        // 显示时间
        OLED_Clear();
        OLED_ShowString(0,0, "Time:");
        OLED_DisplayString(32,0, "HH:MM:SS");
        OLED_DisplayString(0,2, "Current:");
        OLED_DisplayString(32,2, "XX:XX:XX");
        
        // 按键处理
        char key = Matrix_Key_Scan();
        if(key != 0xFF) {
            switch(key) {
                case KEY_MODE:   // 模式切换
                    time_adjust_mode ^= 1;
                    break;
                case KEY_UP:     // 增加时间
                    Adjust_Time(1);
                    break;
                case KEY_CONFIRM: // 确认设置
                    time_adjust_mode = 0;
                    break;
            }
        }
    }
}

参考代码 STM32电子钟功能 www.youwenfan.com/contentcnh/56377.html

七、扩展功能实现

8.1 闹钟功能

typedef struct {
    uint8_t enable;
    uint8_t hours;
    uint8_t minutes;
} AlarmTypeDef;

AlarmTypeDef alarm = {0, 7, 30}; // 7:30闹钟

// 闹钟检测
void Check_Alarm(void)
{
    if(!alarm.enable) return;
    
    if(current_time.hours == alarm.hours &&
       current_time.minutes == alarm.minutes &&
       current_time.seconds == 0) {
        BEEP_ON(); // 触发蜂鸣器
        HAL_Delay(30000); // 持续30秒
        BEEP_OFF();
    }
}

8.2 日期显示扩展

typedef struct {
    uint8_t year;
    uint8_t month;
    uint8_t day;
} DateTypeDef;

DateTypeDef current_date = {24, 9, 2025}; // 2025-09-24

// 日期显示函数
void OLED_ShowDate(uint8_t x, uint8_t y)
{
    char date_str[11] = "Date:2025-09-24";
    OLED_DisplayString(x, y, date_str);
}
posted @ 2025-09-18 10:16  康帅服  阅读(19)  评论(0)    收藏  举报