【转】GD32105R例程---RTC实现万年历

[复制链接]
3119|7
 楼主| Elric_QZH 发表于 2015-8-30 09:10 | 显示全部楼层 |阅读模式
本帖最后由 Elric_QZH 于 2015-8-30 09:11 编辑

最近学习GD32F105的板子,发现论坛例程不多,找了点例程分享

    GD32 105R_STAR的后备寄存器(10个16位的寄存器)可以用于在关闭VDD时,保存20个字节的用户应用数据。RTC和后备寄存器不会被系统或电源复位源复位;当从待机模式唤醒时,也不会被复位。
    楼主在本次试验中,采用的后备寄存器的BKP_DR1进行标志位的存储,供应用程序查询判断。如果标志位被更改,则进行RTC的初始化设置,否则跳过,代码如下:
  1. /*****************************************************************************

  2. *函数名称:void RtcInit(uint16 *time)

  3. *函数功能: 按照默认值初始化实时时钟,秒值增加一次后产生中断.

  4. *入口参数:time:初始化时间指针

  5. *出口参数:

  6. *日期:2015 4 6

  7. *版本:V1.0

  8. *作者:yrj

  9. *****************************************************************************/

  10. void RtcInit(uint16 *time)

  11. {  

  12.    if(BKP_ReadBackupRegister(BKP_DR1)!=0xAAAA) /*未设置过,开始初始化*/

  13.    {  

  14.      RTC_Configuration();  /*初始化RTC*/

  15.      RTC_Set(time);/*默认时间 */

  16.      BKP_WriteBackupRegister(BKP_DR1,0xAAAA );

  17.    }

  18.    else /*系统继续计时*/

  19.    {

  20.    if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) /*电复位*/

  21.            {}

  22.    else if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) /*管脚复位*/

  23.            {}

  24.      RCC_RTCCLKCmd(ENABLE);  //开启备份寄存器时钟

  25.      RTC_WaitForSynchro();   //

  26.      RTC_WaitForLastTask();  //等待RTC寄存器操作完成

  27.      RTC_ITConfig(RTC_IT_SEC,ENABLE); /*允许秒中断*/

  28.      RTC_WaitForLastTask();    /*等待RTC寄存器操作完成*/

  29.    }

  30. }

  31.     根据当前的实际时钟,对RTC的初始化设置,并使其产生1秒的周期定时,RTC初始化代码如下:

  32. /*

  33. ****************************************************************************

  34. *函数名称:u8 RTC_Set(uint16 *tim )

  35. *函数功能: 设置时钟,以1970年1月1日为基准//1970~2099年为合法年份

  36. *入口参数:

  37. *出口参数:

  38. *日期:2015 4 6

  39. *版本:V1.0

  40. *作者:yrj  

  41. ****************************************************************************

  42. */

  43. /*平年的月份日期表*/

  44. const uint8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};


  45. u8 RTC_Set(uint16 *tim )

  46. {  

  47. uint16 syear=tim[0],smon=tim[1],sday=tim[2],hour=tim[3],min=tim[4],sec=tim[5];

  48. u16 t;

  49. u32 seccount=0;

  50. if(syear<2000||syear>2099)return 1;/*syear范围1970-2099,此处设置范围为2000-2099 */

  51. for(t=1970;t<syear;t++) /*把所有年份的秒钟相加*/

  52. {

  53.    if(Is_Leap_Year(t))seccount+=31622400;/*闰年的秒钟数*/

  54.    else seccount+=31536000;              /*平年的秒钟数*/

  55. }

  56. smon-=1;

  57. for(t=0;t<smon;t++)         /*把前面月份的秒钟数相加*/

  58. {

  59.      seccount+=(u32)mon_table[t]*86400;/*月份秒钟数相加*/

  60.      if(Is_Leap_Year(syear)&&t==1) seccount+=86400;/*闰年2月份增加一天的秒钟数*/

  61. }

  62. seccount+=(u32)(sday-1)*86400;/*把前面日期的秒钟数相加 */

  63. seccount+=(u32)hour*3600;/*小时秒钟数*/

  64. seccount+=(u32)min*60;   /*分钟秒钟数*/

  65. seccount+=sec;/*最后的秒钟加上去*/


  66. /*设置时钟*/

  67. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器

  68. RTC_WaitForLastTask();

  69. RTC_SetCounter(seccount); /*设置时钟*/

  70. RTC_WaitForLastTask();

  71. return 0;      

  72. }

  73.     关于闰年平年的计算:

  74. /*

  75. ****************************************************************************

  76. *函数名称:u8 Is_Leap_Year(u16 year)

  77. *函数功能: //判断是否是闰年函数

  78. *入口参数:

  79. *出口参数:

  80. *日期:2015 4 6

  81. *版本:V1.0

  82. *作者:yrj

  83. ****************************************************************************

  84. */

  85. u8 Is_Leap_Year(u16 year)

  86. {                    

  87.   if(year%4==0) /*必须能被4整除*/

  88.   {

  89.    if(year%100==0)

  90.    {

  91.        if(year%400==0) {return 1;}/*如果以00结尾,还要能被400整除*/

  92.        else {return 0;}

  93.    }

  94.      else

  95.      { return 1; }

  96.   }

  97.   else{ return 0; }

  98. }

  99.     在RTC的秒中断服务函数中,对年月日时分秒进行提取,用于万年历的显示,另外还可以根据具体的实际项目需要,进行设计开发,如每天0时定时开启风机等。。。

  100. /*

  101. ****************************************************************************

  102. *函数名称:void RtcException(void)

  103. *函数功能: RTC中断服务函数 在函数中刷新实时日期时间,并发送消息邮箱

  104. *入口参数:无

  105. *出口参数:无

  106. *日期:2015 4 6

  107. *版本:V1.0

  108. *作者:yrj

  109. ****************************************************************************

  110. */

  111. void RtcException(void)

  112. {  

  113.    if(RTC_GetITStatus(RTC_IT_SEC)==SET)

  114.    {

  115.      RTC_WaitForLastTask();

  116.      RTC_ClearITPendingBit(RTC_IT_SEC);

  117.      RTC_WaitForLastTask();

  118.      /*读取当前时分秒*/

  119.      RTC_Get();  /* 刷新当前时间 提取 年、月、日、时、分、秒*/

  120.      if((0==timer.hour)&&(0==timer.min)&&(0==timer.sec))

  121.      {  

  122.        //启动排风,或是设置闹钟。。。自由发挥喽

  123.      }

  124.    }

  125. }

  126.     在GD32 105R 的RTC中断中,对于RTC计数值中年月日时分秒的提取:

  127. /*

  128. ****************************************************************************

  129. *函数名称:u8 RTC_Get(void)

  130. *函数功能: 得到当前的时间 ,RTC2Timer

  131. *入口参数:

  132. *出口参数:

  133. *日期:2015 4 6

  134. *版本:V1.0

  135. *作者:yrj

  136. ****************************************************************************

  137. */

  138. u8 RTC_Get(void)

  139. {

  140.   static u16 daycnt=0;

  141.   u32 timecount=0;

  142.   u32 temp=0;

  143.   u16 temp1=0;

  144.   timecount=RTC_GetCounter();

  145.   temp=timecount/86400;   /*得到天数(秒钟数对应的)*/

  146.   if(daycnt!=temp)/*超过一天了*/

  147.   {      

  148.      daycnt=temp;

  149.      temp1=1970;  /*从1970年开始*/

  150.      while(temp>=365)

  151.      {                          

  152.       if(Is_Leap_Year(temp1))/*是闰年*/  

  153.       {

  154.        if(temp>=366)temp-=366;/*闰年的秒钟数*/

  155.        else {temp1++;break;}  

  156.       }

  157.       else temp-=365;       /*平年 */

  158.       temp1++;  

  159.      }  

  160.      timer.w_year=temp1;    /*得到年份*/

  161.      temp1=0;

  162.      while(temp>=28)  /*超过了一个月*/

  163.      {

  164.       if(Is_Leap_Year(timer.w_year)&&temp1==1)/*当年是不是闰年/2月份*/

  165. {

  166.        if(temp>=29)temp-=29;/*闰年的秒钟数*/

  167.        else break;

  168.       }

  169.       else

  170.       {

  171.        if(temp>=mon_table[temp1])temp-=mon_table[temp1];/*平年*/

  172.        else break;

  173.       }

  174.       temp1++;  

  175.      }

  176.      timer.w_month=temp1+1;   //得到月份

  177.      timer.w_date=temp+1;     //得到日期

  178.   }

  179.   temp=timecount%86400;       //得到秒钟数      

  180.   timer.hour=temp/3600;       //小时

  181.   timer.min=(temp%3600)/60;   //分钟      

  182.   timer.sec=(temp%3600)%60;   //秒钟

  183.   timer.week=RTC_Get_Week(timer.w_year,timer.w_month,timer.w_date); /*获取星期*/



  184.   timer.year=timer.w_year-2000; //专为显示用年 14 7 22

  185.   return 0;

  186. }   

  187.     对于星期的判断:

  188. /*

  189. ****************************************************************************

  190. *函数名称:RTC_Get_Week(u16 year,u8 month,u8 day)

  191. *函数功能: 获得现在是星期几,输入公历日期得到星期(只允许1901-2099年)

  192. *入口参数:公历年月日

  193. *出口参数:星期号

  194. *日期:2015 4 6

  195. *版本:V1.0

  196. *作者:yrj

  197. ****************************************************************************

  198. */

  199. u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; /*月修正数据表*/

  200. u8 RTC_Get_Week(u16 year,u8 month,u8 day)

  201. {   

  202.   u16 temp2;

  203.   u8 yearH,yearL;

  204.   yearH=year/100;     yearL=year%100;

  205.   /*如果为21世纪,年份数加100 */

  206.   if (yearH>19)yearL+=100;

  207.   /* 所过闰年数只算1900年之后的  */

  208.   temp2=yearL+yearL/4;

  209.   temp2=temp2%7;

  210.   temp2=temp2+day+table_week[month-1];

  211.   if (yearL%4==0&&month<3)temp2--;

  212.   return(temp2%7);

  213. }


justperky 发表于 2015-8-30 23:01 | 显示全部楼层
支持下,GD的例程本来就不多,但这个用的好像不是GD的库
哆来咪 发表于 2015-8-31 18:02 | 显示全部楼层
后备寄存器,可以简单的做eeprom用,可以存储几个简单的全局标志位
eggbiscuit 发表于 2015-8-31 21:54 | 显示全部楼层
感觉RTC的万年历有点麻烦,没有1302之类的芯片方便,只要初始化OK句自动运行了,还得判断
小小少年苦中乐 发表于 2015-8-31 22:27 | 显示全部楼层
还得自己判断是否平年闰年之类的,不能都集成进去么
电子玩霸 发表于 2015-8-31 23:15 | 显示全部楼层
还是用专门的RTC芯片方便点
 楼主| Elric_QZH 发表于 2017-11-25 12:42 | 显示全部楼层
eggbiscuit 发表于 2015-8-31 21:54
感觉RTC的万年历有点麻烦,没有1302之类的芯片方便,只要初始化OK句自动运行了,还得判断 ...

是的,这个没有集成进去,但是自带RTC节省了硬件方面的成本,软件的开销大了而已。
uygferfgf 发表于 2017-11-26 15:10 | 显示全部楼层
这个东西量产吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

133

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部