单片机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, &ampm);
            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,防止产品被认为破坏。

相关推荐
踏着七彩祥云的小丑15 小时前
嵌入式测试学习第 21 天:常见硬件故障现象:不开机、死机、串口无输出
单片机·嵌入式硬件
chuwengeileyan11 天前
过零比较器 proteus
嵌入式硬件
foundbug9991 天前
51单片机 PT100 温度测量程序
单片机·嵌入式硬件·51单片机
星夜夏空991 天前
STM32单片机学习(21) —— I2C通信
stm32·单片机·学习
qq_333120971 天前
深入探讨8051单片机C351语言及编译器应用
单片机·嵌入式硬件·51单片机
做萤石二次开发的哈哈1 天前
ERTC-产品介绍-应用场景
音视频·实时音视频
十年编程老舅1 天前
读懂 MCU 启动:从上电到程序运行全链路
单片机·嵌入式硬件·mcu·嵌入式·cpu·嵌入式开发·ram
北京盟通科技官方账号1 天前
Windows如何实现硬实时?LxWin双系统隔离架构深度解析
stm32·嵌入式硬件·具身智能·ethercat·人形机器人·实时系统·windows实时扩展
国科安芯1 天前
低噪声LDO如何破解测试测量与医学成像的电源困局
网络·单片机·嵌入式硬件·安全性测试