利用RTC时钟完成显示日期

RTC时钟实验(复习rtc)

今天周日休息时间,复习下了RTC,想在买的开发板做个时钟出来

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

直接上rtc部分代码,不发原理图

  1. 配置NVIC中断函数
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寄存器
}
  1. 配置rtc
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(2020,4,12,17,42,55);  //设置时间 
  RTC_ExitConfigMode(); //退出配置模式  
  BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据
  }
 else//系统继续计时
  {

  RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成
  RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
  RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
  }
 RTC_NVIC_Config();//RCT中断分组设置               
 RTC_Get();//更新时间 
 return 0; //ok

}           
  1. 配置rtc中断条件
//RTC时钟中断
//每秒触发一次  
//extern u16 tcnt; 
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();                     
}

//判断是否是闰年函数

月份 1 2 3 4 5 6 7 8 9 10 11 12
闰年 31 29 31 30 31 30 31 31 30 31 30 31/非闰年 31 28 31 30 31 30 31 31 30 31 30 31
输入:

u8 Is_Leap_Year(u16 year)
{     
 if(year%4==0) //必须能被4整除
 { 
  if(year%100==0) 
  { 
   if(year%400==0)return 1;//如果以00结尾,还要能被400整除     
   else return 0;   
  }else return 1;   
 }else return 0; 
}        
//设置时钟
//把输入的时钟转换为秒钟
//以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;     
}

//初始化闹钟    
//以1970年1月1日为基准
//1970~2099年为合法年份
//syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
//返回值:0,成功;其他:错误代码.
u8 RTC_Alarm_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外设时
发布了4 篇原创文章 · 获赞 2 · 访问量 12

猜你喜欢

转载自blog.csdn.net/weixin_44547715/article/details/105474833