void RCC_RTCCLKConfig(uint32_t CLKSource);//时钟源选择
void RCC_RTCCLKCmd(FunctionalState NewState)//时钟使能
void RTC_SetPrescaler(uint32_t PrescalerValue);//预分频配置:PRLH/PRLL
void RTC_SetCounter(uint32_t CounterValue);//设置计数器值:CNTH/CNTL
void RTC_SetAlarm(uint32_t AlarmValue);//闹钟设置:ALRH/ALRL
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);//CRH
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);//CRH
void RTC_WaitForLastTask(void);//等待上次操作完成:CRL位RTOFF
void RTC_WaitForSynchro(void);//等待时钟同步:CRL位RSF
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
void RTC_ClearFlag(uint16_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
void RTC_ClearITPendingBit(uint16_t RTC_IT);
PWR_BackupAccessCmd();//BKP后备区域访问使能
RCC_APB1PeriphClockCmd();//使能PWR和BKP时钟
RCC_LSEConfig();//开启LSE,RTC选择LSE作为时钟源
PWR_BackupAccessCmd();//BKP后备区域访问使能
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);//读BKP寄存器
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);//写BKP
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
BKP_DeInit();//复位备份区域
RCC_LSEConfig(RCC_LSE_ON);// 开启外部低速振荡器
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择 LSE 作为 RTC 时钟
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟
RTC_EnterConfigMode();/// 允许配置
RTC_ExitConfigMode();//退出配置模式, 更新配置
void RTC_SetPrescaler(uint32_t PrescalerValue);
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
//实时时钟配置
//初始化 RTC 时钟,同时检测时钟是否工作正常
//BKP->DR1 用于保存是否第一次配置的设置
//返回 0:正常
//其他:错误代码
u8 RTC_Init(void)
{
u8 temp=0;
//检查是不是第一次配置时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |
RCC_APB1Periph_BKP, ENABLE); //①使能 PWR 和 BKP 外设时钟
PWR_BackupAccessCmd(ENABLE); //②使能后备寄存器访问
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //从指定的后备寄存器中
//读出数据:读出了与写入的指定数据不相乎
{
BKP_DeInit(); //③复位备份区域
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE)
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
//检查指定的 RCC 标志位设置与否,等待低速晶振就绪
{
temp++;
delay_ms(10);
}
if(temp>=250)return 1;//初始化时钟失败,晶振有问题
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟
//(RTCCLK),选择 LSE 作为 RTC 时钟
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟
RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
RTC_WaitForSynchro(); //等待 RTC 寄存器同步
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
RTC_EnterConfigMode(); // 允许配置
RTC_SetPrescaler(32767); //设置 RTC 预分频的值
RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
RTC_Set(2015,1,14,17,42,55); //设置时间
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中
//写入用户程序数据 0x5050
}
else//系统继续计时
{
RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
}
RTC_NVIC_Config(); //RCT 中断分组设置
RTC_Get(); //更新时间
return 0; //ok
}
//设置时钟
//把输入的时钟转换为秒钟
//以 1970 年 1 月 1 日为基准
//1970~2099 年为合法年份
//返回值:0,成功;其他:错误代码.
//月份数据表
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
u16 t;
u32 seccount=0;
if(syear<1970||syear>2099)return 1;
for(t=1970;t<syear;t++) //把所有年份的秒钟相加
{ if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
else seccount+=31536000; //平年的秒钟数
}
smon-=1;
for(t=0;t<smon;t++) //把前面月份的秒钟数相加
{ seccount+=(u32)mon_table[t]*86400; //月份秒钟数相加
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年 2 月份增加一天的秒钟数
}
seccount+=(u32)(sday-1)*86400; //把前面日期的秒钟数相加
seccount+=(u32)hour*3600; //小时秒钟数
seccount+=(u32)min*60; //分钟秒钟数
seccount+=sec; //最后的秒钟加上去
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |
RCC_APB1Periph_BKP, ENABLE); //使能 PWR 和 BKP 外设时钟
PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
RTC_SetCounter(seccount); //设置 RTC 计数器的值
RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
return 0;
}
//得到当前的时间,结果保存在 calendar 结构体里面
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{ static u16 daycnt=0;
u32 timecount=0;
u32 temp=0;
u16 temp1=0;
timecount=RTC->CNTH; //得到计数器中的值(秒钟数)
timecount<<=16;
timecount+=RTC->CNTL;
temp=timecount/86400; //得到天数(秒钟数对应的)
if(daycnt!=temp) //超过一天了
{
daycnt=temp;
temp1=1970; //从 1970 年开始
while(temp>=365)
{
if(Is_Leap_Year(temp1)) //是闰年
{
if(temp>=366)temp-=366; //闰年的秒钟数
else break;
}
else temp-=365; //平年
temp1++;
}
calendar.w_year=temp1; //得到年份
temp1=0;
while(temp>=28) //超过了一个月
{
if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2 月份
{
if(temp>=29)temp-=29;//闰年的秒钟数
else break;
}
else
{ if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
else break;
}
temp1++;
}
calendar.w_month=temp1+1; //得到月份
calendar.w_date=temp+1; //得到日期
}
temp=timecount%86400; //得到秒钟数
calendar.hour=temp/3600; //小时
calendar.min=(temp%3600)/60; //分钟
calendar.sec=(temp%3600)%60; //秒钟
calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);
//获取星期
return 0;
}
static void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级1位,从优先级3位
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //先占优先级0位,从优先级4位
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
//RTC 时钟中断
//每秒触发一次
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET) //秒钟中断
{
RTC_Get(); //更新时间
}
if(RTC_GetITStatus(RTC_IT_ALR)!= RESET) //闹钟中断
{
RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断
RTC_Get(); //更新时间
printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,
calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间
}
RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断
RTC_WaitForLastTask();
}
void BSP_RTC_Init(void)
{
u32 i = 0;
#if(INFO_OUT_RTC_INIT_EN > 0)
u8 tmpBuf[60]="";
#endif
/* Clear reset flags */
RCC_ClearFlag();
// 这里标志必须跟测试程序一致否则时间被复位成默认
if (BKP_ReadBackupRegister(BKP_DR1) != RTC_SAVE_FLAG)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
/* Backup data register value is not correct or not yet programmed (when
the first time the program is executed) */
/* RTC Configuration */
BSP_RTC_Config();
#if(DEF_RTCINFO_OUTPUTEN > 0)
if(dbgInfoSwt & DBG_INFO_RTC)
myPrintf("[RTC]: RTC finish configured....\r\n");
#endif
/* Set default time */
SYS_RTC.year = Default_year;
SYS_RTC.month = Default_month;
SYS_RTC.day = Default_day;
SYS_RTC.hour = Default_hour;
SYS_RTC.minute = Default_minute;
SYS_RTC.second = Default_second;
/* Adjust time by values entred by the user on the hyperterminal */
BSP_RTC_Set_Current(&SYS_RTC);
BKP_WriteBackupRegister(BKP_DR1, RTC_SAVE_FLAG);
}
else
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
/* Wait for RTC registers synchronization */
RTC_WaitForSynchro();
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Enable the RTC Second */
//RTC_ITConfig(RTC_IT_SEC, ENABLE); // 不能在系统运行前使能中断
//RTC_ITConfig(RTC_IT_ALR, ENABLE); // 系统闹钟中断
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitForLastTask(); // 不能在系统运行前使能中断
/* Initialize Date structure */
SYS_RTC.year = BKP_ReadBackupRegister(BKP_DR4);
SYS_RTC.month = BKP_ReadBackupRegister(BKP_DR3);
SYS_RTC.day = BKP_ReadBackupRegister(BKP_DR2);
if(RTC_GetCounter() / 86399 != 0)
{
for(i = 0; i < (RTC_GetCounter() / 86399); i++)
{
BSP_Date_Update(&SYS_RTC);
}
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
RTC_SetCounter(RTC_GetCounter() % 86399);
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR4, SYS_RTC.year);
BKP_WriteBackupRegister(BKP_DR3, SYS_RTC.month);
BKP_WriteBackupRegister(BKP_DR2, SYS_RTC.day);
}
}
/* Clear the RTC Second Interrupt pending bit */
RTC_ClearITPendingBit(RTC_IT_SEC); // 防止系统初始化未完成前进入中断程序
RTC_ClearFlag(RTC_IT_SEC);
/* Enable one second interrupe */
//RTC_ITConfig(RTC_IT_SEC, ENABLE); // 不能在系统运行前使能中断
rtcInitFinish =1; // 设置初始化完成标志
}
void BSP_RTC_Config(void)
{
//u32 counter = 0;
uint32_t tmp = 0;
RCC_ClocksTypeDef RCC_Clocks;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
/* Reset Backup Domain */
BKP_DeInit();
RCC_LSICmd(ENABLE); //启用LSI
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
{}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE); // Enable RTC Clock
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(40000); // RTC period = RTCCLK/RTC_PR = (4 KHz)/(4000+1) LSI
RTC_WaitForLastTask();
BKP_TamperPinCmd(DISABLE);
BKP_RTCOutputConfig(BKP_RTCOutputSource_Second);
RCC_GetClocksFreq(&RCC_Clocks);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM5, &TIM_ICInitStructure);
OperationComplete = 0;
TIM_Cmd(TIM5, ENABLE);
TIM5->SR = 0;
//TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);
while (OperationComplete != 2)
{
if (TIM_GetFlagStatus(TIM5, TIM_FLAG_CC4) == SET)
{
tmpCC4[IncrementVar_OperationComplete()] = (uint16_t)(TIM5->CCR4);
TIM_ClearFlag(TIM5, TIM_FLAG_CC4);
if (GetVar_OperationComplete() >= 2)
{
tmp = (uint16_t)(tmpCC4[1] - tmpCC4[0] + 1);
SetVar_PeriodValue(tmp);
}
}
}
if (PeriodValue != 0)
{
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
LsiFreq = (uint32_t)((uint32_t)(RCC_Clocks.PCLK1_Frequency) / (uint32_t)PeriodValue);
#else
LsiFreq = (uint32_t)((uint32_t)(RCC_Clocks.PCLK1_Frequency * 2) / (uint32_t)PeriodValue);
#endif
}
RTC_SetPrescaler(LsiFreq - 1);
RTC_WaitForLastTask();
TIM_DeInit( TIM5 );
}
void RTC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
/* Reset Backup Domain */
BKP_DeInit();
//使用外部高速晶振8M/128 = 62.5K
RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
//允许RTC
RCC_RTCCLKCmd(ENABLE);
//等待RTC寄存器同步
RTC_WaitForSynchro();
RTC_WaitForLastTask();
//允许RTC的秒中断(还有闹钟中断和溢出中断可设置)
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
//62500晶振预分频值是62500,不过一般来说晶振都不那么准
RTC_SetPrescaler(62498); //如果需要校准晶振,可修改此分频值
RTC_WaitForLastTask();
//清除标志
RCC_ClearFlag();
}
~END~
版权声明:版权归原作者所有,如有侵权,请联系我们删除!
获取电子硬件知识,点击下方关注我们
▽

✪ ✪ ✪