0

我使用带有 esp-idf 的 ESP32。我需要正确的时间,因此我正在尝试与 NTP 服务器重新同步时间。我使用这个例子。[1]:https ://github.com/espressif/esp-idf/tree/master/examples/protocols/sntp

当我再次调用 gain_time() 方法时,设备正在重新启动。

我错了什么?我没有找到任何有帮助的东西。

I (2259) initialise_wifi: Setting WiFi configuration SSID OpenWrt                                                                                                                                           
I (2359) syncTime: I'm runing :)                                                                                                                                        
I (2369) getTimeNow: Time is not set yet. Connecting to WiFi and getting time over NTP.                                                                                                    
I (2389) initialize_sntp: Initializing SNTP                                                                                                                                                
I (2389) obtain_time: Waiting for system time to be set... (1/10)                                                                                                                          
...                                                                                                                   
I (18389) obtain_time: Waiting for system time to be set... (9/10)  
-----The time is correct, but when i'm trying resync with NTP                                                                                                                        
I (20639) getTimeNow: Time is not set yet. Connecting to WiFi and getting time over NTP.                                                                                                   
I (20639) initialize_sntp: Initializing SNTP                                                                                                                                               
assertion "Operating mode must not be set while SNTP client is running" failed: file "/home/lenovov510/esp/esp-idf/components/lwip/lwip/src/apps/sntp/sntp.c", line 600, function: sntp_s
etoperatingmode                                                                                                                                                                            
abort() was called at PC 0x400d2c6b on core 1                                                                                                                                              

ELF file SHA256: 145d1f5e047670ed10c462ae090b3e64db1c5aa158a9988417a513b2ee801051                                                                                                          

Backtrace: 0x4008623c:0x3ffc7e00 0x40086489:0x3ffc7e20 0x400d2c6b:0x3ffc7e40 0x4011e251:0x3ffc7e70 0x400d28b4:0x3ffc7e90 0x400d28c7:0x3ffc7eb0 0x400d2aff:0x3ffc7f10 0x400d2bcd:0x3ffc7fa0 
0x4008b569:0x3ffc7fc0                                                                                                                                                                      

Rebooting...   

有我的方法:

This give back the timestamp.
void getDateTime(char *dateTime)
{
  char *TAG = "getDateTime";
  time_t now;
  struct tm timeinfo;
  time(&now);
  localtime_r(&now, &timeinfo);
  char strftime_buf[64];
  setenv("TZ", "GTM-2", 1);
  tzset();
  localtime_r(&now, &timeinfo);
  strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
  sprintf(dateTime, "20%d-%d-%d+%d:%d:%d", timeinfo.tm_year - 100, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}

This method trying to update time. 
void syncTime()
{
  char *TAG = "syncTime";
  obtain_time();

}

static void obtain_time(void)
{
  static const char *TAG = "obtain_time";
  initialize_sntp();
  time_t now = 0;
  struct tm timeinfo = {0};
  int retry = 0;
  const int retry_count = 10;
  while (retry!=retry_count)// timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count )
  {
    ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    time(&now);
    localtime_r(&now, &timeinfo);
  }
}
//----
static void initialize_sntp(void)
{
  static const char *TAG = "initialize_sntp";
  ESP_LOGI(TAG, "Initializing SNTP");
  sntp_setoperatingmode(SNTP_OPMODE_POLL);
  sntp_setservername(0, "pool.ntp.org");
  sntp_init();

...

//Update the timeInSec and Datettime variable
void updateTimeVariables(void *pvParameter)
{
  char *TAG = "updateTimeVariables";
  while (1 == 1)
  {
    getDateTime(dateTime);
    timeInSec = getTimeNow();
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }

  vTaskDelete(NULL);
}

//Sync NTP server.
void updateTime(void *pvParameter)
{
  char *TAG = "updateTime";
  while (1 == 1)
  {
    syncTime();
    vTaskDelay(10000 / portTICK_PERIOD_MS);//1800000 / portTICK_PERIOD_MS);
  }
  vTaskDelete(NULL);
}

...
 xTaskCreate(&updateTime, "updateTime", 4000, NULL, 6, NULL);
  xTaskCreate(&updateTimeVariables, "updateTimeVariables", 4000, NULL, 0, NULL);
4

4 回答 4

2

看起来您每次更新时间时都在尝试初始化 sntp。

注意获取时间函数的第二行:

static const char *TAG = "obtain_time";
initialize_sntp();                     //   <<<< THIS ONE.
time_t now = 0;
struct tm timeinfo = {0};
//.....

您必须以一种只调用一次initialize_sntp的方式更改代码。

于 2019-10-10T18:16:54.913 回答
0

要解决这个问题,你需要做几件事。1.) 修改sntp.c中users/[username]/.platformio/packages/framework-espidf/components/lwip/lwip/src/apps/sntp/sntp.c的文件和users/[username]/.platformio/packages/framework-espidf/components/lwip/lwip/include/lwip/apps/sntp.h文件,修改如下:

a.) 在 sntp.c 文件中 - 将“更改static void sntp_request(void *arg)为” void sntp_request(void *arg)以使该函数可用于其他模块。它位于源文件中的第 490 行附近。此外,在第 160 行,删除单词“static”以防止编译器错误.

b.) 在 sntp.h 头文件中,添加语句void sntp_request(void *)以使函数原型可用于您的代码。

下面是我的代码,经过修改以允许sntp_request()根据需要调用。我每隔 30 分钟左右给我的电话打一次电话,但你可以等待更长的时间,也许一天一个,就足以让时钟保持相当稳定。

bool sntp_1st_init = true;                      // 1st init call allowed
static void obtain_time(void)
{
    if(sntp_1st_init)                           // doing this again?
        {
        sntp_setoperatingmode(SNTP_OPMODE_POLL);
        sntp_setservername(0, "north-america.pool.ntp.org");
        ESP_LOGI(TAG, "Initializing SNTP");
        sntp_1st_init = false;                  // don't call again
        sntp_init();                            // init and set time
        }
    else
        {
        ESP_LOGI(TAG, "Syncing System Time");
        sntp_request(NULL);                     // sync time again
        }

    // wait for System time to be set by monitoring Date changes
    int retry = 0;
    const int retry_count = 15;

    while(timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count)
        {
        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)",
                retry, retry_count);
        vTaskDelay((1 * ONEsec) / portTICK_PERIOD_MS);
        time(&now);
        localtime_r(&now, &timeinfo);
        }
}

布尔“ sntp_1st_init”在程序启动时设置为真,在第一次 sntp 初始化发生后设置为假。对“”的调用sntp_setoperatingmode(SNTP_OPMODE_POLL)只能执行一次,所以必须放在sntp_1st_init代码段中。

我已经确认这些更改可以通过将系统时间更改为正确时间以外的时间并观察到时间按预期得到更正来起作用。

原作者通过使sntp_request()函数静态来限制 sntp 代码的功能,防止用户对计算机时钟时间进行额外的 sntp 更正。即使是最好的振荡器也会随着时间的推移而漂移,如果您要费心使用 sntp,您也可以允许时钟漂移校正。

希望这可以帮助。

杰瑞

JWM工程集团

于 2019-11-30T20:46:10.087 回答
0

幸运的是,该sntp_stop()功能不会删除以前的设置(包括服务器),因此您可以使用它:

sntp_stop();
sntp_init();

在第一次运行时,同步需要约 30 秒,随后运行约 500 毫秒。

我把它放在一个 FreeRTOS 任务中:

#include "esp_sntp.h"
#include "freertos/task.h"

void update(void* pvParameters) {
  while (true) {
    sntp_stop();
    sntp_init();
    vTaskDelay(pdMS_TO_TICKS(60 * 60 * 1000));
  }
}

void setup(void) {
  // Add your SNTP setup code here

  xTaskCreate(update, "NtpUpdate", 2048, NULL, tskIDLE_PRIORITY,
              &updateHandle);
}
于 2020-04-02T16:10:21.850 回答
0

通过问题4386SNTP 文档已更新为以下内容:

具有此初始化代码的应用程序将定期同步时间。时间同步周期由 CONFIG_LWIP_SNTP_UPDATE_DELAY 确定(默认值为一小时)。要修改变量,请在项目配置中设置 CONFIG_LWIP_SNTP_UPDATE_DELAY。

您只需要在您的应用程序中使用以下代码:

sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
于 2020-05-14T00:32:36.710 回答