实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。
系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问:
● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。
附上代码
1 RTC配置代码
/* 秒中断标志,进入秒中断时置1,当时间被刷新之后清0 */
__IO uint32_t TimeDisplay;
/*
* 函数名:NVIC_Configuration
* 描述 :配置RTC秒中断的主中断优先级为1,次优先级为0
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 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);
}
/*
* 函数名:RTC_Configuration
* 描述 :配置RTC
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void RTC_Configuration(void)
{
/* 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)
{}
/* Select LSE as RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization */
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) */
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
/*
* 函数名:Time_Regulate
* 描述 :返回用户在超级终端中输入的时间值,并将值储存在
* RTC 计数寄存器中。
* 输入 :无
* 输出 :用户在超级终端中输入的时间值,单位为 s
* 调用 :内部调用
*/
uint32_t Time_Regulate(void)
{
uint32_t Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF;
printf("\r\n==============时间设定=====================================");
printf("\r\n 请设置小时");
while (Tmp_HH == 0xFF)
{
Tmp_HH = USART_Scanf(23);
}
printf(": %d", Tmp_HH);
printf("\r\n 请设置分钟");
while (Tmp_MM == 0xFF)
{
Tmp_MM = USART_Scanf(59);
}
printf(": %d", Tmp_MM);
printf("\r\n 请设置秒");
while (Tmp_SS == 0xFF)
{
Tmp_SS = USART_Scanf(59);
}
printf(": %d", Tmp_SS);
/* Return the value to store in RTC counter register */
return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));
}
/*
* 函数名:Time_Adjust
* 描述 :时间调节
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void Time_Adjust(void)
{
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Change the current time */
RTC_SetCounter(Time_Regulate());
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
/*
* 函数名:Time_Display
* 描述 :显示当前时间值
* 输入 :-TimeVar RTC计数值,单位为 s
* 输出 :无
* 调用 :内部调用
*/
void Time_Display(uint32_t TimeVar)
{
uint32_t THH = 0, TMM = 0, TSS = 0;
/* Compute hours */
THH = TimeVar / 3600;
/* Compute minutes */
TMM = (TimeVar % 3600) / 60;
/* Compute seconds */
TSS = (TimeVar % 3600) % 60;
printf("\n 当前时间: %0.2d:%0.2d:%0.2d\r\n", THH, TMM, TSS);
}
/*
* 函数名:Time_Show
* 描述 :在超级终端中显示当前时间值
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void Time_Show(void)
{
printf("\n\r");
/* Infinite loop */
while (1)
{
/* If 1s has paased */
if (TimeDisplay == 1)
{
/* Display current time */
Time_Display(RTC_GetCounter());
TimeDisplay = 0;
}
}
}
/*
* 函数名:USART_Scanf
* 描述 :串口从超级终端中获取数值
* 输入 :- value 用户在超级终端中输入的数值
* 输出 :无
* 调用 :内部调用
*/
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));
// 从串口终端里面输进去的数是ASCII码值
if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))
{
printf("\n\r请输入从0到9之间的数据");
index--;
}
}
/* Calculate the Corresponding value */
index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
/* Checks */
if (index > value)
{
printf("\n\rPlease enter valid number between 0 and %d", value);
return 0xFF;
}
return index;
}
2 USART配置代码
void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while ( *Data != 0) // 判断是否到达字符串结束符
{
if ( *Data == 0x5c ) //'\'
{
switch ( *++Data )
{
case 'r': //回车符
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //换行符
USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if ( *Data == '%')
{ //
switch ( *++Data )
{
case 's': //字符串
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
case 'd': //十进制
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
} /* end of else if */
else USART_SendData(USARTx, *Data++);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
}