ESP32-S3实时时钟(RTC)的使用
ESP32-S3是一款高性能的Wi-Fi和蓝牙集成的系统级芯片(SoC),它包含一个实时时钟(RTC)模块,可以在系统的其他部分关闭时继续运行,以节省电能。下面是如何使用ESP32-S3的RTC模块的一些基本步骤。
RTC模块的基本功能
ESP32-S3的RTC模块具有以下主要功能:
- 时间和日期:RTC模块可以提供实时的时间和日期信息。
- 闹钟:可以设置RTC模块在特定的时间和日期发出信号。
- 定时器:RTC模块可以作为一个定时器,用于在特定的时间间隔后发出信号。
- 低功耗模式:当ESP32-S3的其他部分关闭时,RTC模块可以继续运行,以节省电能。
常用API
1.设置当前时间 settimeofday函数
settimeofday
函数用于设置系统时间。它的原型如下:
c
int settimeofday(const struct timeval *tv, const struct timezone *tz);
其中,tv
参数是一个指向timeval
结构体的指针,该结构体包含了要设置的时间(以自Epoch(1970-01-01 00:00:00 +0000 (UTC))以来的秒数和微秒数)。tz
参数在现代系统中通常被忽略,应设置为NULL。
如果函数执行成功,返回0;如果失败,返回-1,并设置errno以指示错误。
2.获取当前时间 localtime_r函数
localtime_r
函数用于将time_t
类型的时间(自Epoch以来的秒数)转换为本地时间表示的tm
结构体。它的原型如下:
c
struct tm *localtime_r(const time_t *timer, struct tm *buf);
其中,timer
参数是一个指向time_t
类型的指针,表示要转换的时间;buf
参数是一个指向tm
结构体的指针,用于存储转换后的时间。
localtime_r
函数是线程安全的,因为它使用用户提供的存储空间来存储结果,而不是使用静态存储空间。如果函数执行成功,返回指向结果的指针;如果失败,返回NULL。
3.设置时间环境变量
setenv
是一个用于设置环境变量的函数。它的原型如下:
c
int setenv(const char *name, const char *value, int overwrite);
其中,name
是要添加或修改的环境变量的名称,value
是环境变量的新值,overwrite
是一个标志,表示当环境变量name
已经存在时是否覆盖其值。
- 如果
overwrite
非零,那么无论环境变量name
是否存在,都将其值设置为value
。 - 如果
overwrite
为零,那么只有当环境变量name
不存在时,才将其值设置为value
。
setenv
函数返回0表示成功,返回-1表示失败。
例如,setenv("TZ", "CST-8", 1);
这行代码的作用是设置环境变量TZ
的值为CST-8
,表示中国标准时间,即UTC+8。这样,当你获取或设置RTC模块的时间时,它就会按照中国标准时间来进行。
关于 协调时间时 的概念
UTC(Coodinated Universal Time),又称协调世界时,世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。
UTC是现在全球通用的时间标准,全球各地都同意将各自的时间进行同步协调。UTC是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。
UTC基于国际原子时,并通过不规则的加入闰秒来抵消地球自转变慢的影响。闰秒在必要的时候会被插入到UTC中,以保证协调世界时(UTC)与世界时(UT1)相差不超过0.9秒。
如何设置RTC模块
写一个示例,设置当前时间然后获取当前时间 打在串口上
c
#include <time.h> // 引入时间库
void setup() {
// 初始化串口
Serial.begin(115200); // 设置串口波特率为115200
// 设置当前时间
struct tm timeinfo; // 定义一个tm结构体变量timeinfo
timeinfo.tm_year = 2024 - 1900; // 设置年份
timeinfo.tm_mon = 5 - 1; // 设置月份
timeinfo.tm_mday = 2; // 设置日期
timeinfo.tm_hour = 13; // 设置小时
timeinfo.tm_min = 45; // 设置分钟
timeinfo.tm_sec = 30; // 设置秒
setenv("TZ", "CST-8", 1); // 设置时区为中国标准时间
tzset(); // 使时区设置生效
const time_t now = mktime(&timeinfo); // 将tm结构体转换为time_t格式
struct timeval tv = { .tv_sec = now }; // 定义一个timeval结构体变量tv,并设置其秒数
settimeofday(&tv, NULL); // 设置系统时间
// 获取并打印当前时间
time_t now_get; // 定义一个time_t变量now_get
struct tm timeinfo_get; // 定义一个tm结构体变量timeinfo_get
time(&now_get); // 获取当前时间
localtime_r(&now_get, &timeinfo_get); // 将time_t格式的时间转换为tm结构体格式
Serial.print("Current time: "); // 打印字符串"Current time: "
Serial.print(timeinfo_get.tm_hour); // 打印小时
Serial.print(":"); // 打印冒号
Serial.print(timeinfo_get.tm_min); // 打印分钟
Serial.print(":"); // 打印冒号
Serial.println(timeinfo_get.tm_sec); // 打印秒数并换行
}
void loop() {
// 延时1秒
delay(1000); // 暂停1秒
}
这个示例首先在setup()
函数中设置了当前时间为2024年5月2日13:45:30,然后立即获取并打印当前时间。这样,你就可以在串口监视器上看到设置的当前时间了。
🚨注意setenv("TZ", "CST-8", 1);
这行代码的作用是设置时区为中国标准时间。,setenv
函数用于设置环境变量。这里,设置了TZ
环境变量的值为CST-8
,表示中国标准时间,即UTC+8。这样,当你获取或设置RTC模块的时间时,它就会按照中国标准时间来进行。如果你想设置为其他时区,只需将CST-8
替换为相应的时区即可。例如,如果你想设置为美国东部标准时间,可以将CST-8
替换为EST5EDT
。
🚨注意在C语言的tm
结构体中,tm_year
字段表示的是自1900年以来的年数,tm_mon
字段表示的是月份,但是它的范围是0(一月)到11(十二月)。所以,当我们设置tm_year
和tm_mon
字段的值时,需要进行相应的调整:
-
对于年份,我们需要从实际年份中减去1900。例如,我们想要设置年份为2024,那么
tm_year
应该设置为2024 - 1900
。 -
对于月份,我们需要从实际月份中减去1。例如,如果我们想要设置月份为5月,那么
tm_mon
应该设置为5 - 1
。
这样,2024 - 1900
和5 - 1
就分别表示了年份2024和5月。
总结
参考资料
微软copilot