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文件的注释
- 这段文字提供了两个函数和一个全局变量,供用户应用程序调用:
- SystemInit(): 设置系统时钟(系统时钟源、PLL乘数因子、AHB/APBx预分频器和Flash设置)。此函数在启动时在重置之后和跳转到主程序之前被调用。该调用在"startup_stm32f10x_xx.s"文件中进行。
- SystemCoreClock变量:包含核心时钟(HCLK),用户可以将其用于设置SysTick定时器或配置其他参数。
- SystemCoreClockUpdate(): 更新变量SystemCoreClock,并且必须在程序执行期间内核时钟发生变化时被调用。
-
在每次设备重置后,HSI(8 MHz)被用作系统时钟源。然后,在"startup_stm32f10x_xx.s"文件中调用SystemInit()函数,在跳转到主程序之前配置系统时钟。
-
如果用户选择的系统时钟源无法启动,SystemInit()函数将不执行任何操作,并且仍然使用HSI作为系统时钟源。用户可以在SetSysClock()函数中添加一些代码来处理此问题。
-
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();
}
}