硬汉嵌入式论坛

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

[技术讨论] stm32f411使用待机模式+RTC闹钟事件,闹钟每秒都会重设

[复制链接]

1

主题

5

回帖

8

积分

新手上路

积分
8
发表于 2024-7-3 22:10:21 | 显示全部楼层 |阅读模式
main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "MyRTC.h"
#include "LED.h"


uint8_t TIME[6];
uint8_t Alarm;
uint8_t Status;
int main(void)
{
        LED_Init();
        MyRTC_Init();//初始化RTC时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR
        MyRTC_SetAlarm();//设置闹钟
        while(1)
        {
                MyRTC_GetCurrentTimeAndDate(TIME);// 读取并显示当前时间和日期
                Alarm = MyRTC_GetAlarm();//获取闹钟的时间
                Status = RTC_GetFlagStatus(RTC_FLAG_ALRAF);//查看闹钟标志位
                PWR_EnterSTANDBYMode();//待机模式
        }
}


MyRTC.c

#include "stm32f4xx.h"                  // Device header
#include "MyRTC.h"
#include "LED.h"


void MyRTC_Init(void)
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR
        PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
       
        RCC_LSEConfig(RCC_LSE_ON);//开启外部低速时钟
        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);//等待外部低速时钟准备完成
       
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择RTC的时钟源
        RCC_RTCCLKCmd(ENABLE);
       
        RTC_WaitForSynchro();
       


        if(RTC_ReadBackupRegister(RTC_BKP_DR1) != 0xA1A1)//通过读取BKP寄存器可防止重复的初始化
        {                                                                                                //,在主电源和备用电源都断电后重新上电,就会重新初始化RTC
                RTC_InitTypeDef RTC_InitStructure;
                RTC_InitStructure.RTC_AsynchPrediv = 127; // 异步预分频器值,设置 RTC_PRER 寄存器的 PREDIV_A 相关位
                RTC_InitStructure.RTC_SynchPrediv = 255;  // 同步预分频器值,设置 RTC_PRER 寄存器的 PREDIV_S 相关位
                //为了得到1 Hz的RTC时钟,通常设置异步预分频器为127,同步预分频器为255。
                RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;//设置 RTC 的时间格式,
                RTC_Init(&RTC_InitStructure);
                //RTC_Init不需要调用RTC_EnterInitMode。底层会调用。但是设置具体的时间和日期时,仍需手动调用初始化模式。
                MyRTC_SetTime(12, 34, 56);// 设置时间为12:34:56
                MyRTC_SetDate(24, 6, 30, 7);// 设置日期为2024-06-30(星期日)
                RTC_WriteBackupRegister(RTC_BKP_DR1,0xA1A1);
        }
}


void MyRTC_SetTime(uint8_t hour, uint8_t minute, uint8_t second)
{
        RTC_TimeTypeDef RTC_TimeStructure;
        RTC_TimeStructure.RTC_H12 = RTC_H12_AM;
        RTC_TimeStructure.RTC_Hours = hour;
        RTC_TimeStructure.RTC_Minutes = minute;
        RTC_TimeStructure.RTC_Seconds = second;
    RTC_EnterInitMode();// 进入初始化模式
        RTC_SetTime(RTC_Format_BIN,&RTC_TimeStructure);
        RTC_ExitInitMode();// 退出初始化模式
}


void MyRTC_SetDate(uint8_t year, uint8_t month, uint8_t day, uint8_t weekday)
{
        RTC_DateTypeDef RTC_DateStructure;
        RTC_DateStructure.RTC_Date = day;
        RTC_DateStructure.RTC_Month = month;
        RTC_DateStructure.RTC_WeekDay = weekday;
        RTC_DateStructure.RTC_Year = year;
    RTC_EnterInitMode();
        RTC_SetDate(RTC_Format_BIN,&RTC_DateStructure);
        RTC_ExitInitMode();
}


void MyRTC_GetCurrentTimeAndDate(uint8_t *TIME)
{
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_DateTypeDef RTC_DateStructure;


    RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure); // 读取当前时间
    RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);// 读取当前日期
       
        TIME[0] = RTC_DateStructure.RTC_Year;
        TIME[1] = RTC_DateStructure.RTC_Month;
        TIME[2] = RTC_DateStructure.RTC_Date;
        TIME[3] = RTC_TimeStructure.RTC_Hours;
        TIME[4] = RTC_TimeStructure.RTC_Minutes;
        TIME[5] = RTC_TimeStructure.RTC_Seconds;
}


void MyRTC_SetAlarm(void)
{       
        RTC_TimeTypeDef RTC_TimeStructure;
        RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
       
        RTC_AlarmCmd(RTC_Alarm_A,DISABLE);
        RTC_AlarmTypeDef RTC_AlarmStructure;
        RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
        RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = 0;
        RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = 0;
        RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = (RTC_TimeStructure.RTC_Seconds+10)%60;
        RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31; // 任意日期
    RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
        RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours | RTC_AlarmMask_Minutes;//使用掩码忽略日期、小时和分钟部分,只关注秒部分。
        RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmStructure);
        RTC_AlarmCmd(RTC_Alarm_A,ENABLE);
       
        //RTC_ClearFlag(RTC_FLAG_ALRAF);// 清除闹钟标志
        RTC_ITConfig(RTC_IT_ALRA, ENABLE);// 使能闹钟中断


        EXTI_InitTypeDef EXTI_InitStructure;
        EXTI_InitStructure.EXTI_Line = EXTI_Line17;                     // Line 17 connected to RTC Alarm
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;          // Trigger on rising edge
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);


        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;    // Set a low priority
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}


uint8_t MyRTC_GetAlarm(void)
{       
        RTC_AlarmTypeDef RTC_AlarmStructure;
        RTC_GetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmStructure);
        return RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds;
}


void RTC_Alarm_IRQHandler(void)
{
        if (RTC_GetITStatus(RTC_IT_ALRA) != RESET)
        {
        RTC_ClearITPendingBit(RTC_IT_ALRA);
        EXTI_ClearITPendingBit(EXTI_Line17); // 清除EXTI线路17(连接到RTC闹钟)的中断挂起位
        LED1_Turn();
        }
}

回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2024-7-3 22:13:26 | 显示全部楼层
想要设一个10秒后的闹钟来唤醒设备,比如时间是10秒的时候就设一个20秒的闹钟,然后闹钟响了以后会重设一次30秒的闹钟,等待十秒后再次响起。结果在Keil调试器中看见闹钟的数值跟着我时钟的秒数一起,每秒都在重设,比如10秒的时候,闹钟就是20,但是时钟来到11秒的时候,闹钟就被设置成了21.
回复

使用道具 举报

3

主题

15

回帖

24

积分

新手上路

积分
24
发表于 2024-7-4 09:16:26 | 显示全部楼层
听起来像是在秒中断里重设了闹钟?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 2024-7-4 09:36:37 | 显示全部楼层
1、注意你的RTC初始化,星期值一定要是存在的,且 和设置的日期是对应的。
2、不使用调试状态,正常下载运行,是否正常。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 2024-7-4 09:36:51 | 显示全部楼层
1、注意你的RTC初始化,星期值一定要是存在的,且 和设置的日期是对应的。
2、不使用调试状态,正常下载运行,是否正常。
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2024-7-4 12:10:27 | 显示全部楼层
eric2013 发表于 2024-7-4 09:36
1、注意你的RTC初始化,星期值一定要是存在的,且 和设置的日期是对应的。
2、不使用调试状态,正常下载运 ...

1.星期值要存在指的是闹钟要设星期值吗?RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31; // 任意日期
我在这随便设了一个,但是在掩码部分我只保留了对秒数的计算
2.应该也是不正常的,因为我在中断里使用了翻转LED电平,但是不调试直接运行的话,LED还是只翻转了一次
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2024-7-4 18:14:04 | 显示全部楼层
还是没找到问题,救救

待机模式 实时时钟.zip

607.07 KB, 下载次数: 2

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 2024-7-5 09:16:12 | 显示全部楼层
knowlz 发表于 2024-7-4 12:10
1.星期值要存在指的是闹钟要设星期值吗?RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31; // 任意日期
...

是这个RTC_DateStructure.RTC_WeekDay = weekday;
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2024-7-5 10:30:32 | 显示全部楼层
eric2013 发表于 2024-7-5 09:16
是这个RTC_DateStructure.RTC_WeekDay = weekday;

这个我设置了
void MyRTC_SetDate(uint8_t year, uint8_t month, uint8_t day, uint8_t weekday);
MyRTC_SetDate(24, 6, 30, 7);// 设置日期为2024-06-30(星期日)
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2024-7-5 10:38:58 | 显示全部楼层
翻阅手册后发现F4配置RTC闹钟有以下几个要注意的点,在图片中有说明。
还有一点就是在进入待机模式之前要自己手动清除WUF标志位,我在我的程序中使用的是PWR->CR |= ~PWR_CR_CWUF;
现在闹钟不会每秒都更新了,但是出现了新问题,好像是进入待机模式后无法被唤醒,在调试器中看到闹钟只被更新了一次,
LED电平也是只翻转了一次,然后就不更新也不翻转了。即使不使用调试器看,LED也是只会翻转一次
Snipaste_2024-07-05_10-33-07.png
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2024-9-11 16:26:42 | 显示全部楼层
兄弟我现在也碰到这个问题了,想问下你解决了吗
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-10 04:24 , Processed in 0.287779 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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