网络时间的获取是通过向第三方服务器发送GET请求获取并解析出来的。
在本篇博客中,网络时间的获取是一种自动的行为,当系统成功连接WiFi获取到网络天气后,系统将自动获取并解析得到时间和日期,为了减少误差每两分钟左右进行一次校准。在网络时间成功获取后,定时器中时间计数从这个数开始,并且到达一定数目,系统自动更新上下午和日期信息。
时间日期显示设计如图所示:
访问网络服务器校准网络时钟,需要了解服务器返回给我们的json字符串格式。可以用CJSON库进行解析,但是这里我采用手动解析。
{
"success": "1",
"result": {
"timestamp": "1718090343",
"datetime_1": "2024-06-11 15:19:03",
"datetime_2": "2024年06月11日 15时19分03秒",
"week_1": "2",
"week_2": "星期二",
"week_3": "周二",
"week_4": "Tuesday"
}
}
对应的接收代码
if(comGetChar(COM3,&getChar))
{
switch(state)
{
case 0:
if(getChar == '{'){ state=1;}
Recv_len=0;
break;
case 1:
if(getChar == '}')
{
state=0;
Recv_CommandFlag=TIMERECV;
}
else
{
*(Recv_Buf+Recv_len) = getChar;
Recv_len++;
printf("%c",getChar);
if(Recv_len>=210)
{
Recv_CommandFlag=UNRECV;
state=0;
}
}
break;
default:
break;
}
}
解析调用
Recv_CommandFlag = 0;
ret = timeParse(Recv_Buf);
if(ret == 0)
{
Times_Change(myday,mymonth,myyear); //计算当前日期
Display_days(myyear, mymonth, myday); //显示日期
GetTimes(myhour,myminute,mysecond);Display_time(TIMES);
}else{
printf("\r\ntimeParse fail\r\n");
}
NetStatus=ESP_TLINK_INIT;//回去弄tlink看看是不是有网
mytime.c
#include "mytime.h"
#include "esp8266.h"
volatile uint32_t TIMES = 0;
void GetTimes(char h,char m, char s )
{
TIMES=h*60*60+m*60+s;
return;
}
void Times_Change(unsigned char d, unsigned char m, int y)
{
if(m == 2) //如果是2月
{
if(d == 29)
{
if(!((((y%4) == 0) && ((y%100) != 0)) || ((y % 400) == 0))) //如果不是闰年
{
m ++;
d = 1;
}
}
else if(d == 30)
{
if((((y%4) == 0) && ((y%100) != 0)) || ((y % 400) == 0)) //如果是闰年
{
m ++;
d = 1;
}
}
}
else if(d == 31)
{
if(m == 4 | m == 6 | m == 9 | m == 11)
{
m ++;
d = 1;
}
}
else if(d > 31)
{
if(m == 12)
{
y ++;
m = 1;
d = 1;
}
else
{
m ++;
d = 1;
}
}
}
/*-------------------------------------------------------------
*计算时间函数
*起始页地址 宏定义 TIME_START_PAGE
*起始列地址 宏定义 TIME_START_COL
*时间 times 为0~86399,即24小时最大秒数
*分别计算出时 分 秒 上 下午 并显示在相应位置
*-------------------------------------------------------------*/
void Display_time(unsigned int times)
{
char timeStr_lvgldisp[30];
unsigned int temp_time = times;
unsigned char temp_hour, temp_minutues, temp_seconds;
unsigned char t_h_ten, t_h_one, t_m_ten, t_m_one, t_s_ten, t_s_one;
char timewhen;
temp_hour = times / 3600; //得到小时数
temp_minutues =(times % 3600) / 60; //得到分钟数
temp_seconds = (times % 3600) % 60; //得到秒数
myhour=temp_hour;
myminute=temp_minutues;
mysecond=temp_seconds;
t_h_ten = temp_hour / 10; //取小时十位数
t_h_one = temp_hour % 10; //取小时个位数
t_m_ten = temp_minutues /10; //取分钟十位数
t_m_one = temp_minutues %10; //取分钟个位数
t_s_ten = temp_seconds /10; //取秒十位数
t_s_one = temp_seconds %10; //取秒个位数
if(temp_time < 43200) //上午
{
timewhen='A';
}
else //下午
{
timewhen='P';
}
sprintf((char *)timeStr_lvgldisp, "%d%d:%d%d:%d%d-%cM",t_h_ten,t_h_one,t_m_ten,t_m_one,t_s_ten,t_s_one,timewhen);
printf("\r\ntimeStr:%s\n\r",(char *)timeStr_lvgldisp);
}
/*-------------------------------------------------------------
*计算日期和星期函数
*日期起始页地址 宏定义 DAYS_START_PAGE
*日期起始列地址 宏定义 DAYS_START_COL
*星期起始页地址 宏定义 WEEK_START_PAGE
*星期起始列地址 宏定义 WEEK_START_COL
*日期 days 为0~86399,即24小时最大秒数
*计算出星期 和日期 并显示在相应位置
*
* 吉姆拉尔森公式:w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)mod7
*w:week, y = year , m = moon, d = day , 1月=13月,2月=14月
*w = 0,星期一 ~ w = 6,星期日
*-------------------------------------------------------------*/
void Display_days(int year, unsigned char moon, unsigned char day)
{
char dateStr[20];
int temp_year, temp_moon, temp_day, temp_week;
unsigned char t_y_frist, t_y_second, t_y_thrid, t_y_forth;
unsigned char t_m_ten, t_m_one, t_d_ten, t_d_one;
int y, m, d;
temp_year = year;
temp_moon = moon;
temp_day = day;
t_y_frist = temp_year / 1000;
t_y_second = (temp_year % 1000) / 100;
t_y_thrid = (temp_year % 100) / 10;
t_y_forth = temp_year % 10;
t_m_ten = temp_moon / 10;
t_m_one = temp_moon % 10;
t_d_ten = temp_day / 10;
t_d_one = temp_day % 10;
y = year;
m = moon;
d = day;
if((m == 1) || (m == 2))
{
m += 12;
y --;
}
temp_week = ((d +2*m + 3*(m + 1) / 5 + y +y/4 - y /100 +y/400)%7)+1; //计算星期几
myweek = temp_week; //汉字一为第1个字符,方便计算
sprintf((char *)dateStr, "%d%d%d%d-%d%d-%d%d:%d",t_y_frist,t_y_second,t_y_thrid,t_y_forth,t_m_ten,t_m_one,t_d_ten,t_d_one,temp_week);
printf("dateStr:%s\n\r",(char *)dateStr);
}
mytime.h
#ifndef __MYTIME__
#define __MYTIME__
#include "stdint.h"
extern volatile uint32_t TIMES;
//extern char timeStr_lvgldisp[30];
void Times_Change(unsigned char d, unsigned char m, int y);
void Display_time(unsigned int times);
void Display_days(int year, unsigned char moon, unsigned char day);
void GetTimes(char h,char m, char s );
#endif
发起请求
ESP_Fefresh_NET_Massage(wifi_ssid,wifi_password,time_address,time_point,GetNet_Time);
key str的链接,删掉“GET”后复制粘贴浏览器应该是可以看到json字符串的,看不到就说明你模块怎么访问都不会获得的,建议自己先访问看一下
//time
char time_keystr[150]="GET http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json&HTTP/1.1\r\n";
char time_address[25]="api.k780.com";
char time_point[5]="88";
//日期时间变量
int myyear=2024;
int mymonth=6;
int myweek=3;
int myday=12;
int myhour=21;
int myminute=31;
int mysecond=56;
char subdatetime_1[20];
//char subdatetime_2[8];
u8 timeParse(char * timestr)
{
char *datetime1_start = strstr(timestr,"datetime_1");
if (datetime1_start != NULL)
{
datetime1_start += (strlen("datetime_1")+3);
strncpy(subdatetime_1, datetime1_start, 19);
subdatetime_1[19] = '\0';
printf("datetime_1: %s\r\n", subdatetime_1);
sscanf(subdatetime_1, "%d-%d-%d %d:%d:%d", &myyear, &mymonth, &myday, &myhour, &myminute, &mysecond);
GetTimes(myhour,myminute,mysecond);
return 0;
} else {
printf("\r\nKey not found\r\n");
return 1;
}
}
/*-------------------------------------------------
* 更新网络时间函数
* 已经连接WIFI,定期连接TCP更新网络时间
-------------------------------------------------*/
u8 ESP_Fefresh_NET_Massage(char *ssid,char *pwd,const char *tcp_addr, char *point, void (*function)())
{
char tcp_information[160]={0};
char wifi_information[56]={0}; //WiFi热点临时数组
u8 return_temp = 0;
comSendBuf(COM3, (uint8_t *)"+++", 3);
vTaskDelay(3000);
ESP12_SendAT("AT");
if (ESP12_WaitResponse("OK", 5000) != 1)
{
printf("\r\n AT fail!\r\n");
failnum|=(1<<0);
//vTaskDelay(1000);
}
ESP12_SendAT("ATE0");
if (ESP12_WaitResponse("OK", 5000) != 1)
{
printf("\r\n ATE0 fail\r\n");
failnum|=(1<<1);vTaskDelay(1000);
}
ESP12_SendAT("AT+CWMODE=1");
if (ESP12_WaitResponse("OK", 5000) != 1)
{
printf("\r\n CWMODE fail\r\n");
failnum|=(1<<2);vTaskDelay(2000);
}
sprintf(wifi_information, "AT+CWJAP=\"%s\",\"%s\"", ssid, pwd); //将WiFi热点名称和密码
ESP12_SendAT(wifi_information);
if (ESP12_WaitResponse("OK", 5000) != 1)
{
printf("\r\n CWJAP fail\r\n");
failnum|=(1<<3);
//vTaskDelay(1000);
}
sprintf(tcp_information, "AT+CIPSTART=\"TCP\",\"%s\",%s", tcp_addr, point); //将TCP,地址和端口号传给临时变量
// printf("%s\n",tcp_information);
ESP12_SendAT(tcp_information);
if (ESP12_WaitResponse("OK", 5000) != 1)
{
printf("\r\n CIPSTART fail\r\n");
failnum|=(1<<4);//vTaskDelay(1000);
}
ESP12_SendAT("AT+CIPMODE=1");
if (ESP12_WaitResponse("OK", 3000) != 1)
{
printf("\r\n CIPMODE fail\r\n");
failnum|=(1<<5);//vTaskDelay(1000);
}
ESP12_SendAT("AT+CIPSEND");
if (ESP12_WaitResponse("OK", 1000) != 1)
{
printf("\r\n CIPMODE fail\r\n");//vTaskDelay(1000);
failnum|=(1<<6);
}
// Send KeyStr
function();
return 0;
}
注意两个gettime不一样,一个是更新时间,一个是发起GET请求
“>”是访问成功的标志
可以参考这位博主的博客:
ESP8266获取网络时间 实时时钟-CSDN博客
//获取网络时间并解析给系统
void GetNet_Time(void)
{
if (failnum!=0)
{
failnum=0;
WIFI_LOGO=HIDE;
vTaskDelay(1000);
//NetStatus=ESP_TLINK_INIT;//回去弄tlink看看是不是有网
}else{
uart2SendStr(time_keystr); //发送GET请求
if(ESP12_WaitResponse(">", 10000) == 1){
printf("\r\n time server connected!\r\n");
NetStatus=ESP_TIME_CONNECTED;
WIFI_LOGO=SHOW;failnum=0;
}
}
}