目录
引言
系统时钟是嵌入式系统中不可或缺的一部分,广泛应用于工业控制、智能家居、物联网等领域。STM32F103C8T6(俗称“最小系统板”)是一款基于 ARM Cortex-M3 内核的微控制器,具有高性能、低功耗和丰富的外设资源,非常适合用于实现系统时钟功能。本文将详细介绍如何利用 STM32F103C8T6 设计并实现一个功能完善的系统时钟,包括时间显示、时间调整、闹钟功能和时间校准等。
硬件设计
1. STM32F103C8T6 简介
STM32F103C8T6 是意法半导体(STMicroelectronics)推出的一款 32 位 ARM Cortex-M3 微控制器,具有以下特点:
-
主频最高 72MHz
-
内置 64KB Flash 和 20KB SRAM
-
支持多种通信接口(如 UART、SPI、I2C)
-
内置定时器、ADC 和 DAC
-
支持低功耗模式
2. 硬件连接
为了实现系统时钟功能,需要以下硬件组件:
-
STM32F103C8T6 开发板
-
LCD 显示屏(如 1602 或 OLED)
-
按键模块(用于时间调整)
-
时钟晶振(12MHz)
-
备用电池(可选,用于掉电后保持时间)
硬件连接如下:
-
LCD 显示屏通过 I2C 或并行接口连接到 STM32
-
按键模块连接到 GPIO 引脚
-
时钟晶振连接到 STM32 的 OSC_IN 和 OSC_OUT 引脚
-
备用电池连接到 RTC(实时时钟)模块(如果使用)
软件设计
1. 开发环境
使用 STM32CubeMX 进行硬件配置,生成初始化代码,然后在 Keil uVision 或 STM32CubeIDE 中进行编程。
2. 时钟源配置
STM32F103C8T6 的时钟系统包括多个时钟源:
-
HSI(高速内部时钟,8MHz)
-
HSE(高速外部时钟,12MHz)
-
LSI(低速内部时钟,40kHz)
-
LSE(低速外部时钟,32.768kHz,用于 RTC)
为了实现高精度的时间计时,通常使用 LSE 晶振(32.768kHz)作为 RTC 的时钟源。
3. RTC 配置
RTC(实时时钟)模块用于记录时间,配置步骤如下:
-
启用 LSE 晶振
-
配置 RTC 时钟源为 LSE
-
初始化 RTC,设置初始时间
-
启用 RTC 中断(可选,用于定时更新显示)
4. LCD 显示
使用 LCD 显示屏显示当前时间,可以使用 1602 LCD 或 OLED 屏幕。通过 GPIO 或 I2C 接口与 STM32 进行通信。
5. 按键处理
按键模块用于调整时间,通常包括以下功能:
-
设置年、月、日、时、分、秒
-
启动/停止闹钟
-
校准时间
功能实现
1. 时间显示
通过 RTC 获取当前时间,并在 LCD 上显示。显示格式为:YYYY-MM-DD HH:MM:SS
。
2. 时间调整
通过按键调整时间:
-
按键 1:进入设置模式
-
按键 2:切换设置项(年、月、日、时、分、秒)
-
按键 3:增加当前设置项的值
-
按键 4:保存并退出设置模式
3. 闹钟功能
设置闹钟时间,当当前时间与闹钟时间匹配时,触发闹钟事件(如蜂鸣器报警)。
4. 时间校准
由于晶振可能存在误差,可以通过按键或外部信号对时间进行校准。
代码实现
以下是基于 STM32F103C8T6 的系统时钟代码实现。
1. 主程序
#include "main.h"
#include "stm32f10x.h"
#include "lcd.h"
#include "rtc.h"
#include "key.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
LCD_Init();
Key_Init();
while (1)
{
Key_Scan();
Display_Time();
HAL_Delay(100);
}
}
3.按键处理
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOA, KEY1_Pin | KEY2_Pin | KEY3_Pin | KEY4_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = KEY1_Pin | KEY2_Pin | KEY3_Pin | KEY4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Key_Scan(void)
{
static uint8_t key_state = 0;
uint8_t key = 0;
if (HAL_GPIO_ReadPin(KEY1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(20);
if (HAL_GPIO_ReadPin(KEY1_Pin) == GPIO_PIN_RESET)
{
key = 1;
}
while (HAL_GPIO_ReadPin(KEY1_Pin) == GPIO_PIN_RESET);
}
if (key != 0)
{
switch (key)
{
case 1:
// 进入设置模式
break;
case 2:
// 切换设置项
break;
case 3:
// 增加当前设置项
break;
case 4:
// 保存并退出
break;
}
}
}
4.显示时间
void Display_Time(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
char time_str[17];
sprintf(time_str, "%04d-%02d-%02d %02d:%02d:%02d",
2000 + sDate.Year,
sDate.Month,
sDate.Date,
sTime.Hours,
sTime.Minutes,
sTime.Seconds);
LCD_ShowString(0, 0, time_str);
}
测试与优化
1. 测试
对系统时钟进行以下测试:
-
时间显示是否正确
-
时间调整功能是否正常
-
闹钟功能是否触发
-
掉电后时间是否保持(如果使用备用电池)
2. 优化
-
降低功耗:使用低功耗模式
-
提高精度:校准晶振误差
-
增加功能:添加温度补偿、网络校时等
总结与展望
本文介绍了如何使用 STM32F103C8T6 实现一个系统时钟,包括硬件设计、软件设计和功能实现。通过合理的硬件配置和软件设计,可以实现一个功能完善的系统时钟。未来可以进一步优化功耗,增加更多功能,如网络校时、数据记录等,以满足更多应用场景的需求。