RTC->CRH|=0X01; while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成 break; case 6: case 7: case 8: case 9: case 10 :
case 11 : LCD_ShowString(3,5,str); Speech(str);break; default : break; } }
u16 Process_date(u8 q,u8 b,u8 s,u8 g) { u16 temp;
temp=q*1000+b*100+(s-0x30)*10+(g-0x30); return temp ; }
HARDWARE文件夹下rtc。C文件 #include \#include \ #include \#include \
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途 //Mini STM32开发板
//RTC实时时钟 驱动代码 //正点原子@ALIENTEK
//技术论坛:www.openedv.com //修改日期:2010/12/30 //版本:V1.1
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
//********************************************************************************
//V1.1修改说明
//修改了RTC_Init函数分频设置无效的bug //修改了RTC_Get函数的一个bug
//////////////////////////////////////////////////////////////////////////////////
//Mini STM32开发板
//RTC实时时钟 驱动代码 //正点原子@ALIENTEK //2010/6/6
tm timer;//时钟结构体 //实时时钟配置
//初始化RTC时钟,同时检测时钟是否工作正常 //BKP->DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 u8 RTC_Init(void) { //检查是不是第一次配置时钟 u8 temp=0; if(BKP->DR1!=0X5050)//第一次配置 { RCC->APB1ENR|=1<<28; //使能电源时钟 RCC->APB1ENR|=1<<27; //使能备份时钟 PWR->CR|=1<<8; //取消备份区写保护 RCC->BDCR|=1<<16; //备份区域软复位 RCC->BDCR&=~(1<<16); //备份区域软复位结束 RCC->BDCR|=1<<0; //开启外部低速振荡器 while((!(RCC->BDCR&0X02))&&temp<250)//等待外部时钟就绪 { temp++; delay_ms(10); }; if(temp>=250)return 1;//初始化时钟失败,晶振有问题 RCC->BDCR|=1<<8; //LSI作为RTC时钟 RCC->BDCR|=1<<15;//RTC时钟使能 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH|=0X01; //允许秒中断
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 RTC->CRL|=1<<4; //允许配置 RTC->PRLH=0X0000; RTC->PRLL=32767; //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767 Auto_Time_Set(); //RTC_Set(2009,12,2,10,0,55); //设置时间 RTC->CRL&=~(1<<4); //配置更新 while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成 BKP->DR1=0X5050; //BKP_Write(1,0X5050);;//在寄存器1标记已经开启了 //printf(\ }else//系统继续计时 { while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH|=0x01; //允许秒中断 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 //printf(\ } MY_NVIC_Init(0,0,RTC_IRQChannel,2);//RTC,G2,P2,S2.优先级最低 RTC_Get();//更新时间 return 0; //ok }
//RTC中断服务函数 //const u8* Week[2][7]= //{
//{\//{\日\一\二\三\四\五\六\//}; //RTC时钟中断 //每秒触发一次
void RTC_IRQHandler(void) { if(RTC->CRL&0x0001)//秒钟中断 { RTC_Get();//更新时间 //printf(\ } if(RTC->CRL&0x0002)//闹钟中断 { //printf(\ RTC->CRL&=~(0x0002);//清闹钟中断 //闹钟处理
} 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(year0==0) { if(year@0==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 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;//最后的秒钟加上去 //设置时钟 RCC->APB1ENR|=1<<28; //使能电源时钟 RCC->APB1ENR|=1<<27; //使能备份时钟 PWR->CR|=1<<8; //取消备份区写保护 //上面三步是必须的! RTC->CRL|=1<<4; //允许配置 RTC->CNTL=seccount&0xffff; RTC->CNTH=seccount>>16; RTC->CRL&=~(1<<4);//配置更新 while(!(RTC->CRL&(1<<5)));//等待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;//闰年的秒钟数