硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2826|回复: 3
收起左侧

[有问必答] 请问rtc例程中,这里需要再次打开rtc的时钟吗?

[复制链接]

32

主题

103

回帖

199

积分

高级会员

积分
199
发表于 2018-11-21 14:15:40 | 显示全部楼层 |阅读模式
本来是有的,然后注释掉了
  1. if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
  2.         {
  3.                         /* 上电复位 */
  4.         }
  5.         else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
  6.         {
  7.             /* 外部RST管脚复位 */
  8.         }
  9.         /* 清除RCC中复位标志 */
  10.         RCC_ClearFlag();
  11.         
  12.                 //虽然RTC模块不需要重新配置,且掉电后依靠后备电池依然运行
  13.         //但是每次上电后,还是要使能RTCCLK???????
  14.         //RCC_RTCCLKCmd(ENABLE);
  15.         //等待RTC时钟与APB1时钟同步
  16.         //RTC_WaitForSynchro();
  17.         
  18.         //使能秒中断
  19.         //RTC_ITConfig(RTC_IT_SEC, ENABLE);
  20.         
  21.         //等待操作完成
  22.         RTC_WaitForLastTask();
  23.     }
复制代码


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107265
QQ
发表于 2018-11-22 01:17:21 | 显示全部楼层
我们的:

  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : STM32内部RTC模块
  5. *        文件名称 : bsp_cpu_rtc.h
  6. *        版    本 : V1.0
  7. *        说    明 : 头文件
  8. *
  9. *        修改记录 :
  10. *                版本号  日期       作者    说明
  11. *                v1.0    2015-08-08 armfly  首版.安富莱电子原创
  12. *
  13. *        修改记录 :
  14. *                版本号  日期       作者      说明
  15. *                v1.0    2015-09-11 Eric2013  RTC配置说明被修改,增加LSI
  16. *
  17. *        Copyright (C), 2015-2016, 安富莱电子 www.armfly.com
  18. *
  19. *********************************************************************************************************
  20. */

  21. #include "bsp.h"


  22. //#define RTC_Debug      /* 用于选择调试模式 */

  23. /* 选择RTC的时钟源 */
  24. #define RTC_CLOCK_SOURCE_LSE       /* LSE */
  25. //#define RTC_CLOCK_SOURCE_LSI       /* LSI */

  26. RTC_T g_tRTC;

  27. /* 平年的每月天数表 */
  28. const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  29. /*
  30. *********************************************************************************************************
  31. *        函 数 名: bsp_InitRTC
  32. *        功能说明: 初始化CPU内部RTC
  33. *        形    参:无
  34. *        返 回 值: 无
  35. *********************************************************************************************************
  36. */
  37. void bsp_InitRTC(void)
  38. {
  39.      uint16_t u16_WaitForOscSource;

  40.         /*
  41.                 在BKP的后备寄存器1中,存了一个特殊字符0xA5A5, 第一次上电或后备电源掉电后,该寄存器数据丢失,
  42.                 表明RTC数据丢失,需要重新配置
  43.         */
  44.     if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
  45.     {
  46.                 /* PWR时钟(电源控制)与BKP时钟(RTC后备寄存器)使能 */  
  47.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  48.                
  49.                 /* 使能RTC和后备寄存器访问 */  
  50.                 PWR_BackupAccessCmd(ENABLE);
  51.                
  52.                 /* 将外设BKP的全部寄存器重设为缺省值 */   
  53.                 BKP_DeInit();

  54. #if defined (RTC_CLOCK_SOURCE_LSE)
  55.                
  56.                 /* 使能LSE */               
  57.                 RCC_LSEConfig(RCC_LSE_ON);
  58.                
  59.                 #if 1
  60.                 for(u16_WaitForOscSource=0; u16_WaitForOscSource < 5000; u16_WaitForOscSource++)
  61.                 {
  62.                         ;
  63.                 }
  64.                 #endif
  65.                
  66.                  /* 等待外部晶振震荡稳定输出 */  
  67.                 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
  68.                
  69.                 /* 使用外部32.768KHz晶振作为RTC时钟 */
  70.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  71. #elif defined (RTC_CLOCK_SOURCE_LSI)
  72.                
  73.                 /* 使能LSI */
  74.                 RCC_LSICmd(ENABLE);

  75.                 /* 等待直到LSI就绪 */
  76.                 while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);

  77.                 /* 选择LSI作为RTC的时钟 */
  78.                 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);       
  79. #endif
  80.                
  81.                 /* 使能RTC时钟 */
  82.                 RCC_RTCCLKCmd(ENABLE);
  83.                
  84.                 /*
  85.               在APB1总线复位或者停止后重新开启,RTC的任何读取前得等待RTC寄存器
  86.               (RTC_CNT, RTC_ALR and RTC_PRL)跟RTC APB时钟同步。
  87.             */
  88.                 RTC_WaitForSynchro();
  89.                
  90.                 /* 等待RTC寄存器操作完成 */
  91.                 RTC_WaitForLastTask();

  92. #if defined (RTC_CLOCK_SOURCE_LSE)

  93.                 /* 32.768KHz晶振预分频值是32767,如果对精度要求很高可以修改此分频值来校准晶振 */
  94.                 RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */       
  95. #elif defined (RTC_CLOCK_SOURCE_LSI)

  96.                 /*
  97.                   1. LSI的频率典型值是40KHz(30KHz到60KHz)
  98.                   2. 这里按40KHz来计算
  99.                          RTC 周期 = RTCCLK / RTC_PR = (40 KHz)/(39999 + 1) = 1Hz
  100.                 */
  101.                 RTC_SetPrescaler(39999);
  102. #endif
  103.                
  104.                 /* 等待RTC寄存器操作完成 */
  105.                 RTC_WaitForLastTask();
  106.                
  107.                 /* 设置默认时间 */
  108.                 RTC_WriteClock(2015, 8, 8, 0, 0, 0);
  109.                
  110.         /* 配置完成后,向后备寄存器中写特殊字符0xA5A5 */
  111.         BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
  112.                
  113.                 /* 打印调试信息 */
  114.                 #ifdef RTC_Debug
  115.                         printf("重新配置后使用RTC \n\r");
  116.                 #endif
  117.                
  118.                 /* 检测上电复位标志是否设置 */
  119.                 if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
  120.                 {
  121.                         /* 发生上电复位 */
  122.                         #ifdef RTC_Debug
  123.                                 printf("发生上电复位 \n\r");
  124.                         #endif
  125.                 }
  126.     }
  127.     else
  128.         {
  129.                 /* 若后备寄存器没有掉电,则无需重新配置RTC */
  130.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  131.                
  132.                 for (u16_WaitForOscSource = 0; u16_WaitForOscSource < 5000; u16_WaitForOscSource++)
  133.                 {
  134.                         ;
  135.                 }
  136.                
  137.                 /* 打印调试信息 */
  138.                 #ifdef RTC_Debug
  139.                         printf("第n次使用RTC \n\r");
  140.                 #endif
  141.                 /* 检测上电复位标志是否设置 */
  142.                 if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
  143.                 {
  144.                         /* 发生上电复位 */
  145.                         #ifdef RTC_Debug
  146.                                 printf("发生上电复位 \n\r");
  147.                         #endif
  148.                 }
  149.                 /* 检测引脚复位标志是否设置 */
  150.                 else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
  151.                 {
  152.                         /* 发生引脚复位 */
  153.                         #ifdef RTC_Debug
  154.                                 printf("发生引脚复位 \n\r");     
  155.                         #endif   
  156.                 }
  157.                
  158.         /* 清除RCC中复位标志 */
  159.         RCC_ClearFlag();
  160.       
  161.     }
  162.         return;
  163. }

  164. /*
  165. *********************************************************************************************************
  166. *        函 数 名: Is_Leap_Year
  167. *        功能说明: 判断是否为闰年
  168. *        形    参:无
  169. *        返 回 值: 1,是.0,不是
  170. *********************************************************************************************************
  171. */
  172. static uint8_t Is_Leap_Year(uint16_t _year)
  173. {                     
  174.         if (_year % 4 == 0) /* 必须能被4整除 */
  175.         {
  176.                 if (_year % 100 == 0)
  177.                 {
  178.                         if (_year % 400 == 0)
  179.                         {
  180.                                 return 1;        /* 如果以00结尾,还要能被400整除 */
  181.                         }
  182.                         else
  183.                         {
  184.                                 return 0;   
  185.                         }

  186.                 }
  187.                 else
  188.                 {
  189.                         return 1;   
  190.                 }
  191.         }
  192.         else
  193.         {
  194.                 return 0;
  195.         }
  196. }      

  197. /*
  198. *********************************************************************************************************
  199. *        函 数 名: RTC_WriteClock
  200. *        功能说明: 设置RTC时钟
  201. *        形    参:无
  202. *        返 回 值: 1表示成功 0表示错误
  203. *********************************************************************************************************
  204. */
  205. uint8_t RTC_WriteClock(uint16_t _year, uint8_t _mon, uint8_t _day, uint8_t _hour, uint8_t _min, uint8_t _sec)
  206. {
  207.         uint16_t t;
  208.         uint32_t seccount=0;

  209.         if (_year < 2000 || _year > 2099)
  210.         {
  211.                 return 0;        /* _year范围1970-2099,此处设置范围为2000-2099 */   
  212.         }               
  213.        
  214.         for (t = 1970; t < _year; t++)         /* 把所有年份的秒钟相加 */
  215.         {
  216.                 if (Is_Leap_Year(t))                /* 判断是否为闰年 */
  217.                 {
  218.                         seccount += 31622400;        /* 闰年的秒钟数 */
  219.                 }
  220.                 else
  221.                 {
  222.                         seccount += 31536000;         /* 平年的秒钟数 */
  223.                 }
  224.         }

  225.         _mon -= 1;

  226.         for (t = 0; t < _mon; t++)         /* 把前面月份的秒钟数相加 */
  227.         {
  228.                 seccount += (uint32_t)mon_table[t] * 86400;        /* 月份秒钟数相加 */

  229.                 if (Is_Leap_Year(_year) && t == 1)
  230.                 {
  231.                         seccount += 86400;        /* 闰年2月份增加一天的秒钟数 */
  232.                 }                       
  233.         }

  234.         seccount += (uint32_t)(_day - 1) * 86400;        /* 把前面日期的秒钟数相加 */

  235.         seccount += (uint32_t)_hour * 3600;                /* 小时秒钟数 */

  236.         seccount += (uint32_t)_min * 60;        /* 分钟秒钟数 */

  237.         seccount += _sec;        /* 最后的秒钟加上去 */
  238.                                                                                                                                        
  239.         PWR_BackupAccessCmd(ENABLE);        /* 必须要 */

  240.         RTC_WaitForLastTask();

  241.         RTC_SetCounter(seccount);

  242.         RTC_WaitForLastTask();                        /* 必须加 PWR_BackupAccessCmd(ENABLE); 不然进入死循环 */

  243.         return 1;      
  244. }

  245. /*
  246. *********************************************************************************************************
  247. *        函 数 名: RTC_ReadClock
  248. *        功能说明: 得到当前时钟。结果存放在 g_tRTC。
  249. *        形    参:无
  250. *        返 回 值: 1表示成功 0表示错误
  251. *********************************************************************************************************
  252. */
  253. void RTC_ReadClock(void)
  254. {
  255.         static uint16_t daycnt = 0;
  256.         uint32_t timecount = 0;
  257.         uint32_t temp = 0;
  258.         uint16_t temp1 = 0;

  259.         timecount = RTC_GetCounter();     

  260.         temp = timecount / 86400;   /* 得到天数 */

  261.         if (daycnt != temp)        /* 超过一天了 */
  262.         {      
  263.                 daycnt = temp;
  264.                 temp1 = 1970;  /* 从1970年开始 */

  265.                 while (temp >= 365)
  266.                 {                          
  267.                         if (Is_Leap_Year(temp1))        /* 是闰年 */
  268.                         {
  269.                                 if (temp >= 366)
  270.                                 {
  271.                                         temp -= 366;                /* 闰年的秒钟数 */
  272.                                 }
  273.                                 else
  274.                                 {
  275.                                         //temp1++;                /* armfly: 这里闰年处理错误,不能加1 */
  276.                                         break;
  277.                                 }  
  278.             }
  279.                         else
  280.                         {
  281.                                 temp -= 365;       /* 平年 */
  282.                         }
  283.                         temp1++;  
  284.                 }   
  285.                 g_tRTC.Year = temp1;        /* 得到年份 */
  286.                
  287.                 temp1 = 0;
  288.                 while (temp >= 28)        /* 超过了一个月 */
  289.                 {
  290.                         if(Is_Leap_Year(g_tRTC.Year) && temp1 == 1)        /* 当年是不是闰年/2月份 */
  291.                         {
  292.                                 if (temp >= 29)
  293.                                 {
  294.                                         temp -= 29;        /* 闰年的秒钟数 */
  295.                                 }
  296.                                 else
  297.                                 {
  298.                                         break;
  299.                                 }
  300.             }
  301.             else
  302.                         {
  303.                                 if (temp >= mon_table[temp1])
  304.                                 {
  305.                                         temp -= mon_table[temp1];        /* 平年 */
  306.                                 }
  307.                                 else
  308.                                 {
  309.                                         break;
  310.                                 }
  311.                         }
  312.                         temp1++;  
  313.                 }
  314.                 g_tRTC.Mon = temp1 + 1;        /* 得到月份 */
  315.                 g_tRTC.Day = temp + 1;  /* 得到日期 */
  316.         }

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

  318.         g_tRTC.Hour = temp / 3600;        /* 小时 */

  319.         g_tRTC.Min = (temp % 3600) / 60; /* 分钟 */

  320.         g_tRTC.Sec = (temp % 3600) % 60; /* 秒钟 */

  321.         g_tRTC.Week = RTC_CalcWeek(g_tRTC.Year, g_tRTC.Mon, g_tRTC.Day);        /* 计算星期 */
  322. }   


  323. /*
  324. *********************************************************************************************************
  325. *        函 数 名: bsp_CalcWeek
  326. *        功能说明: 根据日期计算星期几
  327. *        形    参: _year _mon _day  年月日  (年是2字节整数,月和日是字节整数)
  328. *        返 回 值: 周几 (1-7) 7表示周日
  329. *********************************************************************************************************
  330. */
  331. uint8_t RTC_CalcWeek(uint16_t _year, uint8_t _mon, uint8_t _day)
  332. {
  333.         /*
  334.         蔡勒(Zeller)公式
  335.                 历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和
  336.         一些分段计算公式),其中最著名的是蔡勒(Zeller)公式。
  337.             即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1

  338.                 公式中的符号含义如下,
  339.              w:星期;
  340.              c:年的高2位,即世纪-1
  341.              y:年(两位数);
  342.              m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,
  343.                       比如2003年1月1日要看作2002年的13月1日来计算);
  344.              d:日;
  345.              [ ]代表取整,即只要整数部分。

  346.             算出来的W除以7,余数是几就是星期几。如果余数是0,则为星期日。
  347.         如果结果是负数,负数求余数则需要特殊处理:
  348.             负数不能按习惯的余数的概念求余数,只能按数论中的余数的定义求余。为了方便
  349.         计算,我们可以给它加上一个7的整数倍,使它变为一个正数,然后再求余数

  350.                 以2049年10月1日(100周年国庆)为例,用蔡勒(Zeller)公式进行计算,过程如下:
  351.                 蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
  352.                 =49+[49/4]+[20/4]-2×20+[26× (10+1)/10]+1-1
  353.                 =49+[12.25]+5-40+[28.6]
  354.                 =49+12+5-40+28
  355.                 =54 (除以7余5)
  356.                 即2049年10月1日(100周年国庆)是星期5。
  357.         */
  358.         uint8_t y, c, m, d;
  359.         int16_t w;

  360.         if (_mon >= 3)
  361.         {
  362.                 m = _mon;
  363.                 y = _year % 100;
  364.                 c = _year / 100;
  365.                 d = _day;
  366.         }
  367.         else        /* 某年的1、2月要看作上一年的13、14月来计算 */
  368.         {
  369.                 m = _mon + 12;
  370.                 y = (_year - 1) % 100;
  371.                 c = (_year - 1) / 100;
  372.                 d = _day;
  373.         }

  374.         w = y + y / 4 +  c / 4 - 2 * c + ((uint16_t)26*(m+1))/10 + d - 1;
  375.         if (w == 0)
  376.         {
  377.                 w = 7;        /* 表示周日 */
  378.         }
  379.         else if (w < 0)        /* 如果w是负数,则计算余数方式不同 */
  380.         {
  381.                 w = 7 - (-w) % 7;
  382.         }
  383.         else
  384.         {
  385.                 w = w % 7;
  386.         }
  387.         return w;
  388. }

  389. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
复制代码


回复

使用道具 举报

32

主题

103

回帖

199

积分

高级会员

积分
199
 楼主| 发表于 2018-11-22 09:21:30 | 显示全部楼层

我就是复制的你的,可能版本有变化吧。我再调调,现在一写完年份就编程2034年
回复

使用道具 举报

3

主题

7

回帖

16

积分

新手上路

积分
16
发表于 2019-8-14 16:53:28 | 显示全部楼层
貌似下载的软件包里面都不是最新的,都还是8-8号的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-23 20:56 , Processed in 0.275697 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表