1. 程式人生 > >stm32f103 RTC週期性待機喚醒(一)

stm32f103 RTC週期性待機喚醒(一)

做一個低功耗的東西,搞了好幾天,程式一直卡在一個地方(見下圖),今天終於發現問題出在哪裡了,對待機喚醒的問題做一個總結(只針對我遇到的問題,其他部分網上都有,基於stm32f103)

1、解決我遇到的問題        我的RTC初始化部分有個“儲存在備份暫存器的RTC標誌是否已經被配置過的判斷”,如果已經配置過,則進入else部分,但是這個else部分沒有“要使能電源時鐘,使能備份時鐘,取消後備區的防寫”這些配置語句,而待機喚醒後程序從主函式執行,會執行到else部分,因為沒有那些配置語句,所以再次對鬧鐘賦值就會不成功,就會卡在那裡。(那些配置語句在clock_ini函式裡,有註釋)

2、待機用不用加extiline17事件 如果把鬧鐘中斷的服務程式放在void RTC_IRQHandler(void)裡面處理的話,不需要extiline17事件也可以喚醒(親測),如果鬧鐘中斷的服務程式放在void RTCAlarm_IRQHandler(void)裡面處理的話,需要extiline17事件

3、RTCAlarm_IRQn和RTC_IRQn優先順序 我見到網上說要把RTCAlarm_IRQn的優先順序設定比RTC_IRQn優先順序高,但是把鬧鐘中斷的服務程式放在void RTC_IRQHandler(void)裡面處理的話,不用這樣設定也可以。如果鬧鐘中斷的服務程式放在void RTCAlarm_IRQHandler(void)裡面處理的話需要設定優先順序,最好根據情況先把優先順序的問題解決清楚

4、下面是我的一些程式碼

  1. void Clock_ini(void)

  2. {

  3. if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) //判斷儲存在備份暫存器的RTC標誌是否已經被配置過

  4. {

  5. printf("\r\n\n RTC not yet configured....");

  6. RTC_Configuration(); <span style="white-space:pre"> </span>//RTC初始化

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

  8. Time_Adjust(); //設定RTC 時鐘引數

  9. BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); //RTC設定後,將已配置標誌寫入備份資料暫存器

  10. }

  11. else

  12. {

  13. if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) //檢查是否掉電重啟

  14. {

  15. printf("\r\n\n Power On Reset occurred....");

  16. }

  17. else if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) //檢查是否reset復位

  18. {

  19. printf("\r\n\n External Reset occurred....");

  20. }

  21. printf("\r\n No need to configure RTC....");

  22. /***新加的,測試,待機喚醒後,程式不經過上面的if部分,所以沒有這三步(兩個語句),所以程式會卡,所以加上,果然***/

  23. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  24. /* 允許訪問BKP區域 */

  25. PWR_BackupAccessCmd(ENABLE); </span>

  26. RTC_WaitForSynchro(); //等待RTC暫存器被同步

  27. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能秒中斷

  28. RTC_WaitForLastTask();

  29. RTC_ITConfig(RTC_IT_ALR, ENABLE); //naozhong

  30. RTC_WaitForLastTask(); <span style="white-space:pre"> </span>//等待寫入完成

  31. }

  32. RCC_ClearFlag(); //清除復位標誌

  1. void NVIC_Configuration(void)

  2. {

  3. NVIC_InitTypeDef NVIC_InitStructure;

  4. EXTI_InitTypeDef EXTI_InitStructure;

  5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  6. /* Enable the RTC Interrupt */

  7. NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //配置外部中斷源(秒中斷)

  8. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

  9. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;

  10. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  11. NVIC_Init(&NVIC_InitStructure);

  12. /* Enable the RTC Alarm Interrupt */

  13. NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; //配置外部中斷源(鬧鐘中斷)

  14. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  15. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

  16. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  17. NVIC_Init(&NVIC_InitStructure);

  18. //鬧鐘中斷接到第17線外部中斷

  19. EXTI_ClearITPendingBit(EXTI_Line17);

  20. EXTI_InitStructure.EXTI_Line = EXTI_Line17;

  21. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

  22. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

  23. EXTI_InitStructure.EXTI_LineCmd = ENABLE;

  24. EXTI_Init(&EXTI_InitStructure);

  25. }

  1. void RTC_Configuration(void)

  2. {

  3. /* 使能 PWR 和 BKP 的時鐘 */

  4. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  5. /* 允許訪問BKP區域 */

  6. PWR_BackupAccessCmd(ENABLE);

  7. /* 復位BKP */

  8. BKP_DeInit();

  9. #ifdef RTCClockSource_LSI

  10. /* 使能內部RTC時鐘 */

  11. RCC_LSICmd(ENABLE);

  12. /* 等待RTC內部時鐘就緒 */

  13. while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)

  14. {

  15. }

  16. /* 選擇RTC內部時鐘為RTC時鐘 */

  17. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  18. #elif defined RTCClockSource_LSE

  19. /* 使能RTC外部時鐘 */

  20. RCC_LSEConfig(RCC_LSE_ON);

  21. /* 等待RTC外部時鐘就緒 */

  22. while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)

  23. {

  24. }

  25. /* 選擇RTC外部時鐘為RTC時鐘 */

  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  27. #endif

  28. /* 使能RTC時鐘 */

  29. RCC_RTCCLKCmd(ENABLE);

  30. #ifdef RTCClockOutput_Enable

  31. /* Disable the Tamper Pin */

  32. BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper

  33. functionality must be disabled */

  34. /* 使能在TAMPER腳輸出RTC時鐘 */

  35. BKP_RTCCalibrationClockOutputCmd(ENABLE);

  36. #endif

  37. /* 等待RTC暫存器同步 */

  38. RTC_WaitForSynchro();

  39. /* 等待寫RTC暫存器完成 */

  40. RTC_WaitForLastTask();

  41. /* 使能RTC naozhong中斷 */

  42. RTC_ITConfig(RTC_IT_ALR, ENABLE);

  43. /* 等待寫RTC暫存器完成 */

  44. RTC_WaitForLastTask();

  45. /* 使能RTC秒中斷 */

  46. RTC_ITConfig(RTC_IT_SEC, ENABLE);

  47. /* 等待寫RTC暫存器完成 */

  48. RTC_WaitForLastTask();

  49. /* 設定RTC預分頻 */

  50. #ifdef RTCClockSource_LSI

  51. RTC_SetPrescaler(31999); /* RTC period = RTCCLK/RTC_PR = (32.000 KHz)/(31999+1) */

  52. #elif defined RTCClockSource_LSE

  53. RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

  54. #endif

  55. /* 等待寫RTC暫存器完成 */

  56. RTC_WaitForLastTask();

  57. }

  1. void RTCAlarm_IRQHandler(void)

  2. {

  3. RTC_WaitForSynchro();

  4. if(RTC_GetITStatus(RTC_IT_ALR) != RESET)

  5. {

  6. //printf("mmmmmm");

  7. EXTI_ClearITPendingBit(EXTI_Line17);

  8. RTC_WaitForLastTask();

  9. if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)

  10. {

  11. // 清除喚醒標誌

  12. PWR_ClearFlag(PWR_FLAG_WU);

  13. RTC_WaitForLastTask();

  14. }

  15. RTC_ClearITPendingBit(RTC_IT_ALR);

  16. RTC_WaitForLastTask();

  17. printf("\nIt will wake up after %d s\n",standbytime);

  18. RTC_Enter_StandbyMode(standbytime);//standbytime秒後喚醒

  19. }

  20. }

  1. void RTC_Enter_StandbyMode(u32 s)

  2. {

  3. RTC_WaitForLastTask();

  4. RTC_SetAlarm(RTC_GetCounter()+s);

  5. RTC_WaitForLastTask();

  6. // 進入待機模式, 此時所有1.8V域的時鐘都關閉,HIS和HSE的振盪器關閉, 電壓調節器關閉.

  7. // 只有WKUP引腳上升沿,RTC警告事件,NRST引腳的外部復位,IWDG復位.

  8. /* Request to enter STANDBY mode (Wake Up flag is cleared in PWR_EnterSTANDBYMode function) */

  9. PWR_EnterSTANDBYMode();

  10. }

5、接下來幾天我要研究一下停機模式和功耗問題