单片机RTC实验
单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
主函数:
int main(void) { uint8_t hour, min, sec, ampm; uint8_t year, month, date, week; uint8_t tbuf[40]; uint8_t t = 0; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */ delay_init(168); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ usmart_dev.init(84); /* 初始化USMART */ led_init(); /* 初始化LED */ lcd_init(); /* 初始化LCD */ rtc_init(); /* 初始化RTC */ rtc_set_wakeup(RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 0); /* 配置WAKE UP中断, 1秒钟中断一次 */ lcd_show_string(30, 50, 200, 16, 16, "STM32", RED); lcd_show_string(30, 70, 200, 16, 16, "RTC TEST", RED); lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED); while (1) { t++; if ((t % 10) == 0) /* 每100ms更新一次显示数据 */ { rtc_get_time(&hour, &min, &sec, &m); sprintf((char *)tbuf, "Time:%02d:%02d:%02d", hour, min, sec); lcd_show_string(30, 130, 210, 16, 16, (char*)tbuf, RED); rtc_get_date(&year, &month, &date, &week); sprintf((char *)tbuf, "Date:20%02d-%02d-%02d", year, month, date); lcd_show_string(30, 150, 210, 16, 16, (char*)tbuf, RED); sprintf((char *)tbuf, "Week:%d", week); lcd_show_string(30, 170, 210, 16, 16, (char*)tbuf, RED); } if ((t % 20) == 0) { LED0_TOGGLE(); /* 每200ms,翻转一次LED0 */ } delay_ms(10); } }配置:
uint8_t rtc_init(void) { uint16_t bkpflag = 0; g_rtc_handle.Instance = RTC; g_rtc_handle.Init.HourFormat = RTC_HOURFORMAT_24; /* RTC设置为24小时格式 */ g_rtc_handle.Init.AsynchPrediv = 0x7F; /* RTC异步分频系数(1~0x7F) */ g_rtc_handle.Init.SynchPrediv = 0xFF; /* RTC同步分频系数(0~0x7FFF) */ g_rtc_handle.Init.OutPut = RTC_OUTPUT_DISABLE; g_rtc_handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; g_rtc_handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; /* 检查是不是第一次配置时钟 */ bkpflag = rtc_read_bkr(RTC_BKP_DR0); /* 读取BKP0的值 */ if (HAL_RTC_Init(&g_rtc_handle) != HAL_OK) { return 1; } if ((bkpflag != 0x5050) && (bkpflag != 0x5051)) /* 之前未初始化过, 重新配置 */ { rtc_set_time(23, 59, 56, RTC_HOURFORMAT12_AM); /* 设置时间, 根据实际时间修改 */ rtc_set_date(26, 5, 28, 17); /* 设置日期 */ } return 0; } void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc) { uint16_t retry = 200; RCC_OscInitTypeDef rcc_osc_init_handle; RCC_PeriphCLKInitTypeDef rcc_periphclk_init_handle; __HAL_RCC_RTC_ENABLE(); /* RTC使能 */ HAL_PWR_EnableBkUpAccess(); /* 取消备份区域写保护 */ __HAL_RCC_PWR_CLK_ENABLE(); /* 使能电源时钟PWR */ /* 使用寄存器的方式去检测LSE是否可以正常工作 */ RCC->BDCR |= 1 << 0; /* 尝试开启LSE */ while (retry && ((RCC->BDCR & 0x02) == 0)) /* 等待LSE准备好 */ { retry--; delay_ms(5); } if (retry == 0) /* LSE起振失败 使用LSI */ { rcc_osc_init_handle.OscillatorType = RCC_OSCILLATORTYPE_LSI; /* 选择要配置的振荡器 */ rcc_osc_init_handle.PLL.PLLState = RCC_PLL_NONE; /* PLL不配置 */ rcc_osc_init_handle.LSIState = RCC_LSI_ON; /* LSI状态:开启 */ HAL_RCC_OscConfig(&rcc_osc_init_handle); /* 配置设置的rcc_oscinitstruct */ rcc_periphclk_init_handle.PeriphClockSelection = RCC_PERIPHCLK_RTC; /* 选择要配置外设 RTC */ rcc_periphclk_init_handle.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; /* RTC时钟源选择LSI */ HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_handle); /* 配置设置的rcc_periphclkinitstruct */ rtc_write_bkr(0, 0x5051); } else { rcc_osc_init_handle.OscillatorType = RCC_OSCILLATORTYPE_LSE; /* 选择要配置的振荡器 */ rcc_osc_init_handle.PLL.PLLState = RCC_PLL_NONE; /* PLL不配置 */ rcc_osc_init_handle.LSEState = RCC_LSE_ON; /* LSE状态:开启 */ HAL_RCC_OscConfig(&rcc_osc_init_handle); /* 配置设置的rcc_oscinitstruct */ rcc_periphclk_init_handle.PeriphClockSelection = RCC_PERIPHCLK_RTC; /* 选择要配置外设RTC */ rcc_periphclk_init_handle.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; /* RTC时钟源选择LSE */ HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_handle); /* 配置设置的rcc_periphclkinitstruct */ rtc_write_bkr(0, 0x5050); } __HAL_RCC_RTC_ENABLE(); /* RTC使能 */ } void rtc_set_wakeup(uint8_t wksel, uint16_t cnt) { __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&g_rtc_handle, RTC_FLAG_WUTF); /* 清除RTC WAKE UP的标志 */ HAL_RTCEx_SetWakeUpTimer_IT(&g_rtc_handle, cnt, wksel); /* 设置重装载值和时钟 */ HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 2, 2); /* 抢占优先级2,子优先级2 */ HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); } void RTC_WKUP_IRQHandler(void) { HAL_RTCEx_WakeUpTimerIRQHandler(&g_rtc_handle); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) { LED1_TOGGLE(); } uint32_t rtc_read_bkr(uint32_t bkrx) { uint32_t temp = 0; temp = RTC_BASE + 0x50 + bkrx * 4; return (*(uint32_t *)temp); /* 返回读取到的值 */ } HAL_StatusTypeDef rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t ampm) { RTC_TimeTypeDef rtc_time_handle; rtc_time_handle.Hours = hour; rtc_time_handle.Minutes = min; rtc_time_handle.Seconds = sec; rtc_time_handle.TimeFormat = ampm; rtc_time_handle.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; rtc_time_handle.StoreOperation = RTC_STOREOPERATION_RESET; return HAL_RTC_SetTime(&g_rtc_handle, &rtc_time_handle, RTC_FORMAT_BIN); } HAL_StatusTypeDef rtc_set_date(uint8_t year, uint8_t month, uint8_t date, uint8_t week) { RTC_DateTypeDef rtc_date_handle; rtc_date_handle.Date = date; rtc_date_handle.Month = month; rtc_date_handle.WeekDay = week; rtc_date_handle.Year = year; return HAL_RTC_SetDate(&g_rtc_handle, &rtc_date_handle, RTC_FORMAT_BIN); }测试结果:1s产生一次wakeup中断
rtc_set_wakeup(RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 10); /* 配置WAKE UP中断, 10秒钟中断一次 */
还可以利用RTC的入侵检测功能,复用PC13或PI8,防止产品被认为破坏。
