• STM32读写RTC内部时钟外设,设置和显示时钟


    今天学习了STM32单片机的内部时钟外设,学会了更改内部时钟和提取时钟数值的操作,只要后备电池有电,该时钟就会一直走,时间不会复位,哪怕没有给单片机供电。好了,直接记录步骤吧:

    首先初始化流程,和BKP一样,在使用RTC外设之前,同样得执行注意事项的的第一点:


    第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问

    如果读后备寄存器不是写入的值(证明包括电池断过电)需要重写时间
            第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时                                          钟。LSE 需要手动开启,不然用不了。
            第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)
            第四步:调用等待的函数(RTC模块里等待同步,等待上一次操作完成)
            第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)
            第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的                                话, 配置中断。

    否则是不需要重新写时间的:

            第四步:调用等待的函数(等待同步,等待上一次操作完成)

    写两个函数:
    一个是设置时间,
    一个是读取时间。

    设置时间的函数:

            声明存放时间戳的变量time_CNT

            创建时间结构体的变量time_data

            第一步:把我们数组指定的时间,填充到struct tm结构体里

                    向结构体赋值年份  减去偏移

                    向结构体赋值月份 减去偏移

                    向结构体赋值日份

                    向结构体赋值小时

                    向结构体赋值分钟

                    向结构体赋值秒钟

            第二步:把结构体中的时间转换成时间戳

                    把结构体中的时间转换成时间戳

            第三步:把时间戳写入到RTC中当做初始时间

                    把时间戳写入到RTC中当做初始时间

                    等待写入操作完成

    读取时间的函数:

            声明存放时间戳的变量time_CNT

            创建时间结构体的变量time_data

            第一步:读取时间戳放到时间戳变量中

            第二步:把时间戳转换成时间,存放到结构体中

            第三步:把结构体中的时间存放到我们指定的全局变量数组中。

                    取结构体赋值年份  +偏移

                    取结构体赋值月份 +偏移

                    取结构体赋值日份

                    取结构体赋值小时

                    取结构体赋值分钟

                    取结构体赋值秒钟

    好了,写的我都有点恶心了,还是直接看源文件吧:

    MyRTC.c:

    1. #include "stm32f10x.h" // Device header
    2. #include "MyRTC.h"
    3. #include
    4. uint16_t MyRTC_Time[] = {2024, 4, 24, 9, 33, 59}; //存储时间的数组
    5. /*
    6. 首先初始化流程,和BKP一样,在使用RTC外设之前,同样得执行注意事项的的第一点:
    7. 第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问
    8. 第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时钟。LSE需要手动开启,不然用不了。
    9. 第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)
    10. 第四步:调用等待的函数(RTC模块里等待同步,等待上一次操作完成)
    11. 第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)
    12. 第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的话,配置中断。
    13. */
    14. void MyRTC_Init(void)
    15. {
    16. //第一步:开启PWR和BKP的时钟,使能PWR和BKP的访问
    17. RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
    18. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    19. PWR_BackupAccessCmd(ENABLE);
    20. if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) //如果读后备寄存器不是写入的值(证明包括电池断过电)需要重写时间
    21. {
    22. //第二步:启动RTC的时钟,使用RCC模块里的RCC_LSEConfig函数,开启LSE的时钟。LSE需要手动开启,不然用不了。
    23. RCC_LSEConfig(RCC_LSE_ON);
    24. //等待LSE时钟启动完成
    25. while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);
    26. //第三步:配置RTCCLK数据选择器,指定LSE为RTCCLK(这个函数也在RCC模块里面)
    27. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    28. RCC_RTCCLKCmd(ENABLE); // 使能LSE的时钟
    29. //第四步:调用等待的函数(等待同步,等待上一次操作完成)
    30. RTC_WaitForSynchro();
    31. RTC_WaitForLastTask();
    32. //第五步:配置预分频器(RTC里给PRL重装寄存器一个分频值,确保输出频率是1Hz)
    33. RTC_SetPrescaler(32768 - 1); // 32768Hz除以32768正好等于1
    34. RTC_WaitForLastTask(); //等待写入操作完成
    35. //第六步:配置CNT的值(给RTC一个初始时间)需要闹钟的话,配置个闹钟;需要中断的话,配置中断。
    36. //下面两条在其他函数内执行,这里就不用执行了。
    37. // RTC_SetCounter(1672588795);
    38. // RTC_WaitForLastTask(); //等待写入操作完成
    39. MyRTC_SetTime(); //设置时间
    40. BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); //BKP1后备寄存器写入0xA5A5
    41. }
    42. else //否则是不需要重新写时间的
    43. {
    44. //第四步:调用等待的函数(等待同步,等待上一次操作完成)
    45. RTC_WaitForSynchro();
    46. RTC_WaitForLastTask();
    47. }
    48. }
    49. /*
    50. 写两个函数:
    51. 一个是设置时间,
    52. 一个是读取时间。
    53. */
    54. // 设置时间的函数
    55. void MyRTC_SetTime(void)
    56. {
    57. time_t time_CNT; //声明存放时间戳的变量time_CNT
    58. struct tm time_date; //创建时间结构体的变量time_data
    59. //第一步:把我们数组指定的时间,填充到struct tm结构体里
    60. time_date.tm_year = MyRTC_Time[0] - 1900; //向结构体赋值年份 减去偏移
    61. time_date.tm_mon = MyRTC_Time[1] - 1; //向结构体赋值月份 减去偏移
    62. time_date.tm_mday = MyRTC_Time[2]; //向结构体赋值日份
    63. time_date.tm_hour = MyRTC_Time[3]; //向结构体赋值小时
    64. time_date.tm_min = MyRTC_Time[4]; //向结构体赋值分钟
    65. time_date.tm_sec = MyRTC_Time[5]; //向结构体赋值秒钟
    66. //第二步:把结构体中的时间转换成时间戳
    67. time_CNT = mktime(&time_date); //把结构体中的时间转换成时间戳
    68. //第三步:把时间戳写入到RTC中当做初始时间
    69. RTC_SetCounter(time_CNT); //把时间戳写入到RTC中当做初始时间
    70. RTC_WaitForLastTask(); //等待写入操作完成
    71. }
    72. //读取时间的函数
    73. void MyRTC_ReadTime(void)
    74. {
    75. time_t time_CNT; //声明存放时间戳的变量time_CNT
    76. struct tm time_date; //创建时间结构体的变量time_data
    77. //第一步:读取时间戳放到时间戳变量中
    78. time_CNT = RTC_GetCounter();
    79. //第二步:把时间戳转换成时间,存放到结构体中
    80. time_date = *localtime(&time_CNT);
    81. //第三步:把结构体中的时间存放到我们指定的全局变量数组中。
    82. MyRTC_Time[0] = time_date.tm_year + 1900 ; //取结构体赋值年份 +偏移
    83. MyRTC_Time[1] = time_date.tm_mon + 1; //取结构体赋值月份 +偏移
    84. MyRTC_Time[2] = time_date.tm_mday; //取结构体赋值日份
    85. MyRTC_Time[3] = time_date.tm_hour; //取结构体赋值小时
    86. MyRTC_Time[4] = time_date.tm_min; //取结构体赋值分钟
    87. MyRTC_Time[5] = time_date.tm_sec; //取结构体赋值秒钟
    88. }

    MyRTC.h:

    1. #ifndef __MYRTC_H
    2. #define __MYRTC_H
    3. extern uint16_t MyRTC_Time[]; //存储时间的数组
    4. void MyRTC_Init(void);
    5. // 设置时间的函数
    6. void MyRTC_SetTime(void);
    7. //读取时间的函数
    8. void MyRTC_ReadTime(void);
    9. #endif

    主函数main.c:

    1. #include "stm32f10x.h" // Device header
    2. #include "OLED.h"
    3. #include "MyRTC.h"
    4. int main(void)
    5. {
    6. OLED_Init(); //oled 屏幕初始化
    7. MyRTC_Init(); //RTC初始化
    8. OLED_ShowString(1,1,"Data:xxxx-xx-xx"); //1行1列显示日期
    9. OLED_ShowString(2,1,"Time:xx:xx:xx"); //2行1列显示时间
    10. OLED_ShowString(3,1,"CNT:"); //3行1列显示:CNT
    11. OLED_ShowString(4,1,"DIV:"); //4行1列显示:DIV余数寄存器
    12. while(1)
    13. {
    14. MyRTC_ReadTime(); //读取时间
    15. OLED_ShowNum(1,6, MyRTC_Time[0],4); //1行6列显示:年份
    16. OLED_ShowNum(1,11, MyRTC_Time[1],2); //1行11列显示:月份
    17. OLED_ShowNum(1,14, MyRTC_Time[2],2); //1行14列显示:日子
    18. OLED_ShowNum(2,6, MyRTC_Time[3],2); //2行6列显示:小时
    19. OLED_ShowNum(2,9, MyRTC_Time[4],2); //2行9列显示:分钟
    20. OLED_ShowNum(2,12, MyRTC_Time[5],2); //2行12列显示:秒钟
    21. OLED_ShowNum(3,5, RTC_GetCounter(),10); //3行5列显示:CNT
    22. OLED_ShowNum(4,5, RTC_GetDivider(),10); //4行5列显示:DIV余数寄存器
    23. }
    24. }

    编译下载后,就能看到本次的实验结果了:

  • 相关阅读:
    python常用标准库(时间模块time和datetime)
    Cpp/Qt-day030919Qt
    期末复习重点总结(5-9章)-计算机操作系统(慕课版)
    基于 Kafka 的实时数仓在搜索的实践应用
    mybatis使用双层<foreach> 循环嵌套
    北京十大知名律师事务所最新排名(2022前十公布)
    异地远程访问内网BUG管理系统【Cpolar内网穿透】
    【学习】深度学习代码各个步骤都是为了啥(一)
    Thrift、Dubbo、Spring Cloud 和 gRPC
    阿里云短信服务设置操作项目
  • 原文地址:https://blog.csdn.net/xingyuncao520025/article/details/138148422