- 应用示例:此程序主要实现开机后经过10秒后进入 STOP 模式,然后每经过5秒 SLEEP 模式和 STOP 模式互相切换,如此循环往复,同时经过一个循环后,切换 MCU 的运行频率,验证运行的稳定性。并且打开了回调和中断唤醒,在进入睡眠和唤醒后会分别熄灭和点亮LED灯,在睡眠时间可以通过外部中断唤醒:
- /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-11-06 SummerGift first version
- */
- #include
- #include
- #include
- #include
- #define LOG_TAG 'PM.test'
- #define LOG_LVL LOG_LVL_DBG
- #include
- /* defined the LED0 pin: PB13 */
- #define LED0_PIN GET_PIN(C, 6)
- #define MCU_IRQ_WAKE_PIN GET_PIN(C, 9)
- static RTC_HandleTypeDef hrtc;
- static RTC_TimeTypeDef curtime = {0};
- static RTC_TimeTypeDef alarmtime = {0};
- static RTC_AlarmTypeDef alarm = {0};
- static struct rt_semaphore wake_sem;
- static rt_uint8_t sleep_mode = PM_SLEEP_MODE_DEEP; /* STOP 模式 */
- static rt_uint8_t run_mode = PM_RUN_MODE_NORMAL_SPEED;
- static rt_uint32_t get_interval(void);
- static void get_rtc_time(RTC_TimeTypeDef *time);
- static rt_uint8_t mode_loop(void);
- static rt_uint8_t issleep = 0;
- /* 中断回调函数 */
- static void MCU_IRQ_WAKE(void *args)
- {
- if(issleep)
- {
- rt_kprintf('MCU_IRQ_WAKE!\n');
- rt_sem_release(&wake_sem);
- issleep = 0;
- }
- }
- static void pm_botify(uint8_t event, uint8_t mode, void *data)
- {
- if(event == RT_PM_ENTER_SLEEP && mode == PM_SLEEP_MODE_DEEP)
- {
- rt_pin_write(LED0_PIN, PIN_HIGH);
- issleep = 1;
- }
- else if (event == RT_PM_EXIT_SLEEP && mode == PM_SLEEP_MODE_DEEP )
- {
- rt_pin_write(LED0_PIN, PIN_LOW);
- }
- }
- int pm_test(void)
- {
- hrtc.Instance = RTC;
- rt_sem_init(&wake_sem, 'wake_sem', 0, RT_IPC_FLAG_FIFO);
- rt_pm_notify_set(pm_botify,0);
- /* 按键0引脚为输入模式 */
- rt_pin_mode(MCU_IRQ_WAKE_PIN, PIN_MODE_INPUT_PULLDOWN);
- /* 绑定中断,上升沿模式,回调函数名为beep_on */
- rt_pin_attach_irq(MCU_IRQ_WAKE_PIN, PIN_IRQ_MODE_RISING, MCU_IRQ_WAKE, RT_NULL);
- /* 使能中断 */
- rt_pin_irq_enable(MCU_IRQ_WAKE_PIN, PIN_IRQ_ENABLE);
- rt_thread_mdelay(10000);
- #ifdef RT_USING_PM
- /* 申请低功耗模式 */
- rt_pm_request(sleep_mode);
- #endif
- get_rtc_time(&curtime);
- if (sleep_mode == PM_SLEEP_MODE_STANDBY)
- {
- /* 设置休眠,闹钟 20 秒后唤醒,简化版闹钟,只支持 1分钟内有效 */
- alarmtime.Hours = curtime.Hours;
- alarmtime.Minutes = curtime.Minutes;
- alarmtime.SubSeconds = curtime.SubSeconds;
- alarmtime.Seconds = curtime.Seconds + 20;
- if (alarmtime.Seconds >= 60)
- {
- alarmtime.Seconds -= 60;
- alarmtime.Minutes ++;
- if (alarmtime.Minutes >= 60)
- alarmtime.Minutes -= 60;
- }
- alarm.Alarm = RTC_ALARM_A;
- alarm.AlarmTime = alarmtime;
- alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
- alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
- alarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS;
- alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
- alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
- alarm.AlarmDateWeekDay = 0x1;
- /* 开启闹钟 */
- HAL_RTC_SetAlarm_IT(&hrtc, &alarm, RTC_FORMAT_BIN);
- }
- while (1)
- {
- /* 开始进入低功耗模式 */
- rt_sem_take(&wake_sem, rt_tick_from_millisecond(5000));
- /* 退出低功耗模式 */
- rt_kprintf('Sleep %d ms\n', get_interval());
- #ifdef RT_USING_PM
- /* 申请正常模式 */
- rt_pm_request(PM_SLEEP_MODE_NONE);
- #endif
- rt_thread_mdelay(5000);
- rt_kprintf('Wakeup %d ms\n', get_interval());
- /* 运行模式切换 */
- rt_pm_run_enter(mode_loop());
- #ifdef RT_USING_PM
- rt_pm_release(PM_SLEEP_MODE_NONE);
- #endif
- }
- return RT_EOK;
- }
- //MSH_CMD_EXPORT(pm_test, PM TEST);
- static rt_uint32_t get_interval(void)
- {
- rt_uint32_t seconds;
- rt_uint32_t last_seconds = curtime.Seconds;
- rt_uint32_t last_subseconds = curtime.SubSeconds;
- get_rtc_time(&curtime);
- if (curtime.Seconds < last_seconds)
- seconds = 60 + curtime.Seconds - last_seconds;
- else
- seconds = curtime.Seconds - last_seconds;
- return (rt_uint32_t)(seconds * 1000 + ((int32_t)last_subseconds - (int32_t)curtime.SubSeconds) * 1000 \
- / (int32_t)(((RTC->PRER & RTC_PRER_PREDIV_S) >> RTC_PRER_PREDIV_S_Pos) + 1U));
- }
- static void get_rtc_time(RTC_TimeTypeDef *time)
- {
- rt_uint32_t st, datetmpreg;
- HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
- datetmpreg = RTC->DR;
- if (HAL_RCC_GetPCLK1Freq() < 32000U * 7U)
- {
- st = time->SubSeconds;
- HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
- datetmpreg = RTC->DR;
- if (st != time->SubSeconds)
- {
- HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
- datetmpreg = RTC->DR;
- }
- }
- (void)datetmpreg;
- }
- rt_uint8_t mode_loop(void)
- {
- rt_uint8_t mode = 1;
- run_mode++;
- switch (run_mode)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- mode = run_mode;
- break;
- case 4:
- mode = 2;
- break;
- case 5:
- mode = 1;
- break;
- case 6:
- mode = run_mode = 0;
- break;
- }
- return mode;
- }
|