STM32开发(十六)STM32F103 片内资源 —— 实时时钟RTC 详解
文章目录
-
- 一、基础知识点
- 二、开发环境
- 三、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译码格式相符合