RTCSetup.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*--------------------------------------------------------------------------------------
  2. * @file RTCSetup.c
  3. * @author ZhangJing
  4. * @version base on stm32f0x
  5. * @date 2015.09.11
  6. * @brief RTC驱动
  7. ---------------------------------------------------------------------------------------*/
  8. #include "stm32f10x_gpio.h"
  9. #include "stm32f10x_rtc.h"
  10. #include "stm32f10x_pwr.h"
  11. #include "stm32f10x_bkp.h"
  12. #include "stm32f10x_exti.h"
  13. #include "TypeDefine.h"
  14. #include "DrawLCDGUI.h"
  15. #include "RTCSetup.h"
  16. #include "FM31256.h"
  17. //extern SpeakerWorkType speakerWorkStep;//蜂鸣器工作步骤
  18. const uint8_t table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
  19. const uint8_t mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};//平年月份日期表
  20. static ErrorStatus HSEStartUpStatus;//HSE时钟启动状态
  21. /*********************************************************************************
  22. * Function: Is_Leap_Year
  23. * Object: 判断是否是闰年
  24. * 输入: 年份
  25. * 输出: 该年是不是闰年。1是 0不是
  26. * 备注: //月份 1 2 3 4 5 6 7 8 9 10 11 12
  27. //闰年 31 29 31 30 31 30 31 31 30 31 30 31
  28. //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
  29. **********************************************************************************/
  30. uint8_t Is_Leap_Year(uint16_t year)
  31. {
  32. if( year % 4 == 0 ) //必须能被4整除
  33. {
  34. if( year % 100 == 0 )
  35. {
  36. if( year % 400 == 0 )
  37. {
  38. return 1;//如果以00结尾,还能被400整除
  39. }
  40. else
  41. {
  42. return 0;
  43. }
  44. }
  45. else
  46. {
  47. return 1;
  48. }
  49. }
  50. else
  51. {
  52. return 0;
  53. }
  54. }
  55. /*********************************************************************************
  56. * Function: RTC_Get_Week
  57. * Object: 获得现在是星期几
  58. * 输入: 公历年月日
  59. * 输出: 星期号
  60. * 备注: 1、uint8_t yearH,yearL;年的高低字节计算
  61. * 2、uint16_t temp2;作为计算的临时变量
  62. **********************************************************************************/
  63. uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day)
  64. {
  65. uint16_t temp2;
  66. uint8_t yearH,yearL;
  67. yearH = year / 100;
  68. yearL = year % 100;
  69. // 如果为21世纪,年份数加100
  70. if( yearH > 19 )
  71. {
  72. yearL += 100;
  73. }
  74. //所过闰年数只算1900年之后的
  75. temp2 = yearL + yearL / 4;
  76. temp2 = temp2 % 7;
  77. temp2 = temp2 + day + table_week[month - 1];
  78. if( yearL % 4 == 0 && month < 3 )
  79. {
  80. temp2--;
  81. }
  82. return( temp2 % 7 );
  83. }
  84. /*********************************************************************************
  85. * Function: RTC_Set
  86. * Object: 设置时钟
  87. * 输入: 月份数据表
  88. * 输出: 0:成功 其它:错误代码
  89. * 备注: 把输入的时钟转换为秒钟
  90. * 以1970年1月1日为基准
  91. * 1970~2099年为合法年份
  92. **********************************************************************************/
  93. uint8_t RTC_Set(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t hour,uint8_t min,uint8_t sec)
  94. {
  95. uint16_t t;
  96. uint32_t seccount=0;
  97. // RTC_ITConfig(RTC_IT_SEC, DISABLE); //关闭秒中断
  98. // RTC_WaitForLastTask();
  99. if( syear < 2015 || syear > 2099 )
  100. {
  101. return 1;//syear范围1970-2099,此处范围设置为2015-2099
  102. }
  103. for( t = 1970;t < syear;t++) //把所有年份的秒钟相加
  104. {
  105. if( Is_Leap_Year( t ) )
  106. {
  107. seccount += 31622400;//闰年的秒钟数
  108. }
  109. else
  110. {
  111. seccount += 31536000;//平年的秒钟数
  112. }
  113. }
  114. smon -= 1;
  115. for( t = 0;t < smon;t++ ) //把前面月份的秒钟数相加
  116. {
  117. seccount += (uint32_t)mon_table[t] * 86400;//月份秒钟数相加
  118. if( Is_Leap_Year( syear ) && ( t == 1 ) )
  119. {
  120. seccount += 86400;//闰年2月份增加一天的秒钟数
  121. }
  122. }
  123. seccount += (uint32_t)( sday - 1 ) * 86400;//把前面日期的秒钟数相加
  124. seccount += (uint32_t)hour * 3600;//小时秒钟数
  125. seccount += (uint32_t)min * 60;//分钟秒钟数
  126. seccount += sec;//最后的秒钟数加上去
  127. //设置时钟
  128. // RCC->APB1ENR|=1<<28;//使能电源时钟
  129. // RCC->APB1ENR|=1<<27;//使能备份时钟
  130. // PWR->CR|=1<<8; //取消备份区写保护
  131. // //以上三步是必须的!
  132. RTC_WaitForLastTask();
  133. RTC_SetCounter(seccount);
  134. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  135. PWR_BackupAccessCmd(ENABLE);
  136. RTC_WaitForLastTask();
  137. RTC_ITConfig(RTC_IT_SEC, ENABLE); //打开秒中断
  138. return 0;
  139. }
  140. /*********************************************************************************
  141. * Function: RTC_Get
  142. * Object: 得到当前时间
  143. * 输入: 无
  144. * 输出: 0:成功 其它:错误代码
  145. * 备注: 1、static uint16_t daycnt=0;天数计算
  146. * 2、uint32_t timecount=0;时间计算
  147. * 3、uint32_t temp=0;临时变量
  148. * 4、uint16_t temp1=0;临时变量
  149. **********************************************************************************/
  150. uint8_t RTC_Get(void)
  151. {
  152. static uint16_t daycnt=0;
  153. uint32_t timecount=0;
  154. uint32_t temp=0;
  155. uint16_t temp1=0;
  156. timecount = RTC_GetCounter();
  157. // timecount=RTC->CNTH;//得到计数器中的值(秒钟数)
  158. // timecount<<=16;
  159. // timecount+=RTC->CNTL;
  160. temp = timecount / 86400; //得到天数(秒钟数对应的)
  161. if( daycnt != temp )//超过一天了
  162. {
  163. daycnt = temp;
  164. temp1 = 1970; //从1970开始
  165. while( temp >= 365 )
  166. {
  167. if( Is_Leap_Year( temp1 ) )//是闰年
  168. {
  169. // if( temp >= 366 )
  170. // {
  171. // temp -= 366;//闰年的秒钟数
  172. // }
  173. // else
  174. // {
  175. // temp1++;
  176. // break;
  177. // }
  178. temp -= 366;//闰年的秒钟数
  179. }
  180. else
  181. {
  182. temp -= 365; //平年
  183. // temp1++;
  184. }
  185. temp1++;
  186. }
  187. displayTimeBuf.year = temp1;//得到年份
  188. temp1 = 0;
  189. while( temp >= 28 )//超过了一个月
  190. {
  191. if( Is_Leap_Year( displayTimeBuf.year ) && ( temp1 == 1 ) )//当年是不是闰年/2月份
  192. {
  193. if( temp >= 29 )
  194. {
  195. temp -= 29;//闰年的秒钟数
  196. }
  197. else
  198. {
  199. break;
  200. }
  201. }
  202. else
  203. {
  204. if( temp >= mon_table[temp1] )
  205. {
  206. temp -= mon_table[temp1];//平年
  207. }
  208. else
  209. {
  210. break;
  211. }
  212. }
  213. temp1++;
  214. }
  215. displayTimeBuf.month = temp1 + 1;//得到月份
  216. displayTimeBuf.date = temp + 1; //得到日期
  217. }
  218. temp = timecount % 86400; //得到秒钟数
  219. displayTimeBuf.hour = temp / 3600; //小时
  220. displayTimeBuf.minute = ( temp % 3600 ) / 60; //分钟
  221. displayTimeBuf.seconds = ( temp % 3600 ) %60; //秒钟
  222. //displayTimeBuf.week = RTC_Get_Week( displayTimeBuf.year,displayTimeBuf.month,displayTimeBuf.date );//获取星期
  223. return 0;
  224. }
  225. /*********************************************************************************
  226. * Function: RTCInit
  227. * Object: RTC计时功能初始化
  228. * 输入: 无
  229. * 输出: 无
  230. * 备注: uint16_t waitForOscSource;临时计算变量
  231. **********************************************************************************/
  232. void RTCInit(void)
  233. {
  234. uint16_t waitForOscSource;
  235. //在BKP后备寄存器1中,存储了一个特殊字符0xA5A5
  236. //第一次上电或后备电源掉电后,该寄存器数据丢失
  237. //表明RTC数据丢失,需重新配置
  238. if( BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5 )
  239. {
  240. //重新配置RTC
  241. /* Enable PWR and BKP clocks */
  242. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  243. /* Allow access to BKP Domain */
  244. PWR_BackupAccessCmd(ENABLE);
  245. /* Reset Backup Domain */
  246. BKP_DeInit();
  247. /* Enable LSE */
  248. RCC_LSEConfig(RCC_LSE_ON);
  249. for( waitForOscSource = 0;waitForOscSource < 5000;waitForOscSource++ )
  250. {
  251. }
  252. // /* Wait till LSE is ready */
  253. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
  254. /* Select LSE as RTC Clock Source */
  255. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  256. /* Enable RTC Clock */
  257. RCC_RTCCLKCmd(ENABLE);
  258. /* Wait for RTC registers synchronization */
  259. RTC_WaitForSynchro();
  260. // /* Wait until last write operation on RTC registers has finished */
  261. // RTC_WaitForLastTask();
  262. //
  263. // /* Enable the RTC Second */
  264. // RTC_ITConfig(RTC_IT_SEC, ENABLE);
  265. /* Wait until last write operation on RTC registers has finished */
  266. RTC_WaitForLastTask();
  267. /* Set RTC prescaler: set RTC period to 1sec */
  268. RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
  269. /* Wait until last write operation on RTC registers has finished */
  270. RTC_WaitForLastTask();
  271. //配置完成后,向后备电源写特殊字符0xA5A5
  272. BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
  273. RTC_Set(2015,01,01,0,0,0);//默认时间
  274. }
  275. else
  276. {
  277. //若后备电源没有掉电,则无需重新配置RTC
  278. //这里我们可以利用RCC_GetFlagStatus()函数查看本次复位类型
  279. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  280. for( waitForOscSource = 0;waitForOscSource < 5000;waitForOscSource++ );
  281. if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
  282. {
  283. //这是上电复位
  284. }
  285. else if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
  286. {
  287. //这是外部RESET管脚复位
  288. }
  289. //清除RCC中复位标志
  290. RCC_ClearFlag();
  291. //虽然RTC模块不需要配置,且掉电后依靠后备电源依然运行
  292. //但是每次上电后,还是要使能RTCCLK???????
  293. //RCC_RTCCLKCmd(ENABLE);
  294. //等待RTC时钟与APB1时钟同步
  295. //RTC_WaitForSynchro();
  296. //使能秒中断
  297. RTC_ITConfig(RTC_IT_SEC, ENABLE);
  298. //等待操作完成
  299. RTC_WaitForLastTask();
  300. }
  301. return;
  302. }
  303. /*********************************************************************************
  304. * Function: SystemTimeUpdate
  305. * Object: 系统时间更新
  306. * 输入: 无
  307. * 输出: 无
  308. * 备注: 1、通过 TaskSchedulerFlag.timeReadFlag标志位来判断是否更新时间
  309. * 2、每读取一次时间进行一次时间显示界面的刷新
  310. **********************************************************************************/
  311. void SystemTimeUpdate( void )
  312. {
  313. if( TaskSchedulerFlag.timeReadFlag == TASK_FLAG_SET )//时间读取
  314. {
  315. if( realTimeData.stateRun != Poweroff )
  316. {
  317. //获取当前时间
  318. if( speakerWorkStep != emSpeakerNoneWork)
  319. return;
  320. GetCurDateTimeFromRTC();
  321. if( emCurrentPicture == TimeDisp )//更新显示时间页面
  322. {
  323. emDisplayPicture = TimeDisp;
  324. }
  325. TaskSchedulerFlag.timeReadFlag = TASK_FLAG_CLEAR;
  326. }
  327. }
  328. }
  329. /*********************************************************************************
  330. * Function: RTC_NVIC_Config
  331. * Object: RTC中断配置
  332. * 输入: 无
  333. * 输出: 无
  334. * 备注: NVIC_InitTypeDef NVIC_InitStructure; 中断配置结构体
  335. **********************************************************************************/
  336. void RTC_NVIC_Config(void)
  337. {
  338. NVIC_InitTypeDef NVIC_InitStructure;
  339. NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断
  340. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级1位,从优先级3位
  341. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  342. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断
  343. NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定参数初始化外设NVIC寄存器
  344. }
  345. /*********************************************************************************
  346. * Function: RTC_Alarm_Configuration
  347. * Object: RTC闹钟初始化
  348. * 输入: 无
  349. * 输出: 无
  350. * 备注: 启动时钟、配置LSI做RTC时钟、设置预分频40000得到1Hz
  351. * 设置运行时间WORK_TIMES
  352. **********************************************************************************/
  353. void RTC_Alarm_Configuration(void)
  354. {
  355. /* Enable PWR and BKP clocks */
  356. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  357. /* Allow access to BKP Domain */
  358. PWR_BackupAccessCmd(ENABLE);
  359. /* Reset Backup Domain */
  360. BKP_DeInit();
  361. /* RTC clock source configuration ----------------------------------------*/
  362. /* Enable the LSI OSC */
  363. RCC_LSICmd(ENABLE);
  364. /* Wait till LSI is ready */
  365. while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  366. {
  367. }
  368. /* Select the RTC Clock Source */
  369. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  370. /* Enable the RTC Clock */
  371. RCC_RTCCLKCmd(ENABLE);
  372. /* Wait for RTC registers synchronization */
  373. RTC_WaitForSynchro();
  374. /* Wait until last write operation on RTC registers has finished */
  375. RTC_WaitForLastTask();
  376. /* 使能RTC闹钟中断*/
  377. RTC_ITConfig(RTC_IT_ALR, ENABLE);
  378. /* Wait until last write operation on RTC registers has finished */
  379. RTC_WaitForLastTask();
  380. /* Set RTC prescaler: set RTC period to 1sec */
  381. RTC_SetPrescaler(40000);
  382. /* Wait until last write operation on RTC registers has finished */
  383. RTC_WaitForLastTask();
  384. //中断配置
  385. RTC_NVIC_Config();
  386. //设置运行WORK_TIMES
  387. RTC_SetAlarm(RTC_GetCounter() + WORK_TIMES);
  388. RTC_WaitForLastTask();
  389. }
  390. /*********************************************************************************
  391. * Function: StopMode_Configuration
  392. * Object: 停止模式RTC闹钟初始化
  393. * 输入: 无
  394. * 输出: 无
  395. * 备注: 启动时钟、配置LSI做RTC时钟、设置预分频40000得到1Hz
  396. **********************************************************************************/
  397. void StopMode_Configuration(void)
  398. {
  399. EXTI_InitTypeDef EXTI_InitStructure;
  400. /* Enable PWR and BKP clocks */
  401. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  402. /* Allow access to BKP Domain */
  403. PWR_BackupAccessCmd(ENABLE);
  404. /* Reset Backup Domain */
  405. BKP_DeInit();
  406. /* RTC clock source configuration ----------------------------------------*/
  407. /* Enable the LSI OSC */
  408. RCC_LSICmd(ENABLE);
  409. /* Wait till LSI is ready */
  410. while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  411. {
  412. }
  413. /* Select the RTC Clock Source */
  414. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  415. /* Enable the RTC Clock */
  416. RCC_RTCCLKCmd(ENABLE);
  417. /* Wait for RTC registers synchronization */
  418. RTC_WaitForSynchro();
  419. /* Wait until last write operation on RTC registers has finished */
  420. RTC_WaitForLastTask();
  421. /* Set RTC prescaler: set RTC period to 1sec */
  422. RTC_SetPrescaler(40000);
  423. /* Wait until last write operation on RTC registers has finished */
  424. RTC_WaitForLastTask();
  425. /* Configure EXTI Line17(RTC Alarm) to generate an interrupt on rising edge */
  426. EXTI_ClearITPendingBit(EXTI_Line17);
  427. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
  428. EXTI_InitStructure.EXTI_Line = EXTI_Line17;
  429. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  430. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  431. EXTI_Init(&EXTI_InitStructure);
  432. }
  433. /*******************************************************************************
  434. * Function Name : SYSCLKConfig_STOP
  435. * Description : Configures system clock after wake-up from STOP: enable HSE, PLL
  436. * and select PLL as system clock source.
  437. * Input : None
  438. * Output : None
  439. * Return : None
  440. *******************************************************************************/
  441. void StopMode_SYSCLKConfig_STOP(void)
  442. {
  443. /* Enable HSE */
  444. RCC_HSEConfig(RCC_HSE_ON);
  445. /* Wait till HSE is ready */
  446. HSEStartUpStatus = RCC_WaitForHSEStartUp();
  447. if(HSEStartUpStatus == SUCCESS)
  448. {
  449. /* Enable PLL */
  450. RCC_PLLCmd(ENABLE);
  451. /* Wait till PLL is ready */
  452. while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  453. {
  454. }
  455. /* Select PLL as system clock source */
  456. RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  457. /* Wait till PLL is used as system clock source */
  458. while(RCC_GetSYSCLKSource() != 0x08)
  459. {
  460. }
  461. }
  462. }
  463. /*********************************************************************************
  464. * Function: StopMode_EnterStopMode
  465. * Object: 进入停止模式
  466. * 输入: uint32_t s,闹钟触发时间
  467. * 输出: 无
  468. * 备注: 设置待机时间并进入停止,闹钟事件发生自动退出stop模式
  469. * 进入stop模式,闹钟唤醒后跳出函数运行
  470. * RAM/GPIO状态保持
  471. * s为单位秒
  472. **********************************************************************************/
  473. void StopMode_EnterStopMode(uint32_t s)
  474. {
  475. //设置待机时间
  476. RTC_SetAlarm(RTC_GetCounter() + s);
  477. RTC_WaitForLastTask();
  478. /* LDO不关掉,闹钟事件唤醒*/
  479. PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFE);
  480. //唤醒后重新配置系统时钟
  481. StopMode_SYSCLKConfig_STOP();
  482. }