28-ESP8266 SDK开发基础入门篇--编写TCP 客户端程序(官方API版,非RTOS版)

https://www.cnblogs.com/yangfengwu/p/11432795.html

注:这节实现的功能是WIFI模块作为TCP 客户端,连接咱的TCP服务器,然后实现透传

本来想着做成断线重连,但是无论如何测试,使用官方给的API默认大约2个小时以后就会主动断开连接......

其实和咱 https://www.cnblogs.com/yangfengwu/p/11112014.html  (TCP 服务器差不多)

先看下程序测试 (连接路由器测试,让电脑和WIFI连接同一个路由器)

打开网络调试助手

我的TCP服务器IP是 192.168.1.93   端口号是 60000     根据自己的修改

下载进去

配网就不说了,如果不是从前面看过来的,去看前面文章哈

正常运行后

测试通信

不用这个调试助手了,关掉这个调试助手,咱用另一个网络调试助手,带自动发送的

关掉调试助手以后,会发现客户端一直在尝试重新连接

启动以后客户端会自动连接上

好,现在看一下程序

连接放在了

#include "esp_common.h"
#include "gpio.h"
#include "uart.h"
#include "esp_timer.h"
#include "hw_timer.h"
#include "pwm.h"
#include  "data_dispose.h"
#include  "espconn.h"
#include  "esp_wifi.h"
#include "lwip/api.h"

#include "crc.h"
#include "smart_config.h"

LOCAL os_timer_t public_timer;//定时器
u32 public_timer_cnt=0;//累加
u32 public_timer_state=0;//状态
u32 public_timer_out=0;//超时
u32 public_timer_cnt1=0;//累加

extern u8  Usart1ReadBuff[Usart1ReadLen];//接收数据的数组
extern u32 Usart1ReadCnt;//串口1接收到的数据个数
extern u32 Usart1ReadCntCopy;//串口1接收到的数据个数拷贝
extern u8  Usart1ReadFlage;//串口1接收到一条完整数据

#define  SSID "Learn8266" //无线名称
#define     PWD "11223344"     //密码
struct softap_config soft_ap_Config;//AP模式配置

//连接的路由器信息
#define APssid "qqqqq"
#define APpassword "11223344"
struct station_config stationConf;

//TCP客户端
struct espconn TcpClient;
esp_tcp esptcp;

ResolveData ResolveDataTest;//解析数据IEEE754
//uint32 pin_info_list[1][3]={PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5,5};//配置GPIO5作为PWM输出
//int duty[1]={0};//高电平时间是0us

/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don‘t know which sector is free in user‘s application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
*******************************************************************************/
uint32 user_rf_cal_sector_set(void)
{
    flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;

        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}

//串口调用此函数就说明接收到了一条完整的数据,就可以去处理了
void UartReadCallback()//定义一个函数
{
    espconn_send(&TcpClient,Usart1ReadBuff,Usart1ReadCntCopy);//串口接收的数据发给网络
}

//网络接收到数据
void TcpClientRecv(void *arg, char *pdata, unsigned short len)
{
    while(len--)
    {
        uart0_write_char(*(pdata++));//发送到串口
    }
}

//断开了连接
void TcpClientDisCon(void *arg)
{
    dbg_printf("\nTcpClientDisCon\n");
    espconn_connect(&TcpClient);//重新连接服务器
}

int keep_alive_sec = 1;//设置心跳包
//连接上服务器
void TcpConnected(void *arg)
{
    dbg_printf("\nTcpConnected\n");

    //设置启用心跳包
    dbg_printf("\nespconn_set_opt=%d\n",espconn_set_opt(&TcpClient,ESPCONN_KEEPALIVE));//成功:0  失败:其它
    //客户端断开直接释放内存
    dbg_printf("\nespconn_set_opt=%d\n",espconn_set_opt(&TcpClient,ESPCONN_REUSEADDR));//成功:0  失败:其它

    //每隔ESPCONN_KEEPIDLE 开始启动心跳包探测,
    //如果探测失败,则每每隔  ESPCONN_KEEPINTVL  发送一次探测,
    //探测  ESPCONN_KEEPCNT  次以后还是无相应,则进入  espconn_reconnect_callback 回调函数  (espconn_regist_reconcb(&TcpClient, TcpConnectErr);//注册连接出错函数)

    keep_alive_sec = 30;//每隔30S开始一次探测
    espconn_set_keepalive(&TcpClient,ESPCONN_KEEPIDLE,&keep_alive_sec);

    keep_alive_sec = 1;//开始探测后,心跳包每隔1S发送一次
    espconn_set_keepalive(&TcpClient,ESPCONN_KEEPINTVL,&keep_alive_sec);

    keep_alive_sec = 3;//心跳包总共发送3次
    espconn_set_keepalive(&TcpClient,ESPCONN_KEEPCNT,&keep_alive_sec);

    espconn_regist_recvcb(&TcpClient, TcpClientRecv);//设置接收回调
    espconn_regist_disconcb(&TcpClient, TcpClientDisCon);//设置断开连接回调
}

//连接出错
void TcpConnectErr(void *arg, sint8 err)
{
    dbg_printf("\nTcpConnectErr=%d\n",err);
    espconn_connect(&TcpClient);//链接
}

//监听WiFi状态改变
void wifi_event_monitor_handle_event_cb(System_Event_t *evt)
{
  switch (evt->event_id)
  {
    case EVENT_STAMODE_CONNECTED://连接上路由器
        dbg_printf("\n\tSTAMODE_CONNECTED\n");

        dbg_printf("\tConnected to SSID %s, Channel %d\n",
          evt->event_info.connected.ssid,
          evt->event_info.connected.channel);
      break;

    case EVENT_STAMODE_DISCONNECTED://和路由器断开
        dbg_printf("\n\tSTAMODE_DISCONNECTED\n");

        dbg_printf("\tDisconnect from SSID %s, reason %d\n",
          evt->event_info.disconnected.ssid,
          evt->event_info.disconnected.reason);
      break;

    case EVENT_STAMODE_AUTHMODE_CHANGE://这个是 啥..
        dbg_printf("\n\tSTAMODE_AUTHMODE_CHANGE\n");

        dbg_printf("\tAuthmode: %u -> %u\n",
          evt->event_info.auth_change.old_mode,
          evt->event_info.auth_change.new_mode);
      break;

    case EVENT_STAMODE_GOT_IP://连接上路由器,并获取了IP
        dbg_printf("\n\tGOT_IP\n");

        dbg_printf("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n",
          IP2STR(&evt->event_info.got_ip.ip),
          IP2STR(&evt->event_info.got_ip.mask),
          IP2STR(&evt->event_info.got_ip.gw));

        if(public_timer_state == 0)//正常运行下连接的路由器
        {
            espconn_connect(&TcpClient);//连接TCP服务器
        }

      break;

    case EVENT_STAMODE_DHCP_TIMEOUT://连接上路由器,但是路由器给WIFI模块分配IP等信息超时了
        dbg_printf("\n\tSTAMODE_DHCP_TIMEOUT\n");
      break;

    case EVENT_SOFTAPMODE_STACONNECTED://AP模式下,有设备连接WIFI模块的无线
        dbg_printf("\n\tSOFTAPMODE_STACONNECTED\n");

        dbg_printf("\tStation: " MACSTR "join, AID = %d\n",
          MAC2STR(evt->event_info.sta_connected.mac),
          evt->event_info.sta_connected.aid);
      break;

    case EVENT_SOFTAPMODE_STADISCONNECTED://AP模式下,有设备断开和WIFI模块的无线连接
        dbg_printf("\n\tSOFTAPMODE_STADISCONNECTED\n");

        dbg_printf("\tstation: " MACSTR "leave, AID = %d\n",
          MAC2STR(evt->event_info.sta_disconnected.mac),
          evt->event_info.sta_disconnected.aid);
      break;

    case EVENT_SOFTAPMODE_PROBEREQRECVED://这是啥??,,,信号强度改变了
        dbg_printf("\n\tSOFTAPMODE_PROBEREQRECVED\n");

        dbg_printf("Station PROBEREQ: " MACSTR " RSSI = %d\n",
          MAC2STR(evt->event_info.ap_probereqrecved.mac),
          evt->event_info.ap_probereqrecved.rssi);
      break;

    default://其它错误
        dbg_printf("\n\tswitch/case default\n");
      break;
  }
}

//所有需要定时操作的函数在此函数中执行
LOCAL void ICACHE_FLASH_ATTR
public_timer_callback(void)
{
    if(GPIO_INPUT_GET(0) == 0)//按键按下
    {
        public_timer_cnt++;
        if(public_timer_cnt>=300 && public_timer_state==0)//3S
        {
            dbg_printf("\nstartsmart\n");
            public_timer_state=1;
            wifi_station_disconnect();
            wifi_set_opmode(STATION_MODE);
            smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);//SmartConfig  +  AirKiss
            xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
        }
    }
    else
    {
        if(public_timer_state!=1 && public_timer_cnt>0 && public_timer_cnt<300)//短按复位
        {
            dbg_printf("\nsystem_restart\n");
            system_restart();//复位
        }
        public_timer_cnt=0;
    }

    switch(public_timer_state)
    {
        case 0:break;
        case 1:
            public_timer_out++;
            public_timer_cnt1++;
            if(public_timer_out>=6000)//60S
            {
                dbg_printf("\nsmartconfig_timeout\n");
                system_restart();//复位
            }
            if(public_timer_cnt1>10)//LED快闪
            {
                public_timer_cnt1=0;
                GPIO_OUTPUT_SET(2, 1-GPIO_INPUT_GET(2));//LED快闪
            }
            break;
        default:break;
    }
}

/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void user_init(void)
{
    GPIO_OUTPUT_SET(5, 1);
    GPIO_OUTPUT_SET(2, 0);//让两个灯初始的状态一样,GOIO2是反接的,0的时候是亮
    GPIO_OUTPUT_SET(0, 1);
    uart_init_new();
    printf("SDK version:%s\n", system_get_sdk_version());

    wifi_set_opmode(STATIONAP_MODE);//配置WiFi的模式STATION + AP AP--连接WIFI自身的无线实现通信  STATION--wifi连接路由器,手机或者电脑也连接路由器,实现通信
    soft_ap_Config.ssid_len = strlen(SSID);//热点名称长度,与你实际的名称长度一致就好
    memcpy(soft_ap_Config.ssid,SSID,soft_ap_Config.ssid_len);//实际热点名称设置,可以根据你的需要来
    memcpy(soft_ap_Config.password,PWD,strlen(PWD));//热点密码设置
    soft_ap_Config.authmode = AUTH_WPA2_PSK;//加密模式
    soft_ap_Config.channel = 1;//信道,共支持1~13个信道
    soft_ap_Config.max_connection = 4;//最大连接数量,最大支持四个,默认四个

    wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash
    //    wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash
    UartCallbackRegister(UartReadCallback);//把 UartReadCallback 函数地址传过去,在串口里面调用

    os_timer_disarm(&public_timer);
    os_timer_setfn(&public_timer, (os_timer_func_t *)public_timer_callback, NULL);
    os_timer_arm(&public_timer, 10, 1);//10ms

    //设置连接的路由器,如果想直接测试不想配网,请去掉屏蔽
//    stationConf.bssid_set = 0;
//    memcpy(stationConf.ssid,APssid,strlen(APssid));//路由器名称
//    memcpy(stationConf.password,APpassword,strlen(APpassword));//路由器密码
//    wifi_station_disconnect();
//    wifi_station_set_config(&stationConf);

    wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb);//监听WiFi状态改变

    //初始化TCP
    espconn_init();
    TcpClient.type = ESPCONN_TCP;
    TcpClient.state = ESPCONN_NONE;
    TcpClient.proto.tcp = &esptcp;

    //服务器IP 地址
    TcpClient.proto.tcp->remote_ip[0]=192;
    TcpClient.proto.tcp->remote_ip[1]=168;
    TcpClient.proto.tcp->remote_ip[2]=1;
    TcpClient.proto.tcp->remote_ip[3]=93;

    TcpClient.proto.tcp->remote_port = 60000;//连接端口号

    espconn_regist_connectcb(&TcpClient, TcpConnected);//注册连接函数
    espconn_regist_reconcb(&TcpClient, TcpConnectErr);//注册连接出错函数

    //espconn_regist_time(&TcpClient,0,0);//测试2个小时自动断开问题
}

大家自己去测试。

原文地址:https://www.cnblogs.com/yangfengwu/p/11456667.html

时间: 2024-08-02 05:40:48

28-ESP8266 SDK开发基础入门篇--编写TCP 客户端程序(官方API版,非RTOS版)的相关文章

19-ESP8266 SDK开发基础入门篇--C# TCP客户端编写 , 连接和断开

https://www.cnblogs.com/yangfengwu/p/11130428.html 渐渐的看过去,,,好多节了... 这节做一个C# TCP客户端 新建项目啥子的就不详细截图写了,自行看前面了解 (我的文章只要是有序号的,必须要看前面,因为我所写的教程即是基础又是综合) 先做个这个页面,先做连接和断开 链接TCP用这个变量 其实连接TCP 几句就完了 我定义了一个函数是因为,其实连接时阻塞的,,所以咱需要开个任务 C# 的任务是这样用 OK  现在测试 由于我是用的台式机,,没

20-ESP8266 SDK开发基础入门篇--C# TCP客户端编写 , 加入数据通信

https://www.cnblogs.com/yangfengwu/p/11192594.html 自行调整页面 连接上以后主动发个数据 namespace TCPClient { public partial class Form1 : Form { private TcpClient myTcpClient = null;// TcpClient Thread ConnectThread;//连接线程 string ipAddress;//记录ip地址 int Port = 0;//端口号

21-ESP8266 SDK开发基础入门篇--C# TCP客户端 , 控制LED亮灭

https://www.cnblogs.com/yangfengwu/p/11192603.html 由于是台式机,,没有插无线网卡...所以呢我就用调试助手监控下数据 后期让WIFI连接路由器的时候,在一个局域网内再和开发板联合测试 我就做的尽量简单点 那个CRC还需要再往后放一放,,,,,,需要和WiFi一块...现在我台式机不能连接WiFi信号,所以,,,,,再等一等 大家如果是笔记本 ,可以连接WiFi的无线,,然后 测试就可以 原文地址:https://www.cnblogs.com/

26-ESP8266 SDK开发基础入门篇--编写WIFI模块 SmartConfig/Airkiss 一键配网

https://www.cnblogs.com/yangfengwu/p/11427504.html SmartConfig/Airkiss 配网需要APP/微信公众号,这节大家先使用我做好的APP/微信公众号 APP下载: https://www.cnblogs.com/yangfengwu/p/11249674.html 微信公众号: 扫描这个二维码关注我的公众号      其余的步骤等写完8266的配网程序,在下面演示. 如果想自己实现微信绑定可以看↓ (注:配置过程和源码全部是公开的,大

12-ESP8266 SDK开发基础入门篇--PWM,呼吸灯

https://www.cnblogs.com/yangfengwu/p/11094085.html PWM其实没有什么,就是看着官方给的API,,,然后就是用呗 对了,其实对于RTOS SDK版本的开发可以直接去参考非RTOS SDK的API  这个直接有例子 其实嵌入操作系统也没有什么,底层自带的外设硬件功能该怎么样还是怎么样,操作系统也不能改变什么,,操作系统的存在只是去操作咱定义的函数,让这些函数执行的时候快速的切换执行... 我直接说第三个参数 第三个参数是说要定义一个 这样的数组  

6-ESP8266 SDK开发基础入门篇--操作系统入门使用

https://www.cnblogs.com/yangfengwu/p/11080567.html 了解了8266的串口了,这一节咱就自己写程序,处理一下数据,如果接收到 0xaa 0x55 0x01  就控制指示灯亮 0xaa 0x55 0x00  就控制指示灯灭 注意哈,我是用的假设没有操作系统的思路,其实如果有了操作系统应该用操作系统提供的API实现 因为8266是用的FreeRtos,,,我还没有深入了解这个系统,所以我先用我的方式实现,后期的文章可能需要等些时间更新了,因为我需要充电

7-ESP8266 SDK开发基础入门篇--串口处理数据,控制LED

https://www.cnblogs.com/yangfengwu/p/11087467.html 接着上一节的写 咱先做一个单片机串口接收到什么就回过来什么 咱自己写个发送函数,其实就是仿照官方的写的 别忘了 现在咱建个任务处理串口数据 下载进去 现在是三个任务都在运行了...操作系统是不是很神奇 现在做这个 咱就控制GPIO5.咱把这里屏蔽掉 现在做处理,,,其实很简单 现在下载进去 OK 了 下一节,咱做一个上位机来控制 https://www.cnblogs.com/yangfengw

Android 开发基础入门篇: 复制一个工程作为一个新的工程

说明 咱们做项目很多时候都需要复制一份工程出来作为一个新的工程 把第一节的工程拷贝到这一节 修改工程名字 打开软件导入此工程 修改包名 第一节的时候说了,一个APP一个包名 自行添加修改 自行修改 自行修改 选择 Sync Now 清理下工程 然后安装到手机 原文地址:https://www.cnblogs.com/yangfengwu/p/11909225.html

Linux及Arm-Linux程序开发笔记(零基础入门篇)

Linux及Arm-Linux程序开发笔记(零基础入门篇)  作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer/archive/2011/05/05/2037449.html 目录 一.Arm-Linux程序开发平台简要介绍... 3 1.1程序开发所需系统及开发语言... 3 1.2系统平台搭建方式... 4 二.Linux开发平台搭建... 5 2.1安装虚拟工作站... 5 2.2安装Linux虚拟