蓝桥杯嵌入式学习笔记(9):RTC程序设计

目录

前言

[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的基本功能。

相关推荐
IM_DALLA13 分钟前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL16
学习·fpga开发
IM_DALLA14 分钟前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL18
学习·fpga开发
完球了16 分钟前
【Day02-JS+Vue+Ajax】
javascript·vue.js·笔记·学习·ajax
怀九日26 分钟前
C++(学习)2024.9.19
开发语言·c++·学习·重构·对象·
开MINI的工科男40 分钟前
【笔记】自动驾驶预测与决策规划_Part1_自动驾驶决策规划简介
人工智能·笔记·自动驾驶
白帽黑客cst1 小时前
网络安全(黑客技术) 最新三个月学习计划
网络·数据结构·windows·学习·安全·web安全·网络安全
RS&2 小时前
python学习笔记
笔记·python·学习
EterNity_TiMe_2 小时前
【Linux基础IO】深入Linux文件描述符与重定向:解锁高效IO操作的秘密
linux·运维·服务器·学习·性能优化·学习方法
好家伙VCC3 小时前
STM32与51单片机的区别:是否应该直接学习STM32?
stm32·学习·51单片机
liuwill3 小时前
从技术打磨到产品验证:读《程序员修炼之道》的务实之道
笔记·程序人生