为了读者容易读懂,该文章里面附的所以代码我都写在了user_main.c里面。
首先需要在user_init(void)函数里面加入下面的代码来配置ESP
8266为客户端模式,然后自动去连接路由器。
/********************************************************************************************************************
*
* 连配置为客户端station模式,自动去连接 WiFi 路由器 ( 注意! 注意! 注意! : 不要使用别的定时器,以免在连接WiFi时被打断,从而造成一直连接不上 WiFi )
*
************************************************************************************************************/
user_set_station_config();//设置 Wi-Fi Station 接口的配置
os_timer_disarm (&os_timer_station);//取消定时器器定时
os_timer_setfn(&os_timer_station, (ETSTimerFunc *)(time_station), NULL);//设置定时器器回调函数。使用定时器器,必须设置回调函数。
os_timer_arm (&os_timer_station, 200, true);//使能毫秒级定时器器
上面对应的定时器回调函数,如下所示:
/****************************************************************************
* 功能: Wi-Fi Station(客户端) 定时器
* 注意:在user_init中调用,则 ESP8266 Station 接口会在系统初始化完成后,自动连接 AP(WiFi路由器)
**************************************************************************/
static os_timer_t os_timer_station;
//软件定时器回调函数
void time_station(void){
struct ip_info info;
static uint16 station_x = 0;
os_printf("time_station: %d !!!!!!!!!!!!!!!!!\r\n",station_x++);
if(wifi_station_get_connect_status() == STATION_GOT_IP) {//查询 ESP8266 Wi-Fi Station 接口连接 AP 的状态 (连接成功则关闭定时器)
os_timer_disarm (&os_timer_station);
wifi_get_ip_info(STATION_IF, &info);//查询 Wi-Fi Station 接口的 IP 地址
uint8 ESP8266_IP[4];
ESP8266_IP[0] = info.ip.addr; // 最高8位
ESP8266_IP[1] = info.ip.addr>>8; // 次高8位
ESP8266_IP[2] = info.ip.addr>>16; // 次低8位
ESP8266_IP[3] = info.ip.addr>>24; // 低8位
os_printf("station_IP: %d . %d . %d . %d \r\n",ESP8266_IP[0],ESP8266_IP[1],ESP8266_IP[2],ESP8266_IP[3]);
dns_test();//获取服务器的IP
espconn_user.type = ESPCONN_TCP;
espconn_user.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));// 开辟内存
// 此处需要设置目标IP/端口(ESP8266作为Client,需要预先知道Server的IP/端口)
espconn_user.proto.tcp->local_port = espconn_port() ; // 设置本地端口
espconn_user.proto.tcp->remote_port = 80; // 设置目标端口
//uint8 remote_ip[4] = {104,108,185,124}; // 目标ip地址
os_memcpy(espconn_user.proto.tcp->local_ip,ESP8266_IP,4); // 拷贝内存
// 注册连接成功回调函数、异常断开回调函数
espconn_regist_connectcb(&espconn_user, ESP8266_TCP_Connect_Cb_JX); // 注册TCP连接成功建立的回调函数
espconn_regist_reconcb(&espconn_user, ESP8266_TCP_Break_Cb_JX); // 注册TCP连接异常断开的回调函数
// 连接 TCP server
espconn_connect(&espconn_user); // 连接TCP-server
}
system_soft_wdt_feed();//这里我们喂下看门狗 ,不让看门狗复位
}
在连接远端服务器时,需要获取IP才能进行连接,而我们平常只能知道服务器的域名,乐鑫SDK_API参考手册的espconn_gethostbyname()函数则是通过域名获取对应服务器的IP地址;
上面回调函数里面的dns_test()函数则是调用该函数获取服务器IP,代码如下所示:
// 获取到对应域名 IP 地址的回调函数
struct espconn espconn_user;
struct ip_addr_t *esp_server_ip;
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
struct espconn *pespconn = (struct espconn *)arg;
if (ipaddr != NULL){
os_printf("user_esp_platform_dns_found %d.%d.%d.%d \r\n",
*((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1),
*((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3));
espconn_user.proto.tcp->remote_ip[0] = *((uint8 *)&ipaddr->addr); // 设置目标IP地址
espconn_user.proto.tcp->remote_ip[1] = *((uint8 *)&ipaddr->addr + 1);
espconn_user.proto.tcp->remote_ip[2] = *((uint8 *)&ipaddr->addr + 2);
espconn_user.proto.tcp->remote_ip[3] = *((uint8 *)&ipaddr->addr + 3);
}
}
// 获取到对应域名 IP 地址
void dns_test(void) {
os_printf("999999%d \r\n");
espconn_gethostbyname(&espconn_user,"api.seniverse.com", &esp_server_ip,
user_esp_platform_dns_found);
}
在上上面的定时器回调函数里面,注册了TCP连接异常断开的回调函数espconn_regist_reconcb(&espconn_user, ESP8266_TCP_Break_Cb_JX); 函数,对应的回调代码函数代码,如下所示:
// TCP连接异常断开时的回调函数【ESP8266作为TCP_Client,连接TCP_Server失败,也会进入此函数】
void ICACHE_FLASH_ATTR
ESP8266_TCP_Break_Cb_JX(void *arg,sint8 err){
struct espconn * T_arg = arg; // 缓存网络连接结构体指针
os_printf("\nESP8266_TCP_Break\n");
espconn_connect(&espconn_user); // 重新连接TCP-server
}
在上上上面的定时器回调函数里面,注册了TCP连接成功建立的回调函数espconn_regist_connectcb(&espconn_user, ESP8266_TCP_Connect_Cb_JX); 函数,对应的回调代码函数代码,如下所示:
// TCP连接建立成功的回调函数
void ICACHE_FLASH_ATTR
ESP8266_TCP_Connect_Cb_JX(void *arg){
#define data "GET /v3/weather/daily.json?key=rrpd2zmqkpwlsckt&location=guangzhou&language=en&unit=c&start=0&days=3 HTTP/1.1\r\nContent-Type: text/html;charset=utf-8\r\nAccept: */*\r\nHost: api.seniverse.com\r\nConnection: Keep-Alive\r\n\r\n"
os_printf("###################### len: %d \r\n",os_strlen(data));
os_printf(data);
// 也可以不打招呼,因为TCP本身就是握手建立连接。只要TCP连接建立,TCP_Server就已经知道TCP_Client的信息
espconn_send((struct espconn *)arg,data,os_strlen(data)); // 打招呼
espconn_regist_sentcb((struct espconn *)arg, ESP8266_WIFI_Send_Cb_JX); // 注册网络数据发送成功的回调函数
espconn_regist_recvcb((struct espconn *)arg, ESP8266_WIFI_Recv_Cb_JX); // 注册网络数据接收成功的回调函数
espconn_regist_disconcb((struct espconn *)arg,ESP8266_TCP_Disconnect_Cb_JX); // 注册成功断开TCP连接的回调函数
os_printf("\n--------------- ESP8266_TCP_Connect_OK ---------------\n");
}
在“ 服务器连接成功回调函数 ”中,注册了数据发送成功回调函数,对应的回调函数,如下所示:
// 网络数据发送成功的回调函数
void ICACHE_FLASH_ATTR
ESP8266_WIFI_Send_Cb_JX(void *arg){
struct espconn * T_arg = arg; // 缓存网络连接结构体指针
os_printf("\nESP8266_Send_OK \r\n");
}
在“ 服务器连接成功回调函数 ”中,注册了接收服务器数据成功回调函数,对应的回调函数,如下所示:
// 成功接收网络数据的回调函数【参数1:网络传输结构体espconn指针、参数2:网络传输数据指针、参数3:数据长度】
void ICACHE_FLASH_ATTR
ESP8266_WIFI_Recv_Cb_JX(void * arg, char * pdata, unsigned short len){
struct espconn * T_arg = arg; // 缓存网络连接结构体指针
os_printf("ESP8266_Receive_Data_len = %d \r\n",len); // 串口打印接收到的数据长度
os_printf("ESP8266_Receive_Data = %s \r\n",pdata); // 串口打印接收到的数据
}
在“ 服务器连接成功回调函数 ”中,注册了断开服务器成功回调函数,对应的回调函数,如下所示:
// TCP连接断开成功的回调函数
void ICACHE_FLASH_ATTR
ESP8266_TCP_Disconnect_Cb_JX(void *arg){
struct espconn * T_arg = arg; // 缓存网络连接结构体指针
os_printf("\nESP8266_TCP_Disconnect_OK \r\n");
// 连接 TCP server
espconn_connect(&espconn_user); // 连接TCP-server
}
直接替换SDK的user_main.c文件,清除缓存,重新进行编译下载即可。代码下载地址:https://download.csdn.net/download/qq_26043945/85312127