一、系统架构设计
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; // 72MHzHAL_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 dutySSD1306_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); // 设置VCOMHSSD1306_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, // 00x38, 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 4GPIO_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 &¤t_time.minutes == alarm.minutes &¤t_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);
}