#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(),这三个函数有点问题,愣是没找到。
一周热门 更多>