搜索
bottom↓
回复: 0
打印 上一主题 下一主题

《DNESP32S3使用指南-IDF版_V1.6》第二十三章 RTC实验

[复制链接]

出0入234汤圆

跳转到指定楼层
1

1)实验平台:正点原子ESP32S3开发板
2)购买链接:https://detail.tmall.com/item.htm?id=768499342659
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-347618-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学ESP32S3快速入门视频教程:https://www.bilibili.com/video/BV1sH4y1W7Tc
6)正点原子FPGA交流群:132780729



第二十三章 RTC实验


       本章介绍ESP32-S3实时时钟(RTC)的使用,实时时钟能为系统提供一个准确的时间,即时系统复位或主电源断电,RTC依然能够运行,因此RTC也经常用于各种低功耗场景。通过本章的学习,读者将学习到RTC的使用。
本章分为如下几个小节:
       23.1 RTC时钟简介
       23.2 硬件设计
       23.3 程序设计
       23.4 下载验证

       23.1 RTC时钟简介
       RTC(实时时钟)是指安装在电子设备或实现其功能的IC(集成电路)上的时钟。当您在数字电路中称其为“时钟”时,您可能会想到周期信号,但在英语中,clock也意味着“时钟”。
       那为什么我们需要一个单独的RTC?
       原因是CPU的定时器时钟功能只在“启动”即“通电时”运行,断电时停止。当然,如果时钟不能连续跟踪时间,则必须手动设置时间。
       通常,RTC配备一个单独分离的电源,如纽扣电池(备用电池),即使开发板电源关闭,它也能保持运作,随时可以实时显示时间。然后,当开发板再次打开时,计算机内置的定时器时钟从RTC读取当前时间,并在此基础上供电的同时,时间在其自身机制下显示。顺便说一句,由于纽扣电池相对便宜且使用寿命长,因此RTC可以以极低的成本运行。基于此这个作用,它也可以用作内存。

       1,ESP32-S3的RTC
       在ESP32-S3中,并没有像STM32芯片一样,具有RTC外设,但是存在一个系统时间,利用系统时间,也可以实现实时时钟的功能效果。
       ESP32-S3使用两种硬件时钟源建立和保持系统时间。根据应用目的及对系统时间的精度要求,既可以仅使用其中一种时钟源,也可以同时使用两种时钟源。这两种硬件时钟源为RTC定时器和高分辨率定时器。默认情况下,是使用这两种定时器。下面我们将逐一介绍。

       23.2 硬件设计

       23.2.1 例程功能

       1. 通过LCD实时显示RTC时间

       2. LED闪烁,指示程序正在运行

       23.2.2 硬件资源
       1. LED
              LED0 - IO1

       2. XL9555
              IIC_SDA-IO41
              IIC_SCL-IO42

       3. SPILCD
              CS-IO21
              SCK-IO12
              SDA-IO11
              DC-IO40(在P5端口,使用跳线帽将IO_SET和LCD_DC相连)
              PWR- IO1_3(XL9555)
              RST- IO1_2(XL9555)

       4. RTC

       23.2.3 原理图
       本章实验使用的RTC为ESP32-S3的片上资源,因此没有相应的连接原理图。

       23.3 程序设计

       23.3.1 程序流程图
       程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图:

图23.3.1.1 RTC实验程序流程图

       23.3.2 RTC函数解析
       由于ESP32并未给出RTC相关的API函数,因而笔者在设计例程时调用了C库中的一些函数来配置RTC时钟,这些函数的描述及其作用如下:

       1,获取当前时间
       该函数用于获取当前时间,其函数原型如下所示:
  1. struct tm *localtime(const time_t *timer);
复制代码
       该函数的形参描述,如下表所示:

表23.3.2.1 函数localtime ()形参描述

       返回值:无。

       2,设置当前时间
       该函数用于设置当前时间,其函数原型如下所示:
  1. int settimeofday(const struct timeval *tv, const struct timezone *tz);
复制代码
       该函数的形参描述,如下表所示:

表23.3.2.2 函数settimeofday ()形参描述

       返回值:无。

       23.3.3 RTC驱动解析
       在IDF版的13_rtc例程中,作者在13_rtc \components\BSP路径下新增了一个RTC文件夹,分别用于存放esp_rtc.c、esp_rtc.h两个文件。其中,esp_rtc.h文件负责声明RTC,而esp_rtc.c文件则实现了RTC的驱动代码。下面,我们将详细解析这两个文件的实现内容。

       1,esp_rtc.h文件
  1. /* 时间结构体, 包括年月日周时分秒等信息 */
  2. typedef struct
  3. {
  4.     uint8_t hour;       /* 时 */
  5.     uint8_t min;        /* 分 */
  6.     uint8_t sec;        /* 秒 */
  7.     /* 公历年月日周 */
  8.     uint16_t year;      /* 年 */
  9.     uint8_t  month;     /* 月 */
  10.     uint8_t  date;      /* 日 */
  11.     uint8_t  week;      /* 周 */
  12. } _calendar_obj;

  13. extern _calendar_obj calendar;      /* 时间结构体 */
复制代码

       2,esp_rtc.c文件
  1. calendar_obj calendar;         /* 时间结构体 */

  2. /**
  3. * @brief       RTC设置时间
  4. * @param       year    :年
  5. * @param       mon     :月
  6. * @param       mday    :日
  7. * @param       hour    :时
  8. * @param       min     :分
  9. * @param       sec     :秒
  10. * @retval      无
  11. */
  12. void rtc_set_time(int year,int mon,int mday,int hour,int min,int sec)
  13. {
  14.     struct tm datetime;
  15.     /* 设置时间 */
  16.     datetime.tm_year = year - 1900;
  17.     datetime.tm_mon = mon - 1;
  18.     datetime.tm_mday = mday;
  19.     datetime.tm_hour = hour;
  20.     datetime.tm_min = min;
  21.     datetime.tm_sec = sec;
  22.     datetime.tm_isdst = -1;
  23.     /* 获取1970.1.1以来的总秒数 */
  24.     time_t second = mktime(&datetime);
  25.     struct timeval val = { .tv_sec = second, .tv_usec = 0 };
  26.     /* 设置当前时间 */
  27.     settimeofday(&val, NULL);
  28. }

  29. /**
  30. * @brief       获取当前的时间
  31. * @param       无
  32. * @retval      无
  33. */
  34. void rtc_get_time(void)
  35. {
  36.     struct tm *datetime;
  37.     time_t second;
  38.     /* 返回自(1970.1.1 00:00:00 UTC)经过的时间(秒) */
  39.     time(&second);
  40.     datetime = localtime(&second);

  41.     calendar.hour = datetime->tm_hour;                  /* 时 */
  42.     calendar.min = datetime->tm_min;                    /* 分 */
  43.     calendar.sec = datetime->tm_sec;                    /* 秒 */
  44.     /* 公历年月日周 */
  45.     calendar.year = datetime->tm_year + 1900;                /* 年 */
  46.     calendar.month = datetime->tm_mon + 1;              /* 月 */
  47.     calendar.date = datetime->tm_mday;                  /* 日 */
  48.     /* 周 */
  49.     calendar.week = rtc_get_week(calendar.year, calendar.month, calendar.date);
  50. }

  51. /**
  52. * @brief      将年月日时分秒转换成秒钟数
  53. * @note       输入公历日期得到星期(起始时间为: 公元0年3月1日开始, 输入往后的任何日期,都                           可以获取正确的星期)
  54. *             使用 基姆拉尔森计算公式 计算, 原理说明见此贴:
  55. *              <a href="https://www.cnblogs.com/fengbohello/p/3264300.html" target="_blank">https://www.cnblogs.com/fengbohello/p/3264300.html</a>
  56. * @param       syear : 年份
  57. * @param       smon  : 月份
  58. * @param       sday  : 日期
  59. * @retval      0, 星期天; 1 ~ 6: 星期一 ~ 星期六
  60. */
  61. uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t day)
  62. {
  63.     uint8_t week = 0;

  64.     if (month < 3)
  65.     {
  66.         month += 12;
  67.         --year;
  68.     }
  69. week = (day + 1 + 2 * month + 3 * (month + 1) /
  70. 5 + year + (year >> 2) - year /
  71. 100 + year / 400) % 7;
  72.     return week;
  73. }
复制代码
       以上三个获取、设置RTC时间、日期的函数,均是对ESP IDF中RTC驱动的简单封装。

       23.3.4 CMakeLists.txt文件
       打开本实验BSP下的CMakeLists.txt文件,其内容如下所示:
  1. set(src_dirs
  2.             IIC
  3.             LCD
  4.             LED
  5.             SPI
  6.             RTC
  7.             XL9555)

  8. set(include_dirs
  9.             IIC
  10.             LCD
  11.             LED
  12.             SPI
  13.             RTC
  14.             XL9555)

  15. set(requires
  16.             driver
  17.             newlib)

  18. idf_component_register(SRC_DIRS ${src_dirs}
  19. INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

  20. component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
复制代码
       上述的红色RTC驱动以及newlib依赖库需要由开发者自行添加,以确保RTC驱动能够顺利集成到构建系统中。这一步骤是必不可少的,它确保了RTC驱动的正确性和可用性,为后续的开发工作提供了坚实的基础。

       23.3.5 实验应用代码
       打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。
  1. i2c_obj_t i2c0_master;

  2. /* 定义字符数组用于显示周 */
  3. char* weekdays[]={"Sunday","Monday","Tuesday","Wednesday",
  4.                       "Thursday","Friday","Saterday"};

  5. /**
  6. * @brief       程序入口
  7. * @param       无
  8. * @retval      无
  9. */
  10. void app_main(void)
  11. {
  12.     esp_err_t ret;
  13.     uint8_t tbuf[40];
  14.     uint8_t t = 0;
  15.    

  16.     ret = nvs_flash_init();                     /* 初始化NVS */

  17. if (ret == ESP_ERR_NVS_NO_FREE_PAGES
  18. || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
  19.     {
  20.         ESP_ERROR_CHECK(nvs_flash_erase());
  21.         ret = nvs_flash_init();
  22.     }

  23.     led_init();                                 /* 初始化LED */
  24.     i2c0_master = iic_init(I2C_NUM_0);          /* 初始化IIC0 */
  25.     spi2_init();                                /* 初始化SPI2 */
  26.     xl9555_init(i2c0_master);                   /* IO扩展芯片初始化 */
  27.     lcd_init();                                 /* 初始化LCD */
  28.     rtc_set_time(2023,8,26,00,00,00);           /* 设置RTC时间 */

  29.     lcd_show_string(10, 40, 240, 32, 32, "ESP32",RED);
  30.     lcd_show_string(10, 80, 240, 24, 24, "RTC Test",RED);
  31.     lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK",RED);

  32.     while (1)
  33.     {
  34.         t++;

  35.         if ((t % 10) == 0)                      /* 每100ms更新一次显示数据 */
  36.         {
  37.             rtc_get_time();
  38.             sprintf((char *)tbuf, "Time:%02d:%02d:%02d",
  39.                                   calendar.hour, calendar.min, calendar.sec);
  40.             printf("Time:%02d:%02d:%02d\r\n", calendar.hour,
  41.                                   calendar.min, calendar.sec);
  42.             lcd_show_string(10, 130, 210, 16, 16, (char *)tbuf,BLUE);
  43.             sprintf((char *)tbuf, "Date:%04d-%02d-%02d",
  44.                                   calendar.year, calendar.month, calendar.date);
  45.             printf("Date:%02d-%02d-%02d\r\n",  calendar.year,  
  46.                                   calendar.month,  calendar.date);
  47.             lcd_show_string(10, 150, 210, 16, 16, (char *)tbuf,BLUE);
  48.             sprintf((char *)tbuf, "Week:%s", weekdays[calendar.week]);
  49.             lcd_show_string(10, 170, 210, 16, 16, (char *)tbuf,BLUE);
  50.         }

  51.         if ((t % 20) == 0)
  52.         {
  53.             LED_TOGGLE();               /* 每200ms,翻转一次LED */
  54.         }

  55.         vTaskDelay(10);
  56.     }
  57. }
复制代码
       从上面的代码中可以看到,在初始化完RTC后便每间隔100毫秒获取一次RTC的时间和日期,并在LCD上进行显示。

       23.4 下载验证
       在完成编译和烧录操作后,可以看到LCD上实时地显示着RTC的时间,并且可以看到LED在RTC周期性唤醒的驱动下以0.5Hz的频率闪烁着。

图23.3.1 SPI LCD显示效果图

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-22 20:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表