第十二篇,STM32中的RTC编程

1.概念

    RTC叫实时时钟,是芯片中用于记录具体时间的硬件

    由于计时操作需要一直运行,永不停歇,因此RTC需要独立的供电,独立的时钟源。

    

               

               

               

stm32f407的RTC是一个独立的定时器,使用BCD码(用十六进制记录十进制数据)的计数器,提供日历时钟(年月日时分秒星期)和闹钟功能。

2.stm32的RTC框图 

3.RTC的配置

(1)RTC配置寄存器具有写保护功能,写寄存器之前必须关闭写保护

1.将电源控制寄存器(PWR_CR)的DBP位置1 2.向RTC写保护寄存器(RTC_WPR)写入:0xca 0x53

(2)RTC的初始化

当初始化完成后,RTC开始计时。RTC不需要每次启动都初始化

4.RTC的库函数编程实现

 

    在工程中加入RTC和PWR(电源控制)的库函数源码

(1)开启PWR时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);

(2)使能PWR中RTC寄存器的写操作

PWR_BackupAccessCmd(ENABLE);

(3)使能LSE,选择LSE作为RTC时钟源

RCC_LSEConfig(RCC_LSE_ON); //等待LSE就绪 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET); //选择LSE作为RTC时钟源 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

(4)使能RTC时钟

RCC_RTCCLKCmd(ENABLE);

(5)关闭RTC的写保护,等待就绪

RTC_WaitForSynchro();

(6)配置RTC的分频系数和时间格式

ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);

//传入RTC初始化结构 typedef struct

{  

  uint32_t RTC_HourFormat;   /*!< 小时格式 12/24 @ref RTC_Hour_Formats */      uint32_t RTC_AsynchPrediv; /*!< 异步分频系数(尽量大) lower than 0x7F */      uint32_t RTC_SynchPrediv;  /*!< 同步分频系数 lower than 0x7FFF */

} RTC_InitTypeDef;

(7)设置初始日期和时间

//设置日期 ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);

参数:     RTC_Format – 日期格式 RTC_Format_BCD    

                RTC_DateStruct – 日期结构

typedef struct 

{   

uint8_t RTC_WeekDay; /*!< 星期 @ref RTC_WeekDay_=Definitions */      

uint8_t RTC_Month;   /*!< 月 @ref RTC_Month_Date_Definitions */   

uint8_t RTC_Date;     /*!< 日 1-31 range. */      

uint8_t RTC_Year;     /*!< 年 0-99 range. */

}RTC_DateTypeDef;        //设置时间

ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);

参数:     RTC_Format – 时间格式 RTC_Format_BCD     

               RTC_DateStruct – 时间结构  

    

typedef struct

{   

uint8_t RTC_Hours;    /*!< 小时 */   

uint8_t RTC_Minutes;  /*!< 分 0-59 range. */      

uint8_t RTC_Seconds;  /*!< 秒 0-59 range. */   

uint8_t RTC_H12;      /*!< 上午/下午 @ref RTC_AM_PM_Definitions */

}RTC_TimeTypeDef;

(8)获取日期和时间

void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct); void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);

RTC提供了备份寄存器,这些寄存器由备份电源供电,数据掉电不丢失,可以通过这些寄存器实现只初始化RTC一次。

void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data); uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);

练习:

    测试RTC功能,通过蓝牙命令读取RTC时间到手机

    

5.RTC的闹钟配置

//关闭RTC寄存器写保护

(1)关闭闹钟

RTC_AlarmCmd(RTC_Alarm_A, DISABLE);

(2)设置闹钟参数

void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct);

参数:     

RTC_Format – 时间格式 RTC_Format_BCD     

RTC_Alarm – 哪个闹钟 RTC_Alarm_A     

RTC_AlarmStruct – 闹钟参数结构体

    

typedef struct
{
  RTC_TimeTypeDef RTC_AlarmTime;     /*!< 闹钟时间 */

  uint32_t RTC_AlarmMask;      /*!< 闹钟时间掩码 @ref RTC_AlarmMask_Definitions */

  uint32_t RTC_AlarmDateWeekDaySel;  

/*!< 星期/日期选择 @ref RTC_AlarmDateWeekDay_Definitions */
  
  uint8_t RTC_AlarmDateWeekDay;     

 /*!< 日期 1-31 range.星期 @ref RTC_WeekDay_Definitions */
}RTC_AlarmTypeDef;

(3)清除中断标志

RTC_ClearITPendingBit(RTC_IT_ALRA);

(4)使能闹钟A中断

RTC_ITConfig(RTC_IT_ALRA, ENABLE);

(5)外部中断初始化

 

EXTI_Init(…);

(6)初始化NVIC

NVIC_Init(…);

(7)启动闹钟

RTC_AlarmCmd(RTC_Alarm_A, ENABLE);

(8)实现RTC闹钟中断处理函数

void RTC_Alarm_IRQHandler(void)

 {     //……          

//清除闹钟中断标志    

 RTC_ClearITPendingBit(RTC_IT_ALRA);   

  //清除外部中断标志  

EXTI_ClearITPendingBit(EXTI_Line17);

}

6.RCT编程实现.

#include <stm32f4xx.h>
#include <rtc.h>
#include <beep.h>

void rtc_init(void)
{
	RTC_InitTypeDef RTC_InitStruct;
	RTC_DateTypeDef RTC_DateStruct;
	RTC_TimeTypeDef RTC_TimeStruct;
	
	if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x8888){
		//1.开启PWR时钟
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
		
		//2.使能PWR中RTC寄存器的写操作
		PWR_BackupAccessCmd(ENABLE);
		
		//3.使能LSE,选择LSE作为RTC时钟源
		RCC_LSEConfig(RCC_LSE_ON);
		//等待LSE就绪
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET);
		//选择LSE作为RTC时钟源
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		
		//4.使能RTC时钟
		RCC_RTCCLKCmd(ENABLE);
		
		//5.关闭RTC的写保护,等待就绪
		RTC_WaitForSynchro();

		//6.配置RTC的分频系数和时间格式  1Hz
		RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;//24小时格式
		RTC_InitStruct.RTC_AsynchPrediv = 0x7f;//异步预分频系数,尽量大 128分频
		RTC_InitStruct.RTC_SynchPrediv = 0xff;//同步预分频系数 256分频
		RTC_Init(&RTC_InitStruct);
		
		//7.设置初始日期和时间
		RTC_DateStruct.RTC_Year = 0x22;//年
		RTC_DateStruct.RTC_Month = RTC_Month_June;//月
		RTC_DateStruct.RTC_Date = 0x26;//日
		RTC_DateStruct.RTC_WeekDay = RTC_Weekday_Sunday;//星期日
		RTC_SetDate(RTC_Format_BCD,&RTC_DateStruct);
		
		RTC_TimeStruct.RTC_H12 = RTC_H12_PM;
		RTC_TimeStruct.RTC_Hours = 0x14;//时
		RTC_TimeStruct.RTC_Minutes = 0x42;//分
		RTC_TimeStruct.RTC_Seconds = 0x50;//秒
		RTC_SetTime(RTC_Format_BCD,&RTC_TimeStruct);
		
		//8.写备份寄存器
		RTC_WriteBackupRegister(RTC_BKP_DR0,0x8888);
	}
}

void rtc_set_time(u8 hour,u8 min,u8 sec)
{
	RTC_TimeTypeDef RTC_TimeStruct;
	
	//1.开启PWR时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
		
	//2.使能PWR中RTC寄存器的写操作
	PWR_BackupAccessCmd(ENABLE);
	
	//3.关闭RTC的写保护,等待就绪
	RTC_WaitForSynchro();
	
	RTC_TimeStruct.RTC_Hours = TOBCD(hour);//时
	RTC_TimeStruct.RTC_Minutes = TOBCD(min);//分
	RTC_TimeStruct.RTC_Seconds = TOBCD(sec);//秒
	RTC_SetTime(RTC_Format_BCD,&RTC_TimeStruct);
}

//RTC闹钟初始化
void rtc_alarm_init(void)
{
	RTC_AlarmTypeDef RTC_AlarmStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	//1.关闭寄存器写保护
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	
	//关闭RTC的写保护,等待就绪
	RTC_WaitForSynchro();
	
	//2.关闭闹钟
	RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
	
	//3.设置闹钟参数
	RTC_AlarmStruct.RTC_AlarmTime.RTC_H12 = RTC_H12_PM;
	RTC_AlarmStruct.RTC_AlarmTime.RTC_Hours = 0x15;
	RTC_AlarmStruct.RTC_AlarmTime.RTC_Minutes = 0x43;
	RTC_AlarmStruct.RTC_AlarmTime.RTC_Seconds = 0x10;
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;//日期匹配
	RTC_AlarmStruct.RTC_AlarmDateWeekDay = 0x27;//日期
	RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay|RTC_AlarmMask_Hours;//RTC_AlarmMask_None;//不屏蔽任何时间
	RTC_SetAlarm(RTC_Format_BCD,RTC_Alarm_A,&RTC_AlarmStruct);
	
	//4.清除中断标志
	RTC_ClearITPendingBit(RTC_IT_ALRA);
	
	//5.使能闹钟A中断
	RTC_ITConfig(RTC_IT_ALRA, ENABLE);
	
	//6.初始化外部中断和NVIC
	EXTI_InitStruct.EXTI_Line = EXTI_Line17;//外部中断线17
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能
	EXTI_Init(&EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn;//闹钟中断通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
	NVIC_Init(&NVIC_InitStruct);
	
	//7.开始闹钟
	RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
}

//闹钟中断处理函数
void RTC_Alarm_IRQHandler(void)
{
    //......
	BEEP = 1;
    
    //清除闹钟中断标志
    RTC_ClearITPendingBit(RTC_IT_ALRA);
    //清除外部中断标志
    EXTI_ClearITPendingBit(EXTI_Line17);
}

物联沃分享整理
物联沃-IOTWORD物联网 » 第十二篇,STM32中的RTC编程

发表评论