实时时钟和待机唤醒实验的综合实验有问题,请大家为我解释解释。

2019-08-22 13:25发布

#include "sys.h"
#include "rtc.h"
#include "delay.h"
#include "usart.h"

void Sys_Standby()
{
    NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP,ENABLE);      
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);    //使能PWR和BKP外设时钟   
    PWR_WakeUpPinCmd(ENABLE);  //使能唤醒管脚功能
    PWR_EnterSTANDBYMode();      //进入待命(STANDBY)模式          
}
void Sys_Enter_Standby(void)
{             
    RCC_APB2PeriphResetCmd(0X01FC,DISABLE);
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);        //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
    RCC_RTCCLKCmd(ENABLE);    //开启RTC时钟使能          
    Sys_Standby();
}


u8 Check_wkup()
{
    if(timer.hour==13&&timer.min<33&&timer.min>30)//在13点33~30分之间时Check_wkup置1,其他时间为0
        return 1;
    else
        return 0;
}

//闹钟结构体   
//闹钟结构体   
__packed typedef struct 
{      
    u8  hour;     //闹铃小时
    u8  min; //闹铃分钟
    }_alarm_obj;
//重新初始化闹钟                        
//alarmx:闹钟结构体
void calendar_alarm_init(_alarm_obj *alarmx)
{  
   u32 curtime=0;
   u32 temptime=0;
   u32 destime=0XFFFFFFFF;//目标闹铃时间(s)设定到最大

    curtime=RTC->CNTH;//得到计数器中的值(秒钟数)
    curtime<<=16;
    curtime+=RTC->CNTL;   
    //取一个与当前时间最接近的值作为闹钟寄存器的内容
    temptime=curtime/86400; //得到当前运行天数(此处没有用到天数,仅作说明用)
    temptime=temptime*86400;
    temptime+=(u32)alarmx->hour*3600+(u32)alarmx->min*60;//得到秒钟数
    if(temptime<=curtime)temptime+=86400;//执行时间已过,推迟到明天
    destime=temptime;//更改闹钟寄存器

    RCC->APB1ENR|=1<<28;//使能电源时钟
    RCC->APB1ENR|=1<<27;//使能备份时钟
    PWR->CR|=1<<8;    //取消备份区写保护
    RTC->CRL|=1<<4;   //允许配置
    RTC->ALRL=destime&0xffff;
    RTC->ALRH=destime>>16;
    RTC->CRL&=~(1<<4);//配置更新
    while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 
}


tm timer;//时钟结构体       
//实时时钟配置
//初始化RTC时钟,同时检测时钟是否工作正常
//BKP->DR1用于保存是否第一次配置的设置
//返回0:正常
//其他:错误代码
void RTC_NVIC_Config(void)
{   
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;        //RTC全局中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    //先占优先级1位,从优先级3位
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    //先占优先级0位,从优先级4位
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //使能该通道中断
    NVIC_Init(&NVIC_InitStructure);        //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}

u8 RTC_Init(void)
    {
    //检查是不是第一次配置时钟
    u8 temp=0;
    _alarm_obj _alarm_;
    RTC_NVIC_Config();
    //if(BKP->DR1!=0X5050)//第一次配置
    if (BKP_ReadBackupRegister(BKP_DR1) == 0x5050)        //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
        {                
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟  
        PWR_BackupAccessCmd(ENABLE);    //使能RTC和后备寄存器访问
        BKP_DeInit();    //将外设BKP的全部寄存器重设为缺省值    
        RCC_LSEConfig(RCC_LSE_ON);    //设置外部低速晶振(LSE),使用外设低速晶振
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)    //检查指定的RCC标志位设置与否,等待低速晶振就绪
            {
            temp++;
            delay_ms(10);
            }
        if(temp>=250)return 1;//初始化时钟失败,晶振有问题       
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);        //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
        RCC_RTCCLKCmd(ENABLE);    //使能RTC时钟 
        RTC_WaitForSynchro();        //等待最近一次对RTC寄存器的写操作完成
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ITConfig(RTC_IT_ALR,ENABLE);    //使能闹钟中断
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_EnterConfigMode();//进入RTC的配置模式
        RTC_WaitForLastTask();
        _alarm_.hour=13;
        _alarm_.min=30;
        calendar_alarm_init(&_alarm_);//设置休眠时间时13:30
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ExitConfigMode();//退出RTC的配置模式
        RTC_SetPrescaler(32767); //设置RTC预分频的值
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_Set(2014,1,8,13,29,30);  //设置时间     
        BKP_WriteBackupRegister(BKP_DR1, 0X5050);    //向指定的后备寄存器中写入用户程序数据
        }
    else//系统继续计时
        {

        RTC_WaitForSynchro();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ITConfig(RTC_IT_SEC, ENABLE);    //使能RTC秒中断
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ITConfig(RTC_IT_ALR,ENABLE);    //使能闹钟中断
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_EnterConfigMode();//进入RTC的配置模式
        RTC_WaitForLastTask();
        _alarm_.hour=13;
        _alarm_.min=30;
        calendar_alarm_init(&_alarm_);
        RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
        RTC_ExitConfigMode();//退出RTC的配置模式

        }                                
    RTC_Get();//更新时间   
    RCC_ClearFlag();    //清除RCC的复位标志位
   
    return 0; //ok
    }


//RTC中断服务函数
void RTC_IRQHandler(void)
{                               
    if(RTC->CRL&0x0001)//秒钟中断
        {                           
        RTC_Get();//更新时间      
        }
    if(RTC->CRL&0x0002)//闹钟中断
        {
        RTC->CRL&=~(0x0002);//清闹钟中断
        Sys_Enter_Standby();//闹钟处理,进入待机模式
        }                                                    
    RTC->CRL&=0X0FFA;         //清除溢出,秒钟中断标志
    while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成                                                    
}
 

//判断是否是闰年函数
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
    {             
    if(year%4==0) //必须能被4整除
        {
        if(year%100==0)
            {
            if(year%400==0)return 1;//如果以00结尾,还要能被400整除       
            else return 0;  
            }else return 1;  
        }else return 0;   
    }   
               
//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//返回值:0,成功;其他:错误代码.
//月份数据表                                             
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表     
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};


u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    {
    u16 t;
    u32 seccount=0;
    if(syear<1970||syear>2099)return 1;      
    for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
        {
        if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
        else seccount+=31536000;              //平年的秒钟数
        }
    smon-=1;
    for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
        {
        seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
        if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数      
        }
    seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;     //分钟秒钟数
    seccount+=sec;//最后的秒钟加上去

    RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成

    RTC_SetCounter(seccount);    //设置RTC计数器的值

    RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成     
    return 0;       
    }

//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{
    static u16 daycnt=0;
    u32 timecount=0;
    u32 temp=0;
    u16 temp1=0;     
      
    timecount=RTC->CNTH;//得到计数器中的值(秒钟数)
    timecount<<=16;
    timecount+=RTC->CNTL;             

    temp=timecount/86400;   //得到天数(秒钟数对应的)
    if(daycnt!=temp)//超过一天了
    {     
        daycnt=temp;
        temp1=1970;    //从1970年开始
        while(temp>=365)
        {                 
            if(Is_Leap_Year(temp1))//是闰年
            {
                if(temp>=366)temp-=366;//闰年的秒钟数
                else {temp1++;break;} 
            }
            else temp-=365;      //平年
            temp1++; 
        }  
        timer.w_year=temp1;//得到年份
        temp1=0;
        while(temp>=28)//超过了一个月
        {
            if(Is_Leap_Year(timer.w_year)&&temp1==1)//当年是不是闰年/2月份
            {
                if(temp>=29)temp-=29;//闰年的秒钟数
                else break;
            }
            else
            {
                if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
                else break;
            }
            temp1++; 
        }
        timer.w_month=temp1+1;//得到月份
        timer.w_date=temp+1;  //得到日期
    }
    temp=timecount%86400;     //得到秒钟数         
    timer.hour=temp/3600;     //小时
    timer.min=(temp%3600)/60; //分钟   
    timer.sec=(temp%3600)%60; //秒钟
    timer.week=RTC_Get_Week(timer.w_year,timer.w_month,timer.w_date);//获取星期  
    return 0;
}     
//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数:公历年月日
//返回值:星期号                                                                                         
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
    {   
    u16 temp2;
    u8 yearH,yearL;
   
    yearH=year/100;    yearL=year%100;
    // 如果为21世纪,年份数加100 
    if (yearH>19)yearL+=100;
    // 所过闰年数只算1900年之后的 
    temp2=yearL+yearL/4;
    temp2=temp2%7;
    temp2=temp2+day+table_week[month-1];
    if (yearL%4==0&&month<3)temp2--;
    return(temp2%7);
    }
//比较两个字符串指定长度的内容是否相等
//参数:s1,s2要比较的两个字符串;len,比较长度
//返回值:1,相等;0,不相等

u8 str_cmpx(u8*s1,u8*s2,u8 len)
{
    u8 i;
    for(i=0;i<len;i++)if((*s1++)!=*s2++)return 0;
    return 1;      
}
extern const u8 *COMPILED_DATE;//获得编译日期
extern const u8 *COMPILED_TIME;//获得编译时间
const u8 Month_Tab[12][3]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
//自动设置时间为编译器时间  
void Auto_Time_Set(void)
{
    u8 temp[3];
    u8 i;
    u8 mon,date;
    u16 year;
    u8 sec,min,hour;
    for(i=0;i<3;i++)temp=COMPILED_DATE;  
    for(i=0;i<12;i++)if(str_cmpx((u8*)Month_Tab,temp,3))break;   
    mon=i+1;//得到月份
    if(COMPILED_DATE[4]==' ')date=COMPILED_DATE[5]-'0';
    else date=10*(COMPILED_DATE[4]-'0')+COMPILED_DATE[5]-'0'; 
    year=1000*(COMPILED_DATE[7]-'0')+100*(COMPILED_DATE[8]-'0')+10*(COMPILED_DATE[9]-'0')+COMPILED_DATE[10]-'0';      
    hour=10*(COMPILED_TIME[0]-'0')+COMPILED_TIME[1]-'0'; 
    min=10*(COMPILED_TIME[3]-'0')+COMPILED_TIME[4]-'0'; 
    sec=10*(COMPILED_TIME[6]-'0')+COMPILED_TIME[7]-'0'; 
    RTC_Set(year,mon,date,hour,min,sec)    ;
}
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、



#include "wkup.h"
#include "led.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////     
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//待机唤醒 驱动代码              
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/6/7
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved                      
//////////////////////////////////////////////////////////////////////////////////     
 
#include "wkup.h"
#include "led.h"
#include "delay.h"

extern u8 Check_wkup(void);
extern void Sys_Standby(void) ;
void WKUP_Init(void)
{
    RCC->BDCR|=1<<8;//LSI作为RTC的时钟
    RCC->BDCR|=1<<15;//RTC时钟使能
    RCC->APB2ENR|=1<<0;//开启辅助时钟
    if(Check_wkup()==0)
        Sys_Standby();
}

///////////////////////////////////////////////////////////////////////////////////
主程序

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "key.h"
#include "usart.h"
#include "exti.h"
#include "wdg.h"
#include "timer.h"
#include "pwm.h"
#include "lcd.h"
#include "rtc.h"

const u8 *COMPILED_DATE=__DATE__;
const u8 *COMPILED_TIME=__TIME__;
const u8* Week[7]={"Sunday","Monday","Tuesday","Wednesday ","Thursday ","Friday","Saturday"};

int main()
{
    u8 t=0;;
    SystemInit();
    delay_init(72);
    LED_Init();
    uart_init(9600);
    NVIC_Configuration();
    LCD_Init();
    RTC_Init();
    WKUP_Init();
    LCD_Clear(WHITE);
    POINT_COLOR=RED;
    LCD_ShowString(30,30,"RTC TEST");
    LCD_ShowString(30,50," 2010 / 12 / 30 ");
    POINT_COLOR=BLUE;

    while(1)
    {
       
       
        if(t!=timer.sec)
        {
            t=timer.sec;
            LCD_ShowNum(30,70,timer.w_year,4,16);
            LCD_ShowNum(70,70,timer.w_month,2,16);
            LCD_ShowNum(90,70,timer.w_date,2,16);//这些数据都存在寄存器否??
            switch(timer.week)
            {
                case 0CD_ShowString(30,90,"Sunday");break;
                case 1CD_ShowString(30,90,"Monday");break;
                case 2CD_ShowString(30,90,"Tuesday");break;
                case 3CD_ShowString(30,90,"Wednesday ");break;
                case 4CD_ShowString(30,90,"Thursday");break;
                case 5CD_ShowString(30,90,"Friday");break;
                case 6CD_ShowString(30,90,"Saturday");break;
            }
           
            LCD_ShowNum(30,110,timer.hour,2,16);
            LCD_ShowNum(50,110,timer.min,2,16);
            LCD_ShowNum(80,110,timer.sec,2,16);//这些数据都存在寄存器否??
            LED0=!LED0;   
        }     
    }
}

麻烦大家给我看看,为什么不能再13:30~13:33这个时间段唤醒,而其他时间段待机呢???哪里有问题??我感觉是在WKUP_Init(),Sys_Standby(),Sys_Enter_Standby(),这三个函数有点问题,愣是没找到。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
5条回答
xhh12001501
2019-08-23 01:55
回复【4楼】bjtmh:
---------------------------------
ok了  不过还是有一点问题,LCD需要硬复位。


主要就是这个:void calendar_alarm_init(u8 hour,u8 min) 
{   
   u32 curtime=0;
   u32 temptime=0;
   u32 destime=0XFFFFFFFF;//目标闹铃时间(s)设定到最大

curtime=RTC->CNTH;//得到计数器中的值(秒钟数)
curtime<<=16;
curtime+=RTC->CNTL;    
//取一个与当前时间最接近的值作为闹钟寄存器的内容
temptime=curtime/86400; //得到当前运行天数(此处没有用到天数,仅作说明用)
temptime=temptime*86400;
temptime+=(u32)hour*3600+(u32)min*60;//得到秒钟数
if(temptime<=curtime)temptime+=86400;//执行时间已过,推迟到明天
destime=temptime;//更改闹钟寄存器

RCC->APB1ENR|=1<<28;//使能电源时钟
RCC->APB1ENR|=1<<27;//使能备份时钟
PWR->CR|=1<<8;    //取消备份区写保护
RTC->CRL|=1<<4;   //允许配置 
RTC->ALRL=destime&0xffff;
RTC->ALRH=destime>>16;
RTC->CRL&=~(1<<4);//配置更新
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成  
}



u8 RTC_Init(void)
{
//检查是不是第一次配置时钟
u8 temp=0;
RTC_NVIC_Config();
//if(BKP->DR1!=0X5050)//第一次配置
if (BKP_ReadBackupRegister(BKP_DR1)!= 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
{  
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟   
PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 
BKP_DeInit(); //将外设BKP的全部寄存器重设为缺省值 
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪
{
temp++;
delay_ms(10);
}
if(temp>=250)return 1;//初始化时钟失败,晶振有问题     
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
  
RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断

RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_ALR,ENABLE); //使能闹钟中断

RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_ExitConfigMode();//退出RTC的配置模式
RTC_SetPrescaler(32767); //设置RTC预分频的值

RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_Set(2014,1,8,13,38,25);  //设置时间   
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据
}
else//系统继续计时
{

RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断

RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_ALR,ENABLE); //使能闹钟中断

RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
}           
RTC_Get();//更新时间
calendar_alarm_init(13,39);
RCC_ClearFlag(); //清除RCC的复位标志位

return 0; //ok
}


//RTC中断服务函数
void RTC_IRQHandler(void)
{     
if(RTC->CRL&0x0001)//秒钟中断
{
RTC_Get();//更新时间
if((timer.hour!=13)||((timer.hour==13)&&((timer.min<39)||(timer.min>=40))))//在13:38和13:40时间外休眠
{
Sys_Standby(); //13:39和13:40时间工作

}
if(RTC->CRL&0x0002)//闹钟中断
{
RTC->CRL&=~(0x0002);//清闹钟中断
}      
RTC->CRL&=0X0FFA;         //清除溢出,秒钟中断标志
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成            
}

一周热门 更多>