STM32 RTC 编程

 #ifndef  RTC_H
#define  RTC_H

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
//#include "Gpio.h"
//#include "USART.h"
typedef struct 
{
    unsigned  char  hour;
    unsigned  char  min;
    unsigned  char  sec;  

    //公历年月日周
    unsigned short    int w_year;
    unsigned  char   w_month;
    unsigned  char   w_date;
    unsigned  char   week;     
}t_timer; 



void RTC_Configuration(void);

void RTC_Init(void);

unsigned  char  RTC_Get(void);

unsigned  char  RTC_Set(u16 year,unsigned  char  mon,unsigned  char  day,unsigned  char  hour,unsigned  char  min,unsigned  char  sec);

void  RtcTestByLxl();

#endif



#include "RTC.h"
#include "rtc.h"  
//时间结构体

t_timer calendar;    //时钟结构体
//平均的月份日期表
const unsigned  char  mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};


unsigned  char  RTC_Set(u16 year,unsigned  char  mon,unsigned  char  day,unsigned  char  hour,unsigned  char  min,unsigned  char  sec) ;
unsigned  char  RTC_Get(void) ;


/**
  * @brief  RTC配置
  * @param  None
  * @retval None
  */
void RTC_Configuration(void)
{   
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE );
    PWR_BackupAccessCmd(ENABLE);                           //允许访问BKP备份域

    BKP_DeInit();                                            //复位备份域

    RCC_LSEConfig(RCC_LSE_ON);                             //开启LSE

    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)    //等待LSE起振
    {}
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //选择LSE为RTC时钟源

    RCC_RTCCLKCmd(ENABLE);                                 //RTC时钟使能

    RTC_WaitForSynchro();                                    //等待RTC寄存器同步

    RTC_WaitForLastTask();                                 //等待最后对RTC寄存器的写操作完成


    RTC_ITConfig(RTC_IT_SEC, ENABLE);                        //RTC中断使能

    RTC_WaitForLastTask();                                 //等待最后对RTC寄存器的写操作完成

    RTC_SetPrescaler(32767); //设置RTC时钟分频值32767,则计数频率= (32.768 KHz)/(32767+1)=1Hz(1s)

    RTC_WaitForLastTask();    //等待最后对RTC寄存器的写操作完成

}



unsigned  char  Is_Leap_Year(u16 pyear)
{
    if(pyear%4==0)//首先需能被4整除
    {
        if(pyear%100==0)
        {
            if(pyear%400==0)    return 1;//如果以00结尾,还要能被400整除
            else    return 0;
        }
        else
            return 1;
    }
    else
        return 0;
}


/*
得到当前的时间
成功返回0,错误返回其它
*/
unsigned  char  RTC_Get(void)
{
        static u16 dayCount=0;
        u32 secCount=0;
        u32 tmp=0;
        u16 tmp1=0;

        secCount=RTC_GetCounter();

        tmp=secCount/86400;//得到天数
        if(dayCount!=tmp)//超过一天
        {
            dayCount=tmp;
            tmp1=1970;//从1970年开始
            while(tmp>=365)
            {
                if(Is_Leap_Year(tmp1))//是闰年
                {
                    if(tmp>=366)    
                        tmp-=366;//减掉闰年的天数
                    else
                    {
                    //    tmp1++;
                        break;
                    }
                }
                else
                    tmp-=365;//平年
                tmp1++;
            }
            calendar.w_year=tmp1;//得到年份
            tmp1=0;
            while(tmp>=28)//超过一个月
            {
                if(Is_Leap_Year(calendar.w_year)&&tmp1==1)//当年是闰年且轮循到2月
                {
                    if(tmp>=29)    
                        tmp-=29;
                    else
                        break;
                }
                else
                {
                    if(tmp>=mon_table[tmp1])//平年
                        tmp-=mon_table[tmp1];
                    else
                        break;
                }
                tmp1++;
            }
            calendar.w_month=tmp1+1;//得到月份,tmp1=0表示1月,所以要加1
            calendar.w_date=tmp+1;    //得到日期,因为这一天还没过完,所以tmp只到其前一天,但是显示的时候要显示正常日期
        }
        tmp=secCount%86400;//得到秒钟数
        calendar.hour=tmp/3600;//小时
        calendar.min=(tmp%3600)/60;//分钟
        calendar.sec=(tmp%3600)%60;//秒

        return 0;
}


/*
*设置时钟
*把输入的时钟转换为秒钟
*以1970年1月1日为基准
*1970~2099年为合法年份
返回值:0,成功;其它:错误
*/
unsigned  char  RTC_Set(u16 year,unsigned  char  mon,unsigned  char  day,unsigned  char  hour,unsigned  char  min,unsigned  char  sec)
{
    u16 t;
    u32 secCount=0;
    if(year<1970||year>2099)
        return 1;//3?′í
    for(t=1970;t<year;t++)    //把所有年份的秒钟相加
    {
        if(Is_Leap_Year(t))//闰年
            secCount+=31622400;//闰年的秒钟数
        else
            secCount+=31536000;    
    }
    mon-=1;//先减掉一个月再算秒数(如现在是5月10日,则只需要算前4个月的天数,再加上10天,然后计算秒数)
    for(t=0;t<mon;t++)
    {
        secCount+=(u32)mon_table[t]*86400;//月份秒钟数相加
        if(Is_Leap_Year(year)&&t==1)
         secCount+=86400;//闰年,2月份增加一天的秒钟数
    }

    secCount+=(u32)(day-1)*86400;//把前面日期的秒钟数相加(这一天还没过完,所以-1)
    secCount+=(u32)hour*3600;//小时秒钟数
    secCount+=(u32)min*60;//分钟秒钟数
    secCount+=sec;
//    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR    | RCC_APB1Periph_BKP,ENABLE);
//    PWR_BackupAccessCmd(ENABLE);
    RTC_SetCounter(secCount);//设置RTC计数器的值
    RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
    RTC_Get();//更新时间
    return 0;
}


/**
  * @brief  RTC初始化
  * @param  None
  * @retval None
  */
void RTC_Init(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置优先级分组

  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)             //判断BKP_DR1寄存器值是否为0xA5A5
    {

        printf("\r\n RTC not yet configured....");               //RTC尚未配置

        RTC_Configuration();                                   //RTC配置

        printf("\r\n RTC configured....");

    //  Time_Adjust();        
     RTC_Set(2017,9,10,10,11,12);       //调整时间值

        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);                //把0xA5A5写入BKP_DR1寄存器
    }
    else
    {

        if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)       //检查POWER是否发生复位标志
        {
            printf("\r\n\n Power On Reset occurred....");
        }

        else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)    //检查PIN复位标志设置
        {
            printf("\r\n\n External Reset occurred....");
        }

        printf("\r\n No need to configure RTC....");
        RTC_WaitForSynchro();                                   //等待RTC寄存器同步

        RTC_ITConfig(RTC_IT_SEC, ENABLE);                       //RTC中断使能

        RTC_WaitForLastTask();                                //等待最后对RTC寄存器的写操作完成
    }

//#ifdef RTCClockOutput_Enable

//  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
//  
//  PWR_BackupAccessCmd(ENABLE);                            //允许访问BKP备份域
//  
//  BKP_TamperPinCmd(DISABLE);                            //禁用Tamper引脚
//  
//  BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);  //使能时钟输出篡改引脚
//#endif

    RCC_ClearFlag();                                      //清除标志位

}


/*
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_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);//清闹钟中断
    RTC_WaitForLastTask();                                                   
}

unsigned  char  t=0;

void  RtcTestByLxl()
{
     if(t!=calendar.sec)
            {
                    t=calendar.sec;
                    printf("\r\n now is %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒 \r\n ", calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);
            }

}

利用Rtx内核时钟计算时间:
systick= osKernelSysTick();// 单位为10ns
这里写图片描述

猜你喜欢

转载自blog.csdn.net/tiger15605353603/article/details/81380294