STM32学习笔记九——RTC实时时钟&BKP备份寄存器&PWR电源控制

Unix时间戳

在这里插入图片描述

UTC/GMT

在这里插入图片描述

时间戳转换

在这里插入图片描述
在这里插入图片描述

BKP备份寄存器

BKP简介

在这里插入图片描述

BKP基本结构

在这里插入图片描述

RTC实时时钟

RTC简介

在这里插入图片描述

RTC框图

在这里插入图片描述

RTC基本结构

在这里插入图片描述

硬件电路

在这里插入图片描述

RTC操作注意事项

在这里插入图片描述

读写备份寄存器

连接电路

编写程序

实验现象:程序下载后,OLED显示屏上第二行显示“R:”,为0000 0000;按下按键,OLED显示屏上第二行显示“W:”,为1235 5679(从1234 5678自增1),OLED显示屏上第二行显示“R:”,为1235 5679;之后,每按下一次按键,数值自增一,W和R显示数值相同。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"

uint16_t KeyNum;

uint16_t ArrayWrite[] = {0x1234,0x5678};
uint16_t ArrayRead[2];

int main (void)
{
	OLED_Init ();
	Key_Init ();
	
	OLED_ShowString (1,1,"W:");
	OLED_ShowString (2,1,"R:");
	
	//初始化BKP
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR ,ENABLE );
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_BKP ,ENABLE );
	
	PWR_BackupAccessCmd (ENABLE );
	
//	BKP_WriteBackupRegister(BKP_DR1 ,0x1234);
//	BKP_ReadBackupRegister(BKP_DR1);
//	OLED_ShowHexNum (1,1,BKP_ReadBackupRegister(BKP_DR1),4);
	
	while(1)
	{
		KeyNum =Key_GetNum ();
		
		if (KeyNum ==1)
		{
			ArrayWrite [0] ++;
			ArrayWrite [1] ++;
			
			BKP_WriteBackupRegister(BKP_DR1 ,ArrayWrite [0]);
			BKP_WriteBackupRegister(BKP_DR2 ,ArrayWrite [1]);
			
			OLED_ShowHexNum (1,3,ArrayWrite [0],4);
			OLED_ShowHexNum (1,8,ArrayWrite [1],4);
		}
		
		ArrayRead [0] = BKP_ReadBackupRegister(BKP_DR1);
		ArrayRead [1] = BKP_ReadBackupRegister(BKP_DR2);
		
		OLED_ShowHexNum (2,3,ArrayRead [0],4);
		OLED_ShowHexNum (2,8,ArrayRead [1],4);
	}
}

实时时钟

实验现象:OLED显示屏第一行显示为“Date:”,年月日;第二行显示:“Time:”,时分秒;第三行显示“CNT:”,秒数;第四行显示“DIV:”,余数。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main (void)
{
	OLED_Init ();
	MyRTC_Init ();
	
	OLED_ShowString (1,1,"Date:XXXX_XX_XX");
	OLED_ShowString (2,1,"Time:XX:XX:XX");
	OLED_ShowString (3,1,"CNT:");
	OLED_ShowString (4,1,"DIV:");
	
	while(1)
	{
		MyRTC_ReadTime();
		
		OLED_ShowNum(1,6,MyRTC_Time[0],4);
		OLED_ShowNum(1,11,MyRTC_Time[1],2);
		OLED_ShowNum(1,14,MyRTC_Time[2],2);
		OLED_ShowNum(2,6,MyRTC_Time[3],2);
		OLED_ShowNum(2,9,MyRTC_Time[4],2);
		OLED_ShowNum(2,12,MyRTC_Time[5],2);
		
		OLED_ShowNum(3,6,RTC_GetCounter (),10);
		OLED_ShowNum(4,6,RTC_GetDivider (),10);
	}
}

MyRTC.c文件

#include "stm32f10x.h"                  // Device header
#include <time.h>

uint16_t MyRTC_Time[] = {2023,1,1,23,59,55};

void MyRTC_SetTime(void);

void MyRTC_Init(void)
{
	//初始化RTC
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
	
	PWR_BackupAccessCmd(ENABLE);
	
	if (BKP_ReadBackupRegister (BKP_DR1 ) != 0xA5A5 )
	{
	
		//配置外部低速时钟(LSE时钟源)
		RCC_LSEConfig (RCC_LSE_ON );
		while ( RCC_GetFlagStatus (RCC_FLAG_LSERDY) != SET );//Checks whether the specified RCC flag(LSE) is set or not.
		
		//选择RTCCLK时钟源
		RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE );
		RCC_RTCCLKCmd(ENABLE );//使能
		
		//等待同步、等待上一次写入操作完成
		RTC_WaitForSynchro ();
		RTC_WaitForLastTask ();
		
		//配置预分频器
		RTC_SetPrescaler (32768-1);
		RTC_WaitForLastTask ();
		
		//设置初始时间
	//	RTC_SetCounter (1672588795);//2023-1-1  15:59:55(伦敦)
	//	RTC_WaitForLastTask ();

		MyRTC_SetTime();
		
		BKP_WriteBackupRegister (BKP_DR1 ,0xA5A5);
	}
	else
	{
		RTC_WaitForSynchro ();
		RTC_WaitForLastTask ();
	}
}

//用于设置时间的函数
void MyRTC_SetTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	
	//将数组指定的时间填充到struck tm结构体里
	time_date.tm_year = MyRTC_Time[0] - 1900;
	time_date.tm_mon = MyRTC_Time[1] - 1;
	time_date.tm_mday = MyRTC_Time[2];
	time_date.tm_hour = MyRTC_Time[3];
	time_date.tm_min = MyRTC_Time[4];
	time_date.tm_sec = MyRTC_Time[5];
	
	//得到秒数
	time_cnt = mktime(&time_date) - 8 * 60 * 60;//并转换为北京时间
	
	//将秒数写入到RTC的CNT中
	RTC_SetCounter (time_cnt);
	RTC_WaitForLastTask ();
}

//用于读取时间的函数
void MyRTC_ReadTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	
	//将秒数写入到RTC的CNT中
	time_cnt = RTC_GetCounter () + 8 * 60 * 60;//并转换为北京时间
	
	//得到日期时间
	time_date = *localtime (&time_cnt);
	
	MyRTC_Time[0] = time_date.tm_year + 1900;
	MyRTC_Time[1] = time_date.tm_mon + 1;
	MyRTC_Time[2] = time_date.tm_mday;
	MyRTC_Time[3] = time_date.tm_hour;
	MyRTC_Time[4] = time_date.tm_min;
	MyRTC_Time[5] = time_date.tm_sec;
}

MyRTC.h文件

#ifndef __MYRTC_H
#define __MYRTC_H

extern uint16_t MyRTC_Time[];

void MyRTC_Init(void);
void MyRTC_SetTime(void);
void MyRTC_ReadTime(void);

#endif

PWR电源控制

PWR简介

在这里插入图片描述

电源框图

在这里插入图片描述

上电复位和掉电复位

在这里插入图片描述

可编程电压检测器

在这里插入图片描述

低功耗模式

在这里插入图片描述

模式选择

在这里插入图片描述

睡眠模式

在这里插入图片描述

停止模式

在这里插入图片描述

待机模式

在这里插入图片描述
system_stm32f10x.c文件的注释

  1. 这段文字提供了两个函数和一个全局变量,供用户应用程序调用:
  • SystemInit(): 设置系统时钟(系统时钟源、PLL乘数因子、AHB/APBx预分频器和Flash设置)。此函数在启动时在重置之后和跳转到主程序之前被调用。该调用在"startup_stm32f10x_xx.s"文件中进行。
  • SystemCoreClock变量:包含核心时钟(HCLK),用户可以将其用于设置SysTick定时器或配置其他参数。
  • SystemCoreClockUpdate(): 更新变量SystemCoreClock,并且必须在程序执行期间内核时钟发生变化时被调用。
  1. 在每次设备重置后,HSI(8 MHz)被用作系统时钟源。然后,在"startup_stm32f10x_xx.s"文件中调用SystemInit()函数,在跳转到主程序之前配置系统时钟。

  2. 如果用户选择的系统时钟源无法启动,SystemInit()函数将不执行任何操作,并且仍然使用HSI作为系统时钟源。用户可以在SetSysClock()函数中添加一些代码来处理此问题。

  3. HSE晶振的默认值设置为8 MHz(或25 MHz,取决于使用的产品),请参阅"stm32f10x.h"文件中的"HSE_VALUE"定义。当HSE用作系统时钟源时,无论是直接还是通过PLL,如果您使用的是不同的晶振,则必须将自己的配置适应HSE值。

修改主频

实验现象:SYSCLK显示系统主频,第二行的“Running”一两秒为周期闪烁。

修改主频需要先取消文件的只读,之后在system_stm32f10x.c文件中修改主频

main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main (void)
{
	OLED_Init ();
	
	OLED_ShowString (1,1,"SYSCLK:");
	OLED_ShowNum (1,8,SystemCoreClock ,8);
	
	while(1)
	{
		OLED_ShowString (2,1,"Running");
		Delay_ms(500);
		OLED_ShowString (2,1,"       ");
		Delay_ms(500);
	}
}

system_stm32f10x.c文件中修改主频

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
#define SYSCLK_FREQ_36MHz  36000000
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
/* #define SYSCLK_FREQ_72MHz  72000000 */
#endif

睡眠模式+串口发送+接收

依靠9-2串口发送+接收工程重新编写代码
实验现象:使用串口发送数据时,Running闪烁一次,未发送数据时,Running不闪烁。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RxData;

int main (void)
{
	OLED_Init ();
	OLED_ShowString(1, 1, "RxData:");
	
	Serial_Init ();

	while(1)
	{
		if (Serial_GetRxFlag() == 1)
		{
			RxData = Serial_GetRxData();
			Serial_SendByte(RxData);
			OLED_ShowHexNum(1, 8, RxData, 2);
		}
		
		OLED_ShowString (2,1,"Running");
		Delay_ms(500);
		OLED_ShowString (2,1,"       ");
		Delay_ms(500);
		
		__WFI ();
		//睡眠模式+中断唤醒
//		__WFE ();
		//睡眠模式+事件唤醒
	}
}

停止模式+对射式红外传感器计次

依靠5-1对射式红外传感器计次工程重新编写代码
实验现象:对传感器进行遮挡,数值加一,Running闪烁一次;未遮挡时,Running不闪烁。
下载程序的步骤:按住复位键,点击下载,松手,就可下载成功。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"

int main (void)
{
	OLED_Init ();
	CountSensor_Init();
	
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR ,ENABLE );
	
	OLED_ShowString (1,1,"Count:");
	
	while(1)
	{
		OLED_ShowNum (1,7,CountSensor_Get (),5);
		
		OLED_ShowString (2,1,"Running");
		Delay_ms (500);
		OLED_ShowString (2,1,"       ");
		Delay_ms (500);
		
		PWR_EnterSTOPMode (PWR_Regulator_ON ,PWR_STOPEntry_WFI );
		SystemInit ();
	}
}

待机模式+实时时钟

依靠12-2实时时钟工程重新编写代码
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	
	OLED_ShowString(1, 1, "CNT :");
	OLED_ShowString(2, 1, "ALR :");
	OLED_ShowString(3, 1, "ALRF:");
	
	PWR_WakeUpPinCmd(ENABLE);
	
	uint32_t Alarm = RTC_GetCounter() + 10;
	RTC_SetAlarm(Alarm);
	OLED_ShowNum(2, 6, Alarm, 10);
	
	while (1)
	{
		OLED_ShowNum(1, 6, RTC_GetCounter(), 10);
		OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1);
		
		OLED_ShowString(4, 1, "Running");
		Delay_ms(100);
		OLED_ShowString(4, 1, "       ");
		Delay_ms(100);
		
		OLED_ShowString(4, 9, "STANDBY");
		Delay_ms(1000);
		OLED_ShowString(4, 9, "       ");
		Delay_ms(100);
		
		OLED_Clear();
		
		PWR_EnterSTANDBYMode();
	}
}

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值