STM32 RTC时钟设置

RTC移植时注意两点

(1)RTC需要中断函数。每秒中断一次,更新需要显示的标志。

(2)RTC运行中校正时间,更新RTC_CNTx时不能直接调用Time_Adjust()函数,需要开启PWR 和 BKP 时钟,且允许访问BKP域。

void RTC_SetCurrentTime(struct rtc_time *tm)
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
	
Time_Adjust(tm);

RCC_ClearFlag();
}

RTC的配置代码如下:

/**
  ******************************************************************************
  * 文件名程: bsp_rtc.c 
  * 作    者: 硬石嵌入式开发团队
  * 版    本: V1.0
  * 编写日期: 2015-10-04
  * 功    能: 实时时钟底层驱动程序
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F1Pro使用。
  * 
  * 淘宝:
  * 论坛:http://www.ing10bbs.com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */
/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp/usart/bsp_usartx.h"
#include  "bsp/rtc/bsp_rtc.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/*星期,生肖用文字ASCII码*/
uint8_t const *WEEK_STR[] = {"日", "一", "二", "三", "四", "五", "六"};
uint8_t const *zodiac_sign[] = {"猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗"};

/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
void Time_Adjust(struct rtc_time *tm);
static uint8_t USART_Scanf(uint32_t value);
void Time_Regulate(struct rtc_time *tm);


/* 函数体 --------------------------------------------------------------------*/
/**
  * 函数功能: 配置RTC秒中断的主中断优先级为1,次优先级为0
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
static void RTC_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* Enable the RTC Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/**
  * 函数功能: 简单的延时函数
  * 输入参数: time:延时时间
  * 返 回 值: 无
  * 说    明:无
  */
static void Delay(uint16_t time)
{
  uint16_t i;
  while(--time)
  {
    for(i=0;i<2000;i++);
  }
}

/**
  * 函数功能: 配置RTC
  * 输入参数: 无
  * 返 回 值: 1:RTC配置成功或运行正常,0:RTC无法正常使用
  * 说    明:无
  */
static uint8_t RTC_Configuration(void)
{
  uint32_t count=0;
  
	/* Enable PWR and BKP clocks */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	
	/* Allow access to BKP Domain */
	PWR_BackupAccessCmd(ENABLE);
	
	/* Reset Backup Domain */
	BKP_DeInit();
	
	/* Enable LSE */
	RCC_LSEConfig(RCC_LSE_ON);
	
	/* Wait till LSE is ready */
	while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
	{
     Delay(100);
     count++;
     if(count>4000)return 0;
  }
	
	/* Select LSE as RTC Clock Source */
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
	
	/* Enable RTC Clock */
	RCC_RTCCLKCmd(ENABLE);
	
	/* Wait for RTC registers synchronization 
	 * 因为RTC时钟是低速的,内环时钟是高速的,所以要同步
	 */
	RTC_WaitForSynchro();
	
	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();
	
	/* Enable the RTC Second */
	RTC_ITConfig(RTC_IT_SEC, ENABLE);
	
	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();
	
	/* Set RTC prescaler: set RTC period to 1sec */
	RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) = 1HZ */
	
	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();
  
  return 1;
}


void RTC_SetCurrentTime(struct rtc_time *tm)
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
	
Time_Adjust(tm);

RCC_ClearFlag();
}

void RTC_SetAlarmTime(struct rtc_time *tm)
{
Time_Regulate(tm);
}






/**
  * 函数功能: 检查并配置RTC
  * 输入参数: tm:用于读取RTC时间的结构体指针
  * 返 回 值: 无
  * 说    明:无
  */
uint8_t RTC_CheckAndConfig(struct rtc_time *tm)
{
  /* 配置RTC秒中断的主中断优先级 */
  RTC_NVIC_Config();
  
  /*在启动时检查备份寄存器BKP_DR1,如果内容不是0xA5A5,
	  则需重新配置时间并询问用户调整时间*/
	

	if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
	{
		printf("RTC not yet configured....\n");

		/* RTC Configuration */
		if(RTC_Configuration()!=1)
		{
      return 0;
		}
		printf("RTC configured....\n");

		/* Adjust time by users typed on the hyperterminal */
		
		
		Time_Adjust(tm);

		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
	}
	else
	{
	  /*启动无需设置新时钟*/
		/*检查是否掉电重启*/
		if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
		{
		    printf("Power On Reset occurred....\n");
		}
		/*检查是否Reset复位*/
		else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
		{
			printf("External Reset occurred....\n");
		}
	
		printf("No need to configure RTC....\n");
		
		/*等待寄存器同步*/
		RTC_WaitForSynchro();
		
		/*允许RTC秒中断*/
		RTC_ITConfig(RTC_IT_SEC, ENABLE);
		
		/*等待上次RTC寄存器写操作完成*/
		RTC_WaitForLastTask();
	}
	   /*定义了时钟输出宏,则配置校正时钟输出到PC13*/
	#ifdef RTCClockOutput_Enable
	  /* Enable PWR and BKP clocks */
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	
	  /* Allow access to BKP Domain */
	  PWR_BackupAccessCmd(ENABLE);
	
	  /* Disable the Tamper Pin */
	  BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper
	                                 functionality must be disabled */
	
	  /* Enable RTC Clock Output on Tamper Pin */
	  BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
	#endif
	
	  /* Clear reset flags */
	  RCC_ClearFlag();
  
  return 1;
}
/**
  * 函数功能: 时间调节实现
  * 输入参数: tm:用于读取RTC时间的结构体指针
  * 返 回 值: 无
  * 说    明:无
  */

/**
  *  static
  * 函数功能: 时间调整,保存在RTC时钟结构体
  * 输入参数: tm:用于读取RTC时间的结构体指针
  * 返 回 值: 无
  * 说    明:无
  */
 void Time_Regulate(struct rtc_time *tm)
{
#if 0
  tm->tm_year = 2015;
  tm->tm_mon  =   10;
  tm->tm_mday =    4;	
  tm->tm_hour =   10;	 
  tm->tm_min  =   15;	 
  tm->tm_sec  =   46;
#else
  u32 Tmp_YY = 0xFF, Tmp_MM = 0xFF, Tmp_DD = 0xFF, Tmp_HH = 0xFF, Tmp_MI = 0xFF, Tmp_SS = 0xFF;

  printf("=========================Time Settings==================\n");

  printf("请输入年份(Please Set Years):  20\n");

  while (Tmp_YY == 0xFF)
  {
    Tmp_YY = USART_Scanf(99);
  }

  printf("年份被设置为:  20%0.2d\n", Tmp_YY);

  tm->tm_year = Tmp_YY+2000;

  Tmp_MM = 0xFF;

  printf("请输入月份(Please Set Months):  \n");

  while (Tmp_MM == 0xFF)
  {
    Tmp_MM = USART_Scanf(12);
  }

  printf("月份被设置为:  %d\n", Tmp_MM);

  tm->tm_mon= Tmp_MM;

  Tmp_DD = 0xFF;

  printf("请输入日期(Please Set Dates):  \n");

  while (Tmp_DD == 0xFF)
  {
    Tmp_DD = USART_Scanf(31);
  }

  printf("日期被设置为:  %d\n", Tmp_DD);

  tm->tm_mday= Tmp_DD;

  Tmp_HH  = 0xFF;

  printf("请输入时钟(Please Set Hours):  \n");

  while (Tmp_HH == 0xFF)
  {
    Tmp_HH = USART_Scanf(23);
  }

  printf("时钟被设置为:  %d\n", Tmp_HH );

  tm->tm_hour= Tmp_HH;
    
  Tmp_MI = 0xFF;

  printf("请输入分钟(Please Set Minutes):  \n");

  while (Tmp_MI == 0xFF)
  {
    Tmp_MI = USART_Scanf(59);
  }

  printf("分钟被设置为:  %d\n", Tmp_MI);

  tm->tm_min= Tmp_MI;

  Tmp_SS = 0xFF;

  printf("请输入秒钟(Please Set Seconds):  \n");

  while (Tmp_SS == 0xFF)
  {
    Tmp_SS = USART_Scanf(59);
  }

  printf("秒钟被设置为:  %d\n", Tmp_SS);

  tm->tm_sec= Tmp_SS;  
#endif
}


void Time_Adjust(struct rtc_time *tm)
{
	  /* Wait until last write operation on RTC registers has finished */
	  RTC_WaitForLastTask();
	
	  /* Get time entred by the user on the hyperterminal */
	  Time_Regulate(tm);
	  
	  /* Get wday */
	  GregorianDay(tm);

	  /* 修改当前RTC计数寄存器内容 */
	  RTC_SetCounter(mktimev(tm));

	  /* Wait until last write operation on RTC registers has finished */
	  RTC_WaitForLastTask();
}







		/**
			* 函数功能: 从串口调试助手获取数字值(把ASCII码转换为数字)
			* 输入参数: value 用户在超级终端中输入的数值
			* 返 回 值: 输入字符的ASCII码对应的数值
			* 说    明:本函数专用于RTC获取时间,若进行其它输入应用,要修改一下
			*/
		static uint8_t USART_Scanf(uint32_t value)
		{
			uint32_t index = 0;
			uint32_t tmp[2] = {0, 0};

			while (index < 2)
			{
				/* Loop until RXNE = 1 */
				while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
				{
				}  
				tmp[index++] = (USART_ReceiveData(USART1));
				if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))   /*数字0到9的ASCII码为0x30至0x39*/
				{ 		  
					printf("Please enter valid number between 0 and 9 -->:  \n");
					index--; 		 
				}
			}
			
			/* 计算输入字符的ASCII码转换为数字*/
			index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
			
			/* Checks */
			if (index > value)
			{
				printf("Please enter valid number between 0 and %d\n", value);
				return 0xFF;
			}
			return index;
		}




/**
  * 函数功能: 显示当前时间值
  * 输入参数: TimeVar RTC计数值,单位为 s,tm:用于读取RTC时间的结构体指针
  * 返 回 值: 无
  * 说    明:无
  */
void Time_Display(uint32_t TimeVar,struct rtc_time *tm)
{
   static uint8_t FirstDisplay = 1;
   uint32_t BJ_TimeVar;
   uint8_t str[15]; // 字符串暂存  	

   /*  把标准时间转换为北京时间*/
   BJ_TimeVar =TimeVar + 8*60*60;

   to_tm(BJ_TimeVar, tm);/*把定时器的值转换为北京时间*/	

  if((!tm->tm_hour && !tm->tm_min && !tm->tm_sec)  || (FirstDisplay))
  {
      
    GetChinaCalendar((u16)tm->tm_year, (u8)tm->tm_mon, (u8)tm->tm_mday, str);	
      printf("今天新历:%0.2d%0.2d,%0.2d,%0.2d\n", str[0], str[1], str[2],  str[3]);

    GetChinaCalendarStr((u16)tm->tm_year,(u8)tm->tm_mon,(u8)tm->tm_mday,str);
      printf("今天农历:%s\n", str);

   if(GetJieQiStr((u16)tm->tm_year, (u8)tm->tm_mon, (u8)tm->tm_mday, str))
      printf("今天农历:%s\n", str);

    FirstDisplay = 0;
  }	 	  	
  /* 输出时间戳,公历时间 */
  printf(" UNIX时间戳 = %d 当前时间为: %d年(%s年) %d月 %d日 (星期%s)  %0.2d:%0.2d:%0.2d\n",TimeVar,
                    tm->tm_year, zodiac_sign[(tm->tm_year-3)%12], tm->tm_mon, tm->tm_mday, 
                    WEEK_STR[tm->tm_wday], tm->tm_hour, 
                    tm->tm_min, tm->tm_sec);
}










/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/


RTC程序文件:http://pan.baidu.com/s/1jIzfaxo


你可能感兴趣的:(STM32开发,stm32)