STM32CubeMX(stm32F030C8T6) 之RTC闹钟唤醒停机模式-STM32开发实战 (2)

一、概述
本例程是用STOP休眠模式,用RTC的周期性自动唤醒功能来唤醒芯片。
根据手册的说明:这里有个可编程的可自动重装的向下计数器,按照相应的时钟频率赋予适当的值,每当向下计数到0时便产生一个唤醒标志,如果此时使能了相应的定时唤醒中断,它就可以把MCU从低功耗模式唤醒。需做如下四项基本的准备工作。
1、确定RTC时钟,即RTCCLK.可以是LSE、LSI、HSE/32其中一个。下面的例程中选用LSI.
2、为自动唤醒定时计数器选择合适的时钟源。
这里写图片描述
3、RTC时钟进来分频之后达到1秒(1Hz),每一次时间更新RTC时钟寄存器(RTC_TR、RTC_DR),我们读取的数字就会更改。如果配置了中断,相应事件的时候,中断也会响应。如果配置了闹钟,同样达到了闹钟设定的值也会响应闹钟。
默认设置
AsynchPrediv = 127;
SynchPrediv = 255;

4、做好RTC周期性定时唤醒的中断配置,即NVIC配置。RTC唤醒事件是连接到EXTI 17/19/20号线。

二、详细步骤

2-1 stm32MxCube 操作
这里写图片描述

这里写图片描述

这里写图片描述

注意配置NVIC(中断控制器),RTC中断的条件选择。
生成工程文件,即可。

2-2 代码解析 (以下部分同时为直接的代码移植做参考,因为stm32cubeMx前期代码生成后,再重新生成会很麻烦,只能直接通过代码操作了)重点内容
2-2-1 相关文件j及配置条件
stm32f0xx_hal_conf.h
#define HAL_RTC_MODULE_ENABLED //打开宏定义
驱动文件:低功耗相关 stm32f0xx_hal_pwr.c
RTC相关 stm32f0xx_hal_rtc.c stm32f0xx_hal_rtc_ex.c
MCU初始化 stm32f0xx_hal_msp.c
2-2-2 详细说明
如何进入睡眠模式

通过执行 WFI(等待中断)或WFE(等待事件)指令进入睡眠状态。

代码实现:
* @param Regulator: Specifies the regulator state in STOP mode. // 调压器模式选择,功耗会存在差异
* This parameter can be one of the following values:
* @arg PWR_MAINREGULATOR_ON: STOP mode with regulator ON
* @arg PWR_LOWPOWERREGULATOR_ON: STOP mode with low power regulator ON
* @param STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction. // 进入睡眠状态进入机制,同时也表明了唤醒的选择方式
* This parameter can be one of the following values:
* @arg PWR_STOPENTRY_WFI:Enter STOP mode with WFI instruction
* @arg PWR_STOPENTRY_WFE: Enter STOP mode with WFE instruction

HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI ); 

其他各种不同的模式可以自己研究。

如何退出睡眠模式

由于我们是采用指令WFI进入睡眠模式,那么任意一个被嵌套向量中断控制器NVIC响应的外设中断都能将系统从睡眠模式唤醒。并且该模式唤醒所需的时间最短,因为没有时间损失在中断的进入或退出上。
在RTX系统上,主要是周期性执行的系统滴答定时器中断会将系统从睡眠态唤醒,我们这里用的闹钟 Alarm A 来唤醒。

   2-2-3 时钟初始化
   void SystemClock_Config(void)
   {
      ....// 省略
             PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_RTC;
             PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;*//cube时钟配置部分默认的时钟选择*

      ....// 省略
   }

   RTC初始化           static void MX_RTC_Init(void);
   中断向量初始化    static void MX_NVIC_Init(void);

     static void MX_RTC_Init(void)

{

RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;

/**Initialize RTC Only
*/

hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}

/**Initialize RTC and set the Time and Date
*/

sTime.Hours = 10;
sTime.Minutes = 12;
sTime.Seconds = 34;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}

sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
sDate.Month = RTC_MONTH_MAY;
sDate.Date = 19;
sDate.Year = 17;

if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}

/**Enable the Alarm A        //允许RTC报警中断
*/

sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 0;
sAlarm.AlarmTime.Seconds = 10;
sAlarm.AlarmTime.SubSeconds = 0;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS |RTC_ALARMMASK_MINUTES;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}

}
static void MX_NVIC_Init(void)
{

/* RTC_IRQn interrupt configuration */
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_IRQn);
}

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)  // 可以重新定义 闹钟中断回调函数,添加自己的代码辅助调试
{
        /* NOTE : This function Should not be modified, when the callback is needed,
        the HAL_RTC_AlarmAEventCallback could be implemented in the user file
        */
        DBS("EventCallback");
}
 读取时钟: 
                HAL_RTC_GetTime(&hrtc, &thisTime, RTC_FORMAT_BIN);
                HAL_RTC_GetDate(&hrtc, &thisData, RTC_FORMAT_BIN);
                DBSTRLONG("_",thisData.Year);
                DBSTRLONG("_",thisData.Month);
                DBSTRLONG("_",thisData.WeekDay);       
                DBSTRLONG("_",thisTime.Hours);
                DBSTRLONG("_",thisTime.Minutes);
                DBSTRLONG("_",thisTime.Seconds);   

                RTC_AlarmTypeDef sAlarm;
                HAL_RTC_GetAlarm(&hrtc,&sAlarm,RTC_ALARM_A,RTC_FORMAT_BIN);  // 获取闹钟定时

三、问题总结 【本次实验碰到的问题】

3-1
STM32F030用LSI作时钟源走时不准,40Khz配置,总会跳秒,要想准时,还是用外部LSE时钟,32768hz,会比较准。
3-2 sAlarm.AlarmMask =RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS |RTC_ALARMMASK_MINUTES ;

//注意屏蔽的对象,设置的日期,星期,时分是无效的,这时RTC闹钟 的秒匹配后触发闹钟中断。如果设置RTC_AlarmMask=RTC_AlarmMask_None;则为精确匹配,即闹钟不仅要求时分秒匹配还要匹配日期和星期,都匹配后触发闹钟中断)

        起初因为没有注意到这一点,我设置10s 闹钟中断,当时只做了RTC_ALARMMASK_DATEWEEKDAY屏蔽 ,以至于耗费了好几天而不得结果。

3-3 测试低功耗时,最好通过任务,或者条件控制进入低功耗,否则,开机几秒就进入,那么下来,再烧写程序就麻烦了。

  • 4
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: STM32F103C8T6是一款集成了ARM Cortex-M3内核的32位微控制器,具有丰富的外设和强大的计算能力。而万年历则是一种功能强大且常见的电子设备,能够用于显示日期、时间、日历等信息。在STM32F103C8T6万年历的设计中,我们可以利用该微控制器的RTC模块来实现日期和时间的精准计时,同时可以通过OLED显示屏等设备实现信息的显示和操作。此外,万年历还可以加入相关的功能模块,如闹钟定时器、温度传感器等,以增强其实用性。总之,STM32F103C8T6可以为万年历的设计提供一个高性能、低功耗的解决方案,为用户提供简单、便捷、高效的日期、时间、日历等信息查询和操作体验。 ### 回答2: STM32F103C8T6是一款基于ARM® Cortex®-M3内核的高性能51系列微控制器。它内置了多个模块,包括但不限于定时器、串口、I2C总线、SPI总线、CAN总线等,具有可编程性强、速度快、功耗低等优点。这款万年历项目利用了STM32F103C8T6的高度集成和灵活性,设计了一款功能丰富、易于使用的万年历。 该万年历具有显示时间、日期、星期、月份、年份、节气等功能。可以显示公历、农历等不同类型的时间,并根据闰年、大小月等不同情况实现高精度的计算。此外,还可以设置闹钟、倒计时、显示倒计时天数等功能。具有强大的防抖功能,可以防止因机械震动或外部干扰造成的误操作。并且可以进行桌面置顶、声音提示、背景颜色调节等个性化设置,提高用户交互性和易用性。 该项目采用了模块化的设计思想,将硬件和软件分为不同的模块,实现了功能模块独立,易于维护和扩展的优点。运用了面向对象的编程技术,大大提高了程序的可读性和可维护性。此外,还采用了多任务操作系统和多线程技术,可同时处理多个任务,提高了程序的效率。 总之,STM32F103C8T6万年历项目具有多种功能,易于使用和维护,是一款高性能、高灵活性的实用项目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值