STM32 RTC小结

 RTC可以用来设置实时时钟,并产生秒中断或闹钟中断。在芯片有电源供电的情况下,系统掉电后仍能保持时钟计时。

RTC设置需要涉及对电源(PWR)、备份区域(BKP)和RCC部分寄存器的改写。

RTC所需的晶振在RCC部分的寄存器中选择。在芯片时钟系统中对RTC的时钟提供如下图所示。RTC时钟可以从LSI, LSE和HSE分频中选择。这些需要对RCC寄存器的一些位进行设置。

RTC的预分频器、计数器和闹钟寄存器在备份区域中,以保证系统掉电后,在电池供电时仍能计数,如下图所示。在电源部分,系统复位后,将禁止向备份区域写入内容,因此,若要配置RTC,需要在电源部分允许对备份区域的写入。

备份区中有留给用户写入数据的空间。由于掉电后备份区中的内容仍保持,可以通过对用户写入数据的比较,知道备份区中的设置(尤其是RTC设置)是否存在。若不存在,需要清空备份区并重新写入;若存在,则只需再次写入备份区之外的RTC_CR。

由于用户是通过APB1接口读写RTC寄存器,在上电之后,需要先等待APB1接口与RTC同步完成,否则读取的RTC值可能有误;完成同步以RTC_CRL的RSF位置1为标志。对于写RTC寄存器,先查询RTC_CRL的RTOFF位,直到为1,说明上一次操作已经完成;再CNF置1,进入配置模式;写寄存器;CNF置0,退出配置模式;等待RTOFF位为1,说明本次写入已经完成。

下面贴一个可以跑通的简化流程,完成按秒计数的功能。 

 #include "stm32f10x.h" #include "stm32_eval.h" #include #include "stm3210c_eval_lcd.h" volatile uint32_t TimeDisplay = 0; int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f10x_xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f10x.c file */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); NVIC_Configuration(); STM3210C_LCD_Init(); LCD_Clear(LCD_COLOR_WHITE); LCD_SetTextColor(LCD_COLOR_BLUE); if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) { RTC_Configuration(); Time_Adjust(); BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); } else { RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); } RCC_ClearFlag(); Time_Show(); } void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 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); } void RTC_Configuration(void) { BKP_DeInit(); RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {} RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */ RTC_WaitForLastTask(); } uint32_t Time_Regulate(void) { uint32_t Tmp_HH = 0x00, Tmp_MM = 0x00, Tmp_SS = 0x00; return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS)); } void Time_Adjust(void) { RTC_WaitForLastTask(); RTC_SetCounter(0);//Time_Regulate()); RTC_WaitForLastTask(); } void Time_Display(uint32_t TimeVar) { uint32_t THH = 0, TMM = 0, TSS = 0; char buf[15]; /* Reset RTC Counter when Time is 23:59:59 */ if (TimeVar == 0x0001517F) { RTC_WaitForLastTask(); RTC_SetCounter(0x0); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); } /* Compute hours */ THH = TimeVar / 3600; /* Compute minutes */ TMM = (TimeVar % 3600) / 60; /* Compute seconds */ TSS = (TimeVar % 3600) % 60; sprintf(buf, "%0.2d:%0.2d:%0.2d/r", THH, TMM, TSS); LCD_DisplayStringLine(LCD_LINE_2, buf); //printf("Time: %0.2d:%0.2d:%0.2d/r", THH, TMM, TSS); } /** * @brief Shows the current time (HH:MM:SS) on the Hyperterminal. * @param None * @retval None */ void Time_Show(void) { // printf("/n/r"); /* Infinite loop */ while (1) { /* If 1s has been elapased */ if (TimeDisplay == 1) { uint32_t Counter = 0; Counter = RTC_GetCounter(); Time_Display(Counter); TimeDisplay = 0; } } } void RTC_IRQHandler(void) { if (RTC_GetITStatus(RTC_IT_SEC) != RESET) { RTC_WaitForLastTask(); /* Clear the RTC Second interrupt */ RTC_ClearITPendingBit(RTC_IT_SEC); /* Toggle LED1 */ // STM_EVAL_LEDToggle(LED1); /* Enable time update */ TimeDisplay = 1; /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); } }

你可能感兴趣的:(stm32)