网络时间的获取是通过向第三方服务器发送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 KeyStrfunction();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;}}
}