我正在使用连接到Google Core的IoT控制灯,以树莓皮为中心,通过IoT核心向ESP32发送消息,在一天中指定的时间打开或关闭它们。
我现在想做的是消除树莓皮,让esp32管理当它需要打开或关闭他们,但我看不到找到一种方式设置警报或类似的警报触发在特定的时间。
输入的时间值以毫秒为单位,从协调时算起。
这样的事情是否存在,或者我如何在esp32上完成警报?
发布于 2019-06-04 19:25:07
我不知道您是在为ESP32使用ESP还是某种Arduino框架(我对此并不熟悉)。这是ESP以色列国防军的答复。如果您没有使用ESP-国防军,并且无法访问相关的头文件和库,那么其中的一些想法可能仍然是相关的。
激活SNTP
通过在https://github.com/espressif/esp-idf/tree/master/examples/protocols/sntp上遵循SNTP示例,确保控制器上的时钟被更新。
使用localtime()
如果您正在使用ESP,您将可以访问localtime_r()函数。传递这个(指向)‘自时代开始’的秒数(由time(NULL)返回),它将用一周、一天、一小时、一分钟和第二天填充一个struct tm。
一般程序是(错误处理).
#include <time.h>
// ...
struct tm now = {};
time_t tnow = time(NULL);
localtime_r(&tnow, &now);
// Compare current day, hour, minute, etc. against pre-defined alarms.注意:如果您喜欢使用UTC,可以使用gmtime_r()而不是localtime_r()。
您可以从主while()循环中周期性地调用它,如下所示。
报警结构
为您的警报信息定义结构。您可以根据需要的粒度级别进行以下调整。请注意,它包括一个callback成员-指定程序在触发警报时实际应该做什么。
typedef struct {
int week_day; // -1 for every day of week
int hour; // -1 for every hour
int minute; // -1 for every minute
void (*callback)(void);
void *callback_arg;
} alarm_t;定义警报和回调
定义警报、回调函数和参数数组。
static void trigger_relay(const void *arg) {
uint32_t num = *(uint32_t *)arg;
printf("Activating relay %u ...\n", num);
// Handle GPIO etc.
}
static uint32_t relay_1 = 0;
static uint32_t relay_2 = 1;
static alarm_t alarms[] = {
// Trigger relay 1 at 9:00 on Sunday
{0, 9, 0, trigger_relay, (void *)&relay_1},
// Relay 2 at 7:30 every day
{-1, 7, 30, trigger_relay, (void *)&relay_2},
};周期扫描
定义一个check_alarms()例程,它用当前时间加载一个struct tm结构,并将其与您定义的每个警报进行比较。如果当前时间与警报时间匹配,则调用回调。
static void check_alarms(void) {
time_t tnow = time(NULL);
struct tm now = {};
localtime_r(&tnow, &now);
ESP_LOGI(TAG, "Time: %u:%u:%u", now.tm_hour, now.tm_min, now.tm_sec);
size_t n_alarms = sizeof(alarms) / sizeof(alarms[0]);
for (int i = 0; i < n_alarms; i++) {
alarm_t *alrm = &alarms[i];
if (alrm->week_day != -1 && alrm->week_day != now.tm_wday) {
continue;
}
if (alrm->hour != -1 && alrm->hour != now.tm_hour) {
continue;
}
if (alrm->minute != -1 && alrm->minute != now.tm_min) {
continue;
}
alrm->callback(alrm->callback_arg);
}
}然后从主while()循环中调用它,频率取决于警报的粒度。由于上面定义的alarm_t粒度为1分钟,所以我将每隔一次调用check_alarms()。此示例适用于FreeRTOS,但可以根据需要进行调整。
while (1) {
TickType_t tick = xTaskGetTickCount();
if (tick - g_time_last_check > pdMS_TO_TICKS(60000)) {
g_time_last_check = tick;
check_alarms();
}
}效率
如果您有大量的警报和/或每一个警报应该在高频触发,上面的效率不是很高。在这种情况下,您可能会考虑根据等待时间对警报进行排序的算法,而不是每次迭代整个数组,而是使用一个一次性软件计时器来调用相关的回调。除非你有大量的计时器,否则这可能不值得麻烦。
备选方案
FreeRTOS和ESP-以色列国防军都包含软件定时器的APIs -但这些API不能(很容易)在一天中的特定时间被用于警报--这是您所要求的。另一方面--正如你可能已经知道的--芯片上的ESP32系统确实有内置的RTC,但我认为最好使用更高级别的接口,而不是直接与它通信。
发布于 2019-06-04 17:24:02
实时时钟是你要找的东西。我从未与ESP32合作过,但显然是它有一个,它是坏的。。但是,5%的错误可能对您来说足够好。如果这是一种选择,我会使用外部的。
https://stackoverflow.com/questions/56420174
复制相似问题