本帖最后由 kkhkbb 于 2018-3-22 11:13 编辑
一、概述
1、实时时钟定义
实时时钟(RTC)是一个独立的BCD定时器/计数器。RTC提供一个日历时钟和两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。
两个32位寄存器包含二进码十进位格式(BCD)的秒、分钟、小时(12或24小时制)、星期几、日期、月份和年份。此外,还可以提供二进制格式的亚秒值。
系统可以自动将月份的天数补偿位28、29(闰年),30和31天。并且还可以进行夏令时的补偿。
其他32位寄存器还包括可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。
上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。 无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。
2、实时时钟主要特性
RTC的主要特性如下: - 包含亚秒、秒、分钟、小时(12/24小时制)、星期几、日期、月份和年份的日期。
- 软件可编程的夏令时补偿。
- 两个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
- 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
- 参考时钟检测:可使用更加精确的第二时钟源(50Hz或60Hz)来提高日历的精确度。
- 利用亚秒级移位特性与外部时钟实现精确同步。
- 可屏蔽中断/事件:
— 闹钟A — 闹钟B — 唤醒中断 — 时间戳 — 入侵检测 — 精度为5ppm。 — 精度为0.95ppm, 在数秒钟的校准窗口中获得。 — 2个带可配置过滤器和内部上拉的入侵事件。
— RTC_CALIB:512Hz或1Hz时钟输出(LSE频率为32.768kHZ)。可通过将RTC_CR寄存器中的COE【23】位置1来使能此输出。该输出可连接到器件RTC_AF1功能。 — RTC_ALARM(闹钟A、闹钟B或唤醒)。可通过配置RTC_CR寄存器的OSEL【1:0】位选择此输出。该输出可连接到器件RTC_AF1功能。 — RTC_TS:时间戳事件检测。该输入可连接到器件RTC_AF1和RTC_AF2功能。 — RTC_TAMP1:TAMPER1 事件检测。该输入可连接到器件RTC_AF1和RTC_AF2功能。 — RTC_TAMP2:TAMPER2 事件检测。 — RTC_REFIN:参考时钟输入(通常为市电,50Hz或60Hz)。 二、硬件电路 1、时钟源 iCore3异构双核心工控板采用32.768K无源晶体为系统提供RTC实时时钟,其电路连接图如下所示。32.768KHz外部无源晶体连接 OSC32_IN和OSC32_OUT两引脚之间,为获得稳定的频率必须加两个电容构成外部震荡电路。
图10_0 外部振荡电路 2、备用电源 RTC实时时钟在iCore3电路中具有备用电源,时刻保证时钟通电。
图10_1 备用电池电路 三、实验原理 STM32的实时时钟(RTC)是一个独立的定时器,有一组连续计数的计时器,通过软件来对其进行相关的配置,可以提供时钟功能,通过修改计数器的值可以调整时钟,最终通过串口在终端显示时间。 四、源代码 1、主函数 /*
* Name : main
* Description : ---
* Author : ysloveivy.
*
* History
* --------------------
* Rev : 0.00
* Date : 11/23/2015
*
* create.
* --------------------
*/
int main(void)
{
int i;
RTC_TimeTypeDef rtc_time;
RTC_DateTypeDef rtc_date;
int second_bak = 0;
led.initialize();
LED_RED_ON;
rtc.initialize();
usart4.initialize(115200);
usart4.printf("\x0c"); //清屏
usart4.printf("\033[1;32;40m"); //设置字体终端为绿色
usart4.printf("\r\n\r\nhello! I am iCore3!\r\n\r\n\r\n");
while(1){
for(i = 0;i < 1000000;i++);
//读取RTC日期和时间
RTC_GetTime(RTC_Format_BIN,&rtc_time);
RTC_GetDate(RTC_Format_BIN,&rtc_date);
//当秒数据与备份不一致时,向终端打印时间/日期
if(second_bak != rtc_time.RTC_Seconds){
usart4.printf(" %02d:%02d:%02d ",rtc_time.RTC_Hours,rtc_time.RTC_Minutes,rtc_time.RTC_Seconds);
usart4.printf("20%02d-%02d-%02d \r",rtc_date.RTC_Year,rtc_date.RTC_Month,rtc_date.RTC_Date);\
second_bak = rtc_time.RTC_Seconds; //秒数据备份
}
}
}
2、RTC初始化 /*
* Name : initialize
* Description : ---
* Author : ysloveivy.
*
* History
* -------------------
* Rev : 0.00
* Date : 11/23/2015
*
* create.
* -------------------
*/
static int initialize(void)
{
//判断读到的备份寄存器的值与写入的值是否一样
if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
//使能PWR时钟
PWR_BackupAccessCmd(ENABLE);
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
RCC_LSEConfig(RCC_LSE_ON); //LSE 开启
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) ==RESET); //检查指定的RCC标志位设置与否,等待低速晶振就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
RTC_WaitForSynchro();
//等待APB1和RTC等时钟同步
rtc_set_time(13,57,12,RTC_H12_PM); //设置时间
rtc_set_date(15,11,28,6); //设置日期
RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2); //向备份寄存器中写入数值
}
return 0;
}
/*
* Name : initialize
* Description : ---
* Author : ysloveivy.
*
* History
* -------------------
* Rev : 0.00
* Date : 11/23/2015
*
* create.
* -------------------
*/
static int rtc_set_time(unsigned char hour,unsigned char min,unsigned char sec,unsigned char ampm)
{
//设置时间
RTC_TimeTypeDef RTC_TimeTypeInitStructure;
RTC_TimeTypeInitStructure.RTC_Hours=hour;
RTC_TimeTypeInitStructure.RTC_Minutes=min;
RTC_TimeTypeInitStructure.RTC_Seconds=sec;
RTC_TimeTypeInitStructure.RTC_H12=ampm;
RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
return 0;
}
3、RTC配置介绍 static int initialize(void)
{
//判断读到的备份寄存器的值与写入的值是否一样
if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
//使能PWR时钟
PWR_BackupAccessCmd(ENABLE);
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
RCC_LSEConfig(RCC_LSE_ON); //LSE 开启
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) ==RESET); //检查指定的RCC标志位设置与否,等待低速晶振就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
RTC_WaitForSynchro();
//等待APB1和RTC等时钟同步
rtc_set_time(13,57,12,RTC_H12_PM); //设置时间
rtc_set_date(15,11,28,6); //设置日期
RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2); //向备份寄存器中写入数值
}
return 0;
}
static int rtc_set_date(unsigned char year,unsigned char month,unsigned char date,unsigned char week)
{
//设置日期
RTC_DateTypeDef RTC_DateTypeInitStructure;
RTC_DateTypeInitStructure.RTC_Date=date;
RTC_DateTypeInitStructure.RTC_Month=month;
RTC_DateTypeInitStructure.RTC_WeekDay=week;
RTC_DateTypeInitStructure.RTC_Year=year;
RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
return 0;
}
4、结构体介绍 /**
* [url=home.php?mod=space&uid=247401]@brief[/url] RTC Init structures definition
*/
typedef struct
{
uint32_t RTC_HourFormat; 指定RTC小时格式,
这个参数可以是[url=home.php?mod=space&uid=144993]@ref[/url] rtc_hour_format的值。
uint32_t RTC_AsynchPrediv; 指定RTC异步预分值,
此参数必须设置为低于0x7F的值。
uint32_t RTC_SynchPrediv; 指定RTC同步预分值,
此参数必须设置为低于0x7FFF的值。
}RTC_InitTypeDef;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] RTC Time structure definition
*/
typedef struct
{
uint8_t RTC_Hours; 指定RTC时间小时,此参数必须设置为0-12范围内的值。如果选择RTC_HourFormat_12,则为0-23。该RTC_HourFormat_24被选中。
uint8_t RTC_Minutes; 指定RTC时间分钟,
此参数必须设置为0-59范围内值。
uint8_t RTC_Seconds; 指定RTC时间秒,
此参数必须设置为0-59范围内的值。
uint8_t RTC_H12; 指定RTC AM/PM时间,
这个参数可以是[url=home.php?mod=space&uid=144993]@ref[/url] rtc_am_pm_definition的值。
}RTC_TimeTypeDef;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] RTC Date structure definition
*/
typedef struct
{
uint8_t RTC_WeekDay; 指定RTC日期工作日,这个参数可以是@refrtc_weekday_definition的值。
uint8_t RTC_Month; 指定RTC日期月(BCD格式),这个参数可以是[url=home.php?mod=space&uid=144993]@ref[/url] rtc_month_date_definition的值。
uint8_t RTC_Date; 指定RTC日期,此参数必须设置为1-31范围内的值。
uint8_t RTC_Year; 指定RTC日期年,此参数必须设置为0-99范围内的值。
}RTC_DateTypeDef;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] RTC Alarm structure definition
*/
typedef struct
{
RTC_TimeTypeDef RTC_AlarmTime; 指定RTC警报时间成员。
uint32_t RTC_AlarmMask; 指定RTC报警面具,这个参数可以是[url=home.php?mod=space&uid=144993]@ref[/url] rtc_alarmmask_definition 的值。
uint32_t RTC_AlarmDateWeekDaySel; 指定RTC警报是在日期或工作日,
这个参数可以是[url=home.php?mod=space&uid=144993]@ref[/url] rtc_alarmdateweekday_definition的值。
uint8_t RTC_AlarmDateWeekDay; 指定RTC报警日期/工作日。
如果选择了警报日期,则该参数。
必须设置为1-31范围内的值。
如果选择了闹钟工作日,这个。
参数可以是@ref rtc_weekday_definition的值。
}RTC_AlarmTypeDef;
五、实验现象 在终端屏幕上可以看到显示的时间和日期(如下图所示)。
图10_3 实验现象图 六、代码包下载
网盘:http://pan.baidu.com/s/1jHnZcnc
|