目录
[1. RTC介绍](#1. RTC介绍)
[2. 使用CubeMx进行源工程配置](#2. 使用CubeMx进行源工程配置)
[3. 代码编程](#3. 代码编程)
[3.1 准备工作](#3.1 准备工作)
[3.2 进行bsp_rtc.h编写](#3.2 进行bsp_rtc.h编写)
[3.3 进行bsp_rtc.c编写](#3.3 进行bsp_rtc.c编写)
[3.4 main.c编写](#3.4 main.c编写)
[3.4.1 头文件引用](#3.4.1 头文件引用)
[3.4.2 变量声明](#3.4.2 变量声明)
[3.4.3 子函数声明](#3.4.3 子函数声明)
[3.4.4 函数实现](#3.4.4 函数实现)
[3.4.5 main函数编写](#3.4.5 main函数编写)
[4. 代码实验](#4. 代码实验)
[5. 总结](#5. 总结)
前言
因本人备赛蓝桥杯嵌入式省赛,故编写此学习笔记进行学习上的记录。
上文我们实现了TIM程序设计,本文我们进行RTC程序设计
1. RTC介绍
RTC是一个独立的定时器,RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。
从STM32G4系列微控制器参考手册的时钟树图可以看出,RTCCLK 时钟源可以是 HSE/32、LSE 或 LSI 时钟。
LSE 时钟位于 RTC 域中,而 HSE 和 LSI 时钟则不在 RTC 域中。
- 如果选择 LSE 作为 RTC 时钟:
即使 VDD 电源关闭,RTC 仍可继续工作,前提是VBAT电源得到维持。
- 如果选择LSI作为RTC时钟:
如果 VDD 电源断电,则无法保证 RTC 状态。
- 如果将除以预分频器的 HSE 时钟用作 RTC 时钟:
如果 VDD 电源断电或内部电压调节器已关闭电源(从 VCORE 域断开电源)。
当RTC时钟为LSE或LSI时,RTC在系统下保持时钟和功能重置。
2. 使用CubeMx进行源工程配置
-【Pinout&Configuration】
-【Timers】
-【RTC】
-【Mode】
-【Activate Clock Source】和【Activate Calendar】
-在【Clock Configuration】配置RTC时钟源为HSE_RTC,时钟源频率为750KHz。
RTC时钟频率 = RTC时钟源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))
-【Parameter Settings】
-【Asynchronous Predivider Value】设置为124
-【Synchronous Predivider value 】设置为5999。
这样,RTC时钟频率就为1Hz。
配置完成后,我们去生成源文件。
3. 代码编程
3.1 准备工作
接下来我们在Test_Project工程里的Src文件夹创建BSP\RTC\bsp_rtc.c,同理,在Inc文件夹创建BSP\RTC\bsp_rtcm.h。这就是我们后面要编写的中间层代码文件。
打开Test_Project工程,进行文件Group的添加
在bsp_rtc.c中添加依赖文件
cpp
#include "RTC/bsp_rtc.h"
随后进行编译。
添加stm32g4xx_hal_rtc.c和stm32g4xx_hal_rtc_ex.c驱动文件
在stm32g4xx_hal_conf.h中去掉#define HAL_RTC_MODULE_ENABLED 的注释。
cpp
#define HAL_RTC_MODULE_ENABLED
3.2 进行bsp_rtc.h编写
通过Source工程生成的tim模块进行剪裁修改,h文件如下
cpp
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern RTC_HandleTypeDef hrtc;
void RTC_Init(void);
3.3 进行bsp_rtc.c编写
通过Source工程生成的tim模块进行剪裁修改,c文件如下
cpp
#include "RTC/bsp_rtc.h"
RTC_HandleTypeDef hrtc;
void RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 125;
hrtc.Init.SynchPrediv = 6000;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0;
sTime.Minutes = 0;
sTime.Seconds = 0;
sTime.SubSeconds = 0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 1;
sDate.Year = 0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
}
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
}
}
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* Peripheral clock disable */
__HAL_RCC_RTC_DISABLE();
}
}
3.4 main.c编写
3.4.1 头文件引用
cpp
#include "main.h"
#include "LCD\bsp_lcd.h"
#include "RTC\bsp_rtc.h"
3.4.2 变量声明
cpp
//变量声明
__IO uint32_t uwTick_Lcd_Set_Point;//LCD减速
//*LCD显示专用变量
unsigned char Lcd_Disp_String[22];
//RTC相关变量
RTC_TimeTypeDef H_M_S_Time;
RTC_DateTypeDef Y_M_D_Date;
3.4.3 子函数声明
cpp
//***子函数声明区
void SystemClock_Config(void);
void Lcd_Proc(void);
3.4.4 函数实现
3.4.4.1 时钟函数定义
cpp
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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.PLLM = RCC_PLLM_DIV3;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
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_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1
|RCC_PERIPHCLK_ADC12;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_PLL;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
3.4.4.2 LCD函数实现
cpp
void Lcd_Proc(void)
{
if((uwTick - uwTick_Lcd_Set_Point)<200)
return;
uwTick_Lcd_Set_Point = uwTick;
//RTC内容显示
HAL_RTC_GetTime(&hrtc,&H_M_S_Time,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&Y_M_D_Date,RTC_FORMAT_BIN);
sprintf((char*)Lcd_Disp_String,"Time:%02d-%02d-%02d",(unsigned int)H_M_S_Time.Hours,(unsigned int)H_M_S_Time.Minutes,(unsigned int)H_M_S_Time.Seconds);
LCD_DisplayStringLine(Line4,Lcd_Disp_String);
}
3.4.5 main函数编写
cpp
int main(void)
{
HAL_Init();
SystemClock_Config();
LCD_Init();
LCD_Clear(White);
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
//RTC初始化
RTC_Init();
while (1)
{
Lcd_Proc();
}
}
4. 代码实验
将代码进行编译并下载到开发板上。效果如下图所示。
时钟计时按1s为单位进行增加,RTC基本功能已成功实现!
5. 总结
本文通过CubeMx进行配置RTC的参数以及时钟资源,并通过CubeMx生成的源工程进行二次编写成功实现了RTC的基本功能。