esp8266 基于sntp協定更新系統時間
我們esp8266裝置,如何然他具有準确的系統時間呢?那就要依賴于sntp協定,一般晶片都內建了sntp協定,我們隻需要使用就可以了。
1.建立一個sntp任務
sntp_example_task更新網絡時間到本地
void app_main(void)
{
//modify cdb 2019-12-19
// printf("SDK version:%s\n", esp_get_idf_version());
// Initialize NVS
esp_err_t ret = nvs_flash_init();
char sys_time[64] = {0};
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
//初始化wifi,并且聯網
initialise_wifi();
//建立mqtt 處理線程
ret = xTaskCreate((void*)mqtt_client_thread,
MQTT_CLIENT_THREAD_NAME,
MQTT_CLIENT_THREAD_STACK_WORDS,
NULL,
MQTT_CLIENT_THREAD_PRIO,
NULL);
if (ret != pdPASS) {
DBG_C("mqtt create client thread %s failed\n", MQTT_CLIENT_THREAD_NAME);
}
//建立gpio led key處理任務
ret = xTaskCreate((void*)gpio_task,
GPIO_THREAD_NAME,
GPIO_THREAD_STACK_WORDS,
NULL,
GPIO_THREAD_PRIO,
NULL);
if (ret != pdPASS) {
DBG_C("qpio thread %s failed\n", GPIO_THREAD_NAME);
}
//建立sntp處理線程
ret = xTaskCreate((void*)sntp_example_task,
SNTP_THREAD_NAME,
SNTP_THREAD_STACK_WORDS,
NULL,
SNTP_THREAD_PRIO,
NULL);
if (ret != pdPASS) {
DBG_C("sntp thread %s failed\n", SNTP_THREAD_NAME);
}
//程式将進入死循環,防止退出,并且列印運作時間log,機關s,也開啟rtos任務排程
while(1)
{ //調用擷取系統時間接口,并且列印
memset(sys_time,0,64);
get_system(sys_time);
DBG_C("the system is runing,runtime:%s\n",sys_time);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
這裡注意下,我前面建立任務的函數第一個參數,函數名取位址指派,發現編譯由警告,其實函數名就是此函數的位址。
在component中添加user_sntp.c user_sntp.h
2.附上user_sntp.c
/* LwIP SNTP example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/apps/sntp.h"
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
/* FreeRTOS event group to signal when we are connected & ready to make a request */
extern EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
extern int CONNECTED_BIT;
#define DBG_C(...) printf("[%s,%d]",__FUNCTION__,__LINE__);printf(__VA_ARGS__)
static void initialize_sntp(void)
{
DBG_C("Initializing SNTP\n");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
}
static void obtain_time(void)
{
DBG_C("Waiting for network connected\n");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 10;
while (timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count) {
DBG_C("Waiting for system time to be set... (%d/%d)\n", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
}
void get_system(char * nowtime)
{
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
sprintf(nowtime,"%02d-%02d-%02d %02d:%02d",timeinfo.tm_year+1900,timeinfo.tm_mon+1,timeinfo.tm_mday,timeinfo.tm_hour,timeinfo.tm_min);
}
void sntp_example_task(void *arg)
{
time_t now;
struct tm timeinfo;
char strftime_buf[64];
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if (timeinfo.tm_year < (2016 - 1900)) {
DBG_C("Time is not set yet. Connecting to WiFi and getting time over NTP.\n");
obtain_time();
}
// Set timezone to Eastern Standard Time and print local time
// setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
// tzset();
// Set timezone to China Standard Time
setenv("TZ", "CST-8", 1);
tzset();
while (1) {
// update 'now' variable with current time
time(&now);
localtime_r(&now, &timeinfo);
if (timeinfo.tm_year < (2016 - 1900)) {
DBG_C("The current date/time error\n");
} else {
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
// DBG_C("The current date/time in Shanghai is: %s\n", strftime_buf);
}
// DBG_C("Free heap size: %d\n", esp_get_free_heap_size());
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
3.附上user_sntp.h
#ifndef _ESP8266_MY_SNTP_H_
#define _ESP8266_MY_SNTP_H_
void sntp_example_task(void *arg);
//擷取系統時間的函數
void get_system(char *nowtime);
#endif
3.修改component.mk
#
# Component Makefile
#
COMPONENT_SRCDIRS := mqtt gpio sntp
COMPONENT_ADD_INCLUDEDIRS += mqtt/include
COMPONENT_ADD_INCLUDEDIRS += gpio/include
COMPONENT_ADD_INCLUDEDIRS += sntp/include
4.編譯
make clean
make
5.燒錄運作
至此,開發闆就存在可用的api擷取準确的系統時間了,哪裡需要,就在哪調用即可。