文章目录
- 一、基础知识点
- 二、开发环境
- 三、STM32CubeMX相关配置
- 四、Vscode代码讲解
- 五、结果演示
- 串口显示乱码解决方案
一、基础知识点
本实验通过stm32片内资源RTC实现实时时钟,通过数码管显示时间。设定闹钟,实现准点报时。
数码管相关知识点:
1、数码管 TM1620芯片手册 解析
2、数码管显示
RTC相关知识点:
1、RTC特点
(1)可编程的预分频系数:分频系数最高为2^20。
(2)32位的可编程计数器,可用于较长时间段的测量。
(3)2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上)。
(4)可以选择以下三种RTC的时钟源:
- HSE时钟除以128
- LSE振荡器时钟;
- LSI振荡器时钟
(5)2个独立的复位类型:
- APB1接口由系统复位;
- RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位。
(6)3个专门的可屏蔽中断:
- 闹钟中断,用来产生一个软件可编程的闹钟中断。
- 秒中断,用来产生一个可编程的周期性中断信号(最长可达1秒)。
- 溢出中断,指示内部可编程计数器溢出并回转为0的状态
2、RTC内部框图
灰色部分是后备区域,在设备断电后,可由纽扣电池供电。
后备区域包括(RTC时钟预分配器、计数器),这里注意的是闹钟,RTC溢出,秒中断在断电之后不起作用。
3、当断电之后CLK时钟是怎么产生的? ———— LSE时钟(纽扣电池供电)
二、开发环境
1、硬件开发准备
主控:STM32F103ZET6
芯片内部RTC
2、软件开发准备
软件开发使用虚拟机 + VScode + STM32Cube 开发STM32,在虚拟机中直接完成编译下载。
该部分可参考:软件开发环境构建
三、STM32CubeMX相关配置
1、STM32CubeMX基本配置
本实验基于CubeMX详解构建基本框架 进行开发。
2、STM32CubeMX RTC相关配置
(1)时钟配置
(2)RTC参数配置
(3)中断开启并配置
四、Vscode代码讲解
1、RTC相关结构体定义以及初始化
typedef struct
{
RTC_TimeTypeDef *pMyrtc_current_time;
RTC_DateTypeDef *pMyrtc_current_date;
void (*Myrtc_Set_Alarm_Time_Date)(void); // 设置闹钟时间
void (*Myrtc_Set_Current_Time_Date)(void); // 设置当前时间和日期
void (*Myrtc_Get_Current_Time_Date)(void); // 获取当前时间和日期
void (*Myrtc_Disp_Current_Time_Date)(void); // 打印当前时间和日期
} Myrtc_t;
extern Myrtc_t Myrtc;
Myrtc_t Myrtc ={
&RTC_TimeStruct_CurrentValue,
&RTC_DateStruct_CurrentValue,
Myrtc_Set_Alarm_Time_Date, // 设置闹钟时间
Myrtc_Set_Current_Time_Date, // 设置当前时间和日期
Myrtc_Get_Current_Time_Date, // 获取当前时间和日期
Myrtc_Disp_Current_Time_Date // 数码管打印当前时间和日期
};
2、函数具体实现
(1)获取当前时间和日期
static void Myrtc_Get_Current_Time_Date(void)
{
// 获取当前时间
HAL_RTC_GetTime(&hrtc, Myrtc.pMyrtc_current_time, RTC_FORMAT_BIN);
// 获取当前日期
HAL_RTC_GetDate(&hrtc, Myrtc.pMyrtc_current_date, RTC_FORMAT_BIN);
}
(2)数码管打印当前时间和日期
static void Myrtc_Disp_Current_Time_Date(void)
{
//串口打印日期
printf("当前时间为: %02u年%02d月%02d日(星期%s) ", 2000+Myrtc.pMyrtc_current_date->Year,Myrtc.pMyrtc_current_date->Month,Myrtc.pMyrtc_current_date->Date,Week_Str[Myrtc.pMyrtc_current_date->WeekDay]);
//串口打印时间
printf("%02u:%02u:%02u\r\n",Myrtc.pMyrtc_current_time->Hours,Myrtc.pMyrtc_current_time->Minutes,Myrtc.pMyrtc_current_time->Seconds);
// 数码管显示
Display.Disp(Disp_NUM_GRID1, Myrtc.pMyrtc_current_time->Hours/10, Disp_DP_OFF);
Display.Disp(Disp_NUM_GRID2, Myrtc.pMyrtc_current_time->Hours%10, Disp_DP_ON);
Display.Disp(Disp_NUM_GRID3, Myrtc.pMyrtc_current_time->Minutes/10, Disp_DP_OFF);
Display.Disp(Disp_NUM_GRID4, Myrtc.pMyrtc_current_time->Minutes%10, Disp_DP_ON);
Display.Disp(Disp_NUM_GRID5, Myrtc.pMyrtc_current_time->Seconds/10, Disp_DP_OFF);
Display.Disp(Disp_NUM_GRID6, Myrtc.pMyrtc_current_time->Seconds%10, Disp_DP_ON);
}
(3)设置当前时间和日期
// 设置时间
static void Myrtc_Set_Current_Date(void)
{
RTC_DateTypeDef RTC_DateStruct_SetValue;
uint8_t SetValue;
printf("=========================DWB日期设置==================\n");
printf("请输入年份(00-99): 20\n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(99);
}
printf("年份被设置为: 20%02u\n", SetValue);
RTC_DateStruct_SetValue.Year = SetValue;
getchar();
printf("请输入月份(01-12): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(12);
if(SetValue == 0x00)
{
printf("月份不能设置为0,请重新输入月份:\r\n");
SetValue = 0xFF;
}
}
printf("月份被设置为: %02u\n", SetValue);
RTC_DateStruct_SetValue.Month = SetValue;
getchar();
printf("请输入日期(01-31): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(31);
if(SetValue == 0x00)
{
printf("日期不能设置为0,请重新输入日期:\r\n");
SetValue = 0xFF;
}
}
printf("日期被设置为: %02u\r\n", SetValue);
RTC_DateStruct_SetValue.Date = SetValue;
getchar();
//设置日期
HAL_RTC_SetDate(&hrtc,&RTC_DateStruct_SetValue,RTC_FORMAT_BIN);
}
// 设置日历
static void Myrtc_Set_Current_Time(void)
{
RTC_TimeTypeDef RTC_TimeStruct_SetValue;
uint8_t SetValue;
printf("=========================DWB时间设置==================\n");
printf("请输入时钟(00-23): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(23);
}
printf("时钟被设置为: %02u\n", SetValue);
RTC_TimeStruct_SetValue.Hours = SetValue;
getchar();
printf("请输入分钟(00-59): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(59);
}
printf("分钟被设置为: %02u\n", SetValue);
RTC_TimeStruct_SetValue.Minutes = SetValue;
getchar();
printf("请输入秒钟(00-59): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(59);
}
printf("秒钟被设置为: %02u\n", SetValue);
RTC_TimeStruct_SetValue.Seconds = SetValue;
getchar();
//设置时间
HAL_RTC_SetTime(&hrtc,&RTC_TimeStruct_SetValue,RTC_FORMAT_BIN);
}
static void Myrtc_Set_Current_Time_Date(void)
{
Myrtc_Set_Current_Date();
Myrtc_Set_Current_Time();
}
(4)设置闹钟时间
// 设置闹钟
static void Myrtc_Set_Alarm_Time_Date(void)
{
RTC_AlarmTypeDef RTC_AlarmStruct_SetValue;
uint8_t SetValue;
printf("=========================DWB闹钟时间设置==================\n");
printf("请输入时钟(00-23): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(23);
}
printf("时钟被设置为: %02u\n", SetValue);
RTC_AlarmStruct_SetValue.AlarmTime.Hours = SetValue;
getchar();
printf("请输入分钟(00-59): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(59);
}
printf("分钟被设置为: %02u\n", SetValue);
RTC_AlarmStruct_SetValue.AlarmTime.Minutes = SetValue;
getchar();
printf("请输入秒钟(00-59): \n");
SetValue = 0xFF;
while (SetValue == 0xFF)
{
SetValue = Input_RTC_SetValue(59);
}
printf("秒钟被设置为: %02u\n", SetValue);
RTC_AlarmStruct_SetValue.AlarmTime.Seconds = SetValue;
getchar();
HAL_RTC_SetAlarm_IT(&hrtc, &RTC_AlarmStruct_SetValue, RTC_FORMAT_BIN);
}
五、结果演示
串口显示乱码解决方案
现象:实验过程中出现与串口通讯中文乱码现象,如下图所示
原因: vscode 编写代码默认是以UTF-8格式编写的,但是SSCOM串口工具是以GBK格式显示的。
因此代码里的需要在串口中显示的中文,会以UTF-8的形式编码。由于SSCOM串口工具只能用GBK格式译码显示,则出现乱码现象。
解决方案:
在编写代码的时候用GBK格式编写,这样就和SSCOM译码格式相符合