STM32F4 裸机RTC驱动

STM32F4裸机RTC驱动,寄存器操作。

/*************************************************************************************************************
 * 文件名		:	RTC.c
 * 功能			:	STM32F4 RTC驱动
 * 作者			:	[email protected]
 * 创建时间		:	2017-07-01
 * 最后修改时间	:	2017-07-01
 * 详细:			要正确读取 RTC 日历寄存器(RTC_SSR、RTC_TR 和 RTC_DR),APB1 时钟频率 (fPCLK1) 必须等于或大于 fRTCCLK RTC 时钟频率的七倍。这可以确保同步机制行为的安全性。
					如果 APB1 时钟频率低于 RTC 时钟频率的七倍,则软件必须分两次读取日历时间寄存器和 日期寄存器。这样,当两次读取的 RTC_TR 结果相同时,才能确保数据正确。
					否则必须执 行第三次读访问。任何情况下,APB1 的时钟频率都不能低于 RTC 的时钟频率。
					RTC->BKP0R:用于标示是否进行了初始化RTC,请不要再使用了。
					注意:初始化时会使用调试串口打印信息
					2017-01-15:修改全局时间结构体名称为g_timer,并且增加系统命令支持
*************************************************************************************************************/	
#include "rtc.h"
#include "system.h" 

volatile tm g_timer;								//全局系统时钟

//秒中断回调函数
static void (*RTC_SerIntCallBack)(void) ;			//秒中断回调函数

//内部函数申明
u8 RTC_GetWeek(u16 year,u8 month,u8 day);		//获取2000-2099年之间的日期对应的星期
u32 RTC_DECtoBCD( u8 DEC);						//将数字转换为压缩BCD格式,最大支持99
u32 RTC_BCDtoDEC(u8 BCD);						//将压缩BCD转为DEC,最大支持99

/*************************************************************************************************************************
* 函数			:	bool RTC_WaitSynchro(void)
* 功能			:	等待RSF同步
* 参数			:	无
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	
*************************************************************************************************************************/
bool RTC_WaitSynchro(void)
{ 
	u32 retry=0XFFFFF; 
	
	//执行以下步骤解锁RTC寄存器写保护
	RTC->WPR = 0xCA;						//写入KEY后关闭RTC寄存器写保护
	RTC->WPR = 0x53; 
	
	RTC->ISR &= ~(1<<5);					//先清除RSF位 
	while(retry && ((RTC->ISR&(1<<5))==0))	//等待影子寄存器同步
	{
		nop;
		retry--;
	}
    if(retry==0) return FALSE;				//超时了,同步失败 
	RTC->WPR= 0xff;							//随便写入一个值(不是KEY)使能RTC寄存器写保护 
	
	return TRUE;
}




/*************************************************************************************************************************
* 函数			:	bool RTC_InitMode(void)
* 功能			:	RTC进入初始化模式
* 参数			:	无
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	
*************************************************************************************************************************/
bool RTC_InitMode(void)
{ 
	u32 retry=0X10000; 
		
	if(RTC->ISR & (1<<6))	return TRUE; 	//当此位置 1 时,RTC 处于初始化状态,此时可更新事件、日期和预分频器寄存器。
	RTC->ISR |= 1<<7;		//进入RTC初始化模式
	while(retry && ((RTC->ISR&(1<<6))==0x00))//等待进入RTC初始化模式成功
	{
		nop;nop;nop;
		retry--;
	}
    if(retry==0)return FALSE;	//同步失败
	else return TRUE; 			//同步成功 
}





/*************************************************************************************************************************
* 函数			:	bool RTC_SetTime(u8 hour,u8 min,u8 sec)
* 功能			:	RTC时间设置
* 参数			:	hour,min,sec:小时,分钟,秒钟
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	会自动退出写保护
*************************************************************************************************************************/
bool RTC_SetTime(u8 hour,u8 min,u8 sec)
{
	u32 temp;
	
	//执行以下步骤解锁RTC寄存器写保护
	RTC->WPR = 0xCA;						//写入KEY后关闭RTC寄存器写保护
	RTC->WPR = 0x53; 
	if(RTC_InitMode() == FALSE)return FALSE;//进入RTC初始化模式失败
	temp = (u32)RTC_DECtoBCD(hour) << 16;	//小时
	temp |= (u32)RTC_DECtoBCD(min) << 8;	//分钟
	temp |= (u32)RTC_DECtoBCD(sec) << 0;	//秒钟
	
	RTC->TR=temp;							//设置时间
	RTC->ISR&=~(1<<7);						//退出RTC初始化模式 
	RTC->WPR = 0xFF;						//开启写保护
	
	return TRUE; 
}


/*************************************************************************************************************************
* 函数			:	bool RTC_SetDate(u16 year,u8 month,u8 date)
* 功能			:	RTC日期设置
* 参数			:	year,month,date:年(2000~2099),月(1~12),日(1~31)
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	会自动退出写保护
*************************************************************************************************************************/
bool RTC_SetDate(u16 year,u8 month,u8 date)
{
	u32 temp;
	u8 week;
	
	//执行以下步骤解锁RTC寄存器写保护
	RTC->WPR = 0xCA;						//写入KEY后关闭RTC寄存器写保护
	RTC->WPR = 0x53; 
	if(RTC_InitMode() == FALSE)return FALSE;//进入RTC初始化模式失败
	if(year < 2000) year = 2000;			//限制年
	if(year > 2099) year = 2099;			//限制年
	if(month < 1) month = 1;				//限制月
	if(month > 12) month = 12;				//限制月
	if(date < 1) date = 1;					//限制日
	if(date > 31) date = 31;				//限制日
	week = RTC_GetWeek(year,month,date);	//计算设置的日期对应的星期
	year -= 2000;							//年转换为0-99
	
	temp = (u32)RTC_DECtoBCD(year)<<16;		//年
	temp |= week<<13;						//星期
	temp |= (u32)RTC_DECtoBCD(month)<<8;	//月份
	temp |= (u32)RTC_DECtoBCD(date)<<0;		//日期
	
	RTC->DR=temp;							//写入
	RTC->ISR&=~(1<<7);						//退出RTC初始化模式 
	RTC->WPR = 0xFF;						//开启写保护
	
	return TRUE; 
}


/*************************************************************************************************************************
* 函数			:	bool RTC_GetTime(u8 *hour,u8 *min,u8 *sec)
* 功能			:	获取RTC时间
* 参数			:	*hour,*min,*sec:小时,分钟,秒钟 
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	24小时制
*************************************************************************************************************************/
bool RTC_GetTime(u8 *hour,u8 *min,u8 *sec)
{
	u32 temp;
	u32 retry = 5250*3;
	u8 ampm;
	
 	while((RTC_WaitSynchro() == FALSE) && (retry!=0))	//等待同步  	 
	{
		nop;nop;nop;nop;nop;nop;
		retry --;
	}
	if(retry==0) return FALSE;
	
	temp=RTC->TR;
	*hour=RTC_BCDtoDEC((temp>>16)&0X3F);
	*min=RTC_BCDtoDEC((temp>>8)&0X7F);
	*sec=RTC_BCDtoDEC(temp&0X7F);
	
	ampm=temp>>22; 
	if(ampm!=0)	//使用的是12小时制,并且是下午,则小时加上12小时
	{
		*hour += 12;
	}
	
	return TRUE;
}


/*************************************************************************************************************************
* 函数			:	bool RTC_GetDate(u16 *year,u8 *month,u8 *date,u8 *week)
* 功能			:	获取RTC日期
* 参数			:	*year,*mon,*date:年,月,日;*week:星期
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	
*************************************************************************************************************************/
bool RTC_GetDate(u16 *year,u8 *month,u8 *date,u8 *week)
{
	u32 retry = 5250*3;
	u32 temp;
	
 	while((RTC_WaitSynchro() == FALSE) && (retry!=0))	//等待同步  	 
	{
		nop;nop;nop;nop;nop;nop;
		retry --;
	}
	if(retry==0) return FALSE;	 
	temp=RTC->DR;
	*year=RTC_BCDtoDEC((temp>>16)&0XFF)+2000;
	*month=RTC_BCDtoDEC((temp>>8)&0X1F);
	*date=RTC_BCDtoDEC(temp&0X3F);
	*week=(temp>>13)&0X07; 
	
	return TRUE;
}


/*************************************************************************************************************************
* 函数			:	bool RTC_Get(void)
* 功能			:	更新RTC时间
* 参数			:	无
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	APB时钟必须大于RTC时钟7倍,通常会远大于,一般APB少说也得1MHZ以上
					时间写入到了全局缓冲区 timer 中
*************************************************************************************************************************/
bool RTC_Get(void)
{
	u32 temp;
	u32 retry = 5250*3;
	u8 ampm;
	
 	while((RTC_WaitSynchro() == FALSE) && (retry!=0))	//等待同步  	 
	{
		nop;nop;nop;nop;nop;nop;
		retry --;
	}
	if(retry==0) return FALSE;
	//获取日期
	temp=RTC->DR;
	g_timer.year=RTC_BCDtoDEC((temp>>16)&0XFF)+2000;
	g_timer.month=RTC_BCDtoDEC((temp>>8)&0X1F);
	g_timer.date=RTC_BCDtoDEC(temp&0X3F);
	g_timer.week=(temp>>13)&0X07; 
	//获取时间
	temp=RTC->TR;
	g_timer.hour=RTC_BCDtoDEC((temp>>16)&0X3F);
	g_timer.min=RTC_BCDtoDEC((temp>>8)&0X7F);
	g_timer.sec=RTC_BCDtoDEC(temp&0X7F);
	
	ampm=temp>>22; 
	if(ampm!=0)	//使用的是12小时制,并且是下午,则小时加上12小时
	{
		g_timer.hour += 12;
	}
	
	return TRUE;
}


/*************************************************************************************************************************
* 函数			:	bool RTC_SetWakeUp(bool isEnableInt, u16 WakeSecs)
* 功能			:	RTC唤醒中断设置
* 参数			:	isEnableInt:是否开启唤醒中断;WakeSecs:唤醒周期,单位秒
* 返回			:	TRUE:开启成功;FALSE:开启失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-02
* 最后修改时间 	: 	2017-07-02
* 说明			: 	
*************************************************************************************************************************/
bool RTC_SetWakeUp(bool isEnableInt, u16 WakeSecs)
{
	u32 temp = RTC->CR;
	u32 retry = 500;
	
	//关闭RTC寄存器写保护
	RTC->WPR=0xCA;
	RTC->WPR=0x53; 
	if(WakeSecs==0) WakeSecs = 1;		//最少1秒	
	temp |= 1<<10;						//唤醒定时器使能	
	if(isEnableInt)	//需要开启唤醒中断
	{			
		temp |= 1<<14;					//使能唤醒定时器中断	
		SYS_EXTI_SetEdge(EXTI_RTC_WAKE_UP, EXTI_POS_EDGE);	//设置RTC唤醒中断上升沿触发
		SYS_EXTI_IntEnable(EXTI_RTC_WAKE_UP, TRUE);			//RTC唤醒中断EXTI开关
		SYS_EXTI_ClearInt(EXTI_RTC_WAKE_UP);				//清除中断标记
		SYS_NVIC_IntEnable(IRQ_RTC_WKUP, TRUE);				//RTC唤醒中断 NVIC全局中断使能
	}
	else
	{	
		temp &= ~(1<<14);				//关闭唤醒定时器中断
		SYS_EXTI_SetEdge(EXTI_RTC_WAKE_UP, EXTI_NULL_EDGE);	//关闭RTC唤醒中断边沿触发
		SYS_EXTI_IntEnable(EXTI_RTC_WAKE_UP, FALSE);		//RTC唤醒中断EXTI开关
		SYS_EXTI_ClearInt(EXTI_RTC_WAKE_UP);				//清除中断标记
		SYS_NVIC_IntEnable(IRQ_RTC_WKUP, FALSE);			//RTC唤醒中断 NVIC全局中断使失能
	}
	RTC->ISR &= ~(1<<10);				//清除唤醒中断标志
	temp &= ~0x07;						//清除唤醒时钟来源
	temp |= 4;							//选择 ck_spre 时钟(通常为 1 Hz)	
	if(RTC->WUTR != (WakeSecs-1))
	{
		//在 RTC_CR 寄存器中的 WUTE 位置 0 后,当唤醒定时器值可更改时,由硬件将该位置 1。
		//仅当 RTC_ISR 中的 WUTWF 置 1 时才可对该寄存器执行写操作。
		RTC->CR &= ~(1<<10);				//WUTE 置 0
		while(((RTC->ISR & (1 << 2)) == 0) && retry)
		{
			Delay_US(1);
			retry --;
		}
		if(retry==0)
		{
			uart_printf("设置RTC唤醒定时器失败!");
			return FALSE;
		}
		
		RTC->WUTR = WakeSecs-1;				//重新设置唤醒自动重载值
	}
	
	RTC->CR = temp;						//设置配置寄存器
	
	RTC->WPR=0xFF;						//开启写保护
	
	return TRUE;
}

/*************************************************************************************************************************
* 函数			:	bool RTC_Init(bool SerIntEnable)
* 功能			:	RTC初始化
* 参数			:	SerIntEnable:TRUE:开启秒中断;FALSE:关闭秒中断
* 返回			:	TRUE:成功,FALSE:失败
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2017-07-01
* 最后修改时间 	: 	2017-07-01
* 说明			: 	使用备份区0存放标志来区别是否进行过初始化 RTC->BKP0R=0x5A5AA5A5
*************************************************************************************************************************/
bool RTC_Init(bool SerIntEnable)
{
	u32 retry=0XFFFFFFF; 
	
	RCC->APB1ENR|=1<<28;			//使能电源接口时钟
	PWR->CR|=1<<8;					//后备区域访问使能(RTC+SRAM)
	if(RTC->BKP0R != 0x5A5AA5A5)	//没有进行过配置
	{
		info_printf("RTC没有初始化,开始初始化...\r\n");
		RCC->BDCR|=1<<0;			//LSE 开启  
		while(retry&&((RCC->BDCR&0X02)==0))//等待LSE准备好
		{
			retry--;
			nop;nop;nop;
		}
		if(retry==0)
		{
			info_printf("RTC时钟初始化失败了!\r\n");
			return FALSE;		//LSE 开启失败.
		}
			 
		RCC->BDCR|=1<<8;			//选择LSE,作为RTC的时钟
		RCC->BDCR|=1<<15;			//使能RTC时钟
 		//关闭RTC寄存器写保护
		RTC->WPR=0xCA;
		RTC->WPR=0x53; 
		if(RTC_InitMode() == FALSE)//进入RTC初始化模式
		{
			info_printf("RTC进入初始化模式失败了!\r\n");
			return FALSE;			
		}
		//将32768 进行128x256分频 得到1秒的 ck_spre频率,用于产生秒唤醒中断
		RTC->PRER=255;				//RTC同步分频系数(0~7FFF),必须先设置同步分频,再设置异步分频,Frtc=Fclks/((Sprec+1)*(Asprec+1))
		RTC->PRER|=127<<16;			//RTC异步分频系数(1~0X7F)
		RTC->CR&=~(1<<6);			//RTC设置为,24小时格式
		RTC->ISR&=~(1<<7);			//退出RTC初始化模式
		RTC->WPR=0xFF;				//使能RTC寄存器写保护  
		RTC_SetTime(6,6,6);			//设置初始时间
		RTC_SetDate(2017,6,6);		//设置初始日期
		RTC->BKP0R = 0x5A5AA5A5;	//写入备份区标记,标示已经初始化过RTC
		
		
		info_printf("初始化RTC成功!\r\n");
		
		//RTC_Set_AlarmA(7,0,0,10);	//设置闹钟时间
	} 
	//RTC_Set_WakeUp(4,0);			
	if(RTC_Get()==FALSE)			//更新一次时间
	{
		info_printf("初始获取时间失败!\r\n");
	}
	RTC_SetWakeUp(SerIntEnable, 1);//配置WAKE UP中断,1秒钟中断一次 
	
	return TRUE;
}

//设置秒中断回调函数
void RTC_SetWkupCallBack(void (*pCallBack)(void))
{
	RTC_SerIntCallBack = pCallBack;
}


//RTC闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{    
	if(RTC->ISR&(1<<8))//ALARM A中断?
	{
		RTC->ISR&=~(1<<8);	//清除中断标志
		uart_printf("ALARM A!\r\n");
	}   
	EXTI->PR|=1<<17;	//清除中断线17的中断标志 											 
}



//RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{    
	if(RTC->ISR&(1<<10))//WK_UP中断
	{ 
		
		RTC->ISR&=~(1<<10);	//清除中断标志
		
		if(RTC_SerIntCallBack!=NULL)	//回调函数有效
		{
			RTC_SerIntCallBack();	//执行回调函数
		}
		
		//RTC_Get();
		//uart_printf("%04d-%02d-%02d %02d:%02d:%02d\r\n",g_timer.year,g_timer.month,g_timer.date,g_timer.hour,g_timer.min,g_timer.sec);
	}   
	SYS_EXTI_ClearInt(EXTI_RTC_WAKE_UP);//清除中断线标记								
}



u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表	  
//获取2000-2099年之间的日期对应的星期
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//year,month,day:公历年月日 
//返回值:星期号(1~7,代表周1~周日)																						 
u8 RTC_GetWeek(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--;
	temp2%=7;
	if(temp2==0)temp2=7;
	return temp2;
}	




//将数字转换为压缩BCD格式,最大支持99
u32 RTC_DECtoBCD( u8 DEC) 
{
	return ((u8)(DEC/10)<<4)+(DEC%10);
}


//将压缩BCD转为DEC,最大支持99
u32 RTC_BCDtoDEC(u8 BCD)
{
	return (u8)(BCD>>4)*10+(BCD&0x0f);
}







//使能系统命令行
#if SYS_CMD_EN_
#include "sys_cmd.h"
#include "string.h"

const SYS_CMD_TYPE  CMD_GET_TIME		=	{"TIME?", CMD_GetTime, "\t\t获取系统时间", TRUE};
const SYS_CMD_TYPE  CMD_GET_DATE		=	{"DATE?", CMD_GetDate, "\t\t获取系统日期", TRUE};
const SYS_CMD_TYPE  CMD_SET_TIME		=	{"TIME=", CMD_SetTime, "\t\t设置系统时间 如(12:32:54):TIME=12 32 54", TRUE};
const SYS_CMD_TYPE  CMD_SET_DATE		=	{"DATE=", CMD_SetDate, "\t\t设置系统日期 如(2014 6 8):TIME=2014 6 8", TRUE};

//获取时间
void CMD_GetTime(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	RTC_Get();		//更新时间
	pHandle->DataPrintf("[获取时间成功]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
}

//获取日期
void CMD_GetDate(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	RTC_Get();		//更新时间
	pHandle->DataPrintf("[获取日期成功]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
}

//设置时间
void CMD_SetTime(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	u8 hour,min,sec;
	u8 len;
	char *p;
	u8 num;
	
	len = strlen(pStr);	//获取长度
	if(isStrNumAndSpc(pStr, len, 2) == FALSE)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//小时
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	hour = SYS_CMD_StringToDec(pStr, num);
	if(hour>23)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	//分钟
	pStr = p+1;
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	min = SYS_CMD_StringToDec(pStr, num);
	if(min>59)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//秒钟
	pStr = p+1;
	num = strlen(pStr);
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	sec = SYS_CMD_StringToDec(pStr, num);
	if(sec>59)
	{
		pHandle->DataPrintf("[时间设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	if(RTC_SetTime(hour, min, sec) == FALSE)
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[时间设置失败]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
	}
	else
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[时间设置成功]:%02d:%02d:%02d\r\n",g_timer.hour, g_timer.min, g_timer.sec);
	}
	
} 


//设置日期
void CMD_SetDate(SYS_CMD_HANDLE *pHandle,char *pStr)
{
	u16 year;
	u8 month, date;
	u8 len;
	char *p;
	u8 num;
	
	len = strlen(pStr);	//获取长度
	if(isStrNumAndSpc(pStr, len, 2) == FALSE)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//年
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 4) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	year = SYS_CMD_StringToDec(pStr, num);
	if(year>9999)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	
	//月
	pStr = p+1;
	p = strstr(pStr," ");	//搜索空格
	if(p == NULL)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	num = p - pStr;
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	month = SYS_CMD_StringToDec(pStr, num);
	if(month>12)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	//日
	pStr = p+1;
	num = strlen(pStr);
	if((num > 2) || (num == 0))
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	date = SYS_CMD_StringToDec(pStr, num);
	if(date>31)
	{
		pHandle->DataPrintf("[日期设置错误]:格式不对或非法参数!\r\n");
		return;
	}
	

	if(RTC_SetDate(year, month, date) == FALSE)
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[日期设置失败]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
	}
	else
	{
		RTC_Get();		//更新时间
		pHandle->DataPrintf("[日期设置成功]:%04d-%02d-%02d\r\n",g_timer.year, g_timer.month, g_timer.date);
	}
	
} 


#endif //SYS_CMD_EN_

/*************************************************************************************************************
 * 文件名		:	RTC.h
 * 功能			:	STM32F4 RTC驱动
 * 作者			:	[email protected]
 * 创建时间		:	2017-07-01
 * 最后修改时间	:	2017-07-01
 * 详细:			要正确读取 RTC 日历寄存器(RTC_SSR、RTC_TR 和 RTC_DR),APB1 时钟频率 (fPCLK1) 必须等于或大于 fRTCCLK RTC 时钟频率的七倍。这可以确保同步机制行为的安全性。
					如果 APB1 时钟频率低于 RTC 时钟频率的七倍,则软件必须分两次读取日历时间寄存器和 日期寄存器。这样,当两次读取的 RTC_TR 结果相同时,才能确保数据正确。
					否则必须执 行第三次读访问。任何情况下,APB1 的时钟频率都不能低于 RTC 的时钟频率。
					RTC->BKP0R:用于标示是否进行了初始化RTC,请不要再使用了。
*************************************************************************************************************/
#ifndef __RTC_H_
#define __RTC_H_
#include "system.h" 


//时间结构体
typedef  struct 
{
	u8	hour; 		//小时
	u8	min;	 	//分钟
	u8	sec;		//秒			
	u8  month;		//月
	u8  date;		//日
	u8  week;		//星期
	u16 year;	 	//年
}tm;
extern volatile tm g_timer;



//函数接口
bool RTC_SetTime(u8 hour,u8 min,u8 sec);	//RTC时间设置
bool RTC_SetDate(u16 year,u8 month,u8 date);//RTC日期设置
bool RTC_GetTime(u8 *hour,u8 *min,u8 *sec);	//获取RTC时间
bool RTC_GetDate(u16 *year,u8 *month,u8 *date,u8 *week);//获取RTC日期
bool RTC_Get(void);							//更新RTC时间
bool RTC_Init(bool SerIntEnable);			//RTC初始化
bool RTC_SetWakeUp(bool isEnableInt, u16 WakeSecs);	//RTC唤醒中断设置
void RTC_SetWkupCallBack(void (*pCallBack)(void));//设置秒中断回调函数



//使能系统命令行
#if SYS_CMD_EN_
#include "sys_cmd.h"
#include "string.h"

extern const SYS_CMD_TYPE  CMD_GET_TIME;
extern const SYS_CMD_TYPE  CMD_GET_DATE;
extern const SYS_CMD_TYPE  CMD_SET_TIME;
extern const SYS_CMD_TYPE  CMD_SET_DATE;


//获取时间
void CMD_GetTime(SYS_CMD_HANDLE *pHandle,char *pStr);
//获取日期
void CMD_GetDate(SYS_CMD_HANDLE *pHandle,char *pStr);
//设置时间
void CMD_SetTime(SYS_CMD_HANDLE *pHandle,char *pStr);
//设置日期
void CMD_SetDate(SYS_CMD_HANDLE *pHandle,char *pStr);

#endif //SYS_CMD_EN_




#endif //__RTC_H_

使用时需要一个秒中断回调函数,比如我的秒中断是用来唤醒一个线程,处理秒任务

RTC_Init(TRUE);


//任务2:负责后台(RTC 1秒唤醒一次)
void TaskBack(void *pdata)
{
	RTC_SetWkupCallBack(RTC_WkupCallBack);					//设置RTC回调函数
	
	while(1)
	{
		RTC_Get();											//更新系统时间
		uart_printf("%04d-%02d-%02d %02d:%02d:%02d\r\n",g_timer.year,g_timer.month,g_timer.date,g_timer.hour,g_timer.min,g_timer.sec);
		OSTimeDlyHMSM(0,0,0,100);
		IWDG_Feed();

		OSTaskSuspend(BACK_TASK_Prio);						//挂起后台进程
	}
}
//RTC秒中断回调函数
void RTC_WkupCallBack(void)
{
	OSTaskResume(BACK_TASK_Prio);						//唤醒后台进程
}



猜你喜欢

转载自blog.csdn.net/cp1300/article/details/79100092