ESP8266使用arduino开发时遇到的IO读写延迟的问题及解决方案

作者:cwb_tfx | 更新时间:2018-12-13

最近在使用ESP8266连接BIGIOT服务器做开发时遇到了一个很奇怪的问题

由于本人也是第一次玩arduino和esp8266,不知道arduino 里面的io读写会有这么大的坑

在使用client类调用readstring等系列(只要是读一大串字符串的api)接口都会发生延迟的现象,手机发送的数据经过服务器传

到板子,延迟有四五秒左右。起初我以为跟网络延迟有关系,但是经过测试发现,与此无关。

后面我想是否跟io读取string 数据的实现有关系,也就是说,底层读取函数并不知道从服务器发来的数据已经读取完成了,因此

会一直等待完整的数据到来(这种情况下,我们发送多次数据后,在停止发送后会一次性把所有的数据读取出来),于是我想是否

可以人为的区分服务器发来的每一条信息,在查阅arduino函数后,发现有readBytes()方法,但是我在使用这个函数一次性读取多个

字符串时也存在延迟现象,因此我改成一个字符一个字符去读(只有每次读一个字符才能解决,其他方式都不行,读者可以自行测试),

读到\n就算拿到一帧完整的数据。使用int recvData(char* buff, int len) 这个函数解决了延迟的问题。

下面贴出源码,在此之前,先简单介绍一下:

该源码实现了WIFI断开自动重启,连接超时自动重连,离线自动重连等功能,意思就是说,无论在哪个环节掉线了,都会重新去连接。

代码只是一段测试,有需要的朋友可以自行修改测试。

另外值得注意的地方是,这里使用的是8282端口,被动在线(客户端不主动给服务器发心跳包,而是等服务器先发心跳包过来,然后再发心跳包给服务器)

源码如下:

============================================================================================

#include
WiFiClient client;

#define RCV_BUFF_LEN 512

#define SND_HEART_JUMP_PKG     "{\"M\":\"b\"}\n"
#define SND_CONNECT_PKG        "{\"M\":\"checkin\",\"ID\":\"1234\",\"K\":\"1212121\"}\n"
#define MSG_CONNECT_TO_BIGIOT  "{\"M\":\"WELCOME TO BIGIOT\"}\n"
#define LED1 16 //LED连接在8266的GPIO16上
#define LED2 2 //LED连接在8266的GPIO2上
const char *ssid     = "cwbtest";//"360WiFi-3C7943";
const char *password = "1234567891";//"112233445566";
const char *host = www.bigiot.net;
const int httpPort = 8282;
static char recvBuff[RCV_BUFF_LEN] = {0};
int len = 0;

int recvData(char* buff, int len)
{
     if(len <= 0)
     {
           Serial.print("Len value error ");
           return -1;
     }
     char str;
     int count = 0;
     while(client.readBytes(&str,1) > 0)
     {
          recvBuff[count++] = str;
          if(str == '\n')
          {
              recvBuff[count++] = '\0';
              break; 
          }
          if(count >= len)
          {
              return -1; 
          }
     }
     return count;
}

bool ConnectToWIFI(const char* ssid, const char* passwd)
{
    if(WiFi.status() == WL_CONNECTED)
    {
        return true; 
    }
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, passwd);
    int timeCount = 0;
    while(WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
        timeCount++;
        if(timeCount >= 20)
        {
            Serial.print("Connect to ");
            Serial.print(WiFi.SSID());
            Serial.println("failer, time out!");
            return false;
        }
    }
    Serial.println("");
    return true;
}
bool ConnectToServer(const char* host, const int port)
{
    int timeCount = 0;
    client.flush();
    while(!client.connect(host, port))
    {
        Serial.println("connection to Server failed,retry...");
        delay(4000);
        timeCount++;
        if(timeCount >= 5)
        {
            Serial.print("Connect to ");
            Serial.print(host);
            Serial.println(" failer, time out!");
            return false;
        }
    }
    timeCount = 0;
    while(true)
    {
        if(( len = client.readBytesUntil('\0',recvBuff,RCV_BUFF_LEN)) > 0)
        {
            recvBuff[len] = '\0';
            Serial.print(recvBuff);
            String line = String(recvBuff);
            if(line.compareTo(MSG_CONNECT_TO_BIGIOT) == 0)
            {
                Serial.print("connected to ");
                Serial.println(host);
            }
            break;
        }
        delay(10);
        timeCount++;
        if(timeCount >= 1000)
        {
            Serial.println("GET Connect Message time out!");
            return false; 
        }
    }
    return true;
}
bool LogInToServer()
{
    int timeCount = 0;
    while(true)
    {
        int count = 0;
        bool isConnect = false;
        client.write(SND_CONNECT_PKG);//登陆设备,修改成自己的ID和key
        while(true)
        {
            if(( len = client.readBytesUntil('\0',recvBuff,RCV_BUFF_LEN)) > 0)
            {
                Serial.println(recvBuff);
                String line = String(recvBuff);
                if(line.compareTo("checkinok") > 0)
                {
                    //Serial.println("connect ok");
                    return true;
                }
            }
            delay(3000);
            count++;
            if(count >= 5)
            {
                Serial.println ("time out>>> retry");
                timeCount++;
                break;
            }
        }
        if(timeCount >= 3)
        {
            return false;
        }
    }
    return true; 
}
bool IsWifiConnect()
{
    if(WiFi.status() != WL_CONNECTED)
    {
        return false;
    }
    return true; 
}

void setup()
{
    Serial.begin(115200);
    Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    delay(10);
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
}

void loop()
{
    unsigned int timeStart = 0;
    unsigned int timeEnd = 0;
    static int ledctrl = LOW;
    while(1)
    {
        Serial.println("Welcom to use this ESP8266 device");
        Serial.print("Step1: Connecting to ");
        Serial.println(ssid);
   
        if(!ConnectToWIFI(ssid, password))
        {
            continue ;
        }
        Serial.println("WiFi connected");
        Serial.print("IP address: ");
        Serial.println(WiFi.localIP());
        Serial.println("");

        Serial.println("Step2: ConnectTo Server>>");
        if(!ConnectToServer(host, httpPort))
        {
            delay(3000);
            continue;
        }
        Serial.println("Connect to server successful!");
        Serial.println("");
        Serial.println("Step3: Login to Server>>");
        if(!LogInToServer())
        {
            client.stop();
            delay(3000);
            continue;
        }
        Serial.println("Login to Server successful!");
        Serial.println("Now you can control your device by ethernet!");
        timeStart = millis();
        while(1)
        {
             if(( len = recvData(recvBuff,RCV_BUFF_LEN)) > 0)
            {
                digitalWrite(LED1,ledctrl);
                digitalWrite(LED2,ledctrl);
                if(ledctrl == LOW)
                {
                    ledctrl = HIGH; 
                }
                else
                {
                    ledctrl = LOW;
                }
                timeStart = millis();
                String line = String(recvBuff);
                if(line.compareTo(SND_HEART_JUMP_PKG) == 0)
                {
                    Serial.println("this is heart jump package");
                    client.write(SND_HEART_JUMP_PKG);
                }
                Serial.print(line);
            }
            timeEnd = millis();
            if((IsWifiConnect() == false) || ((timeEnd - timeStart) > 180000))
            {
                Serial.println(timeEnd - timeStart);
                Serial.println("Error Message: Wifi Disconnect!\n");
                Serial.println("Retry to connect to WIFI");
                break;
            }
        }
    }
}

 


评论:共2条

xbk 评论于:2018-12-13 14:03:28
厉害了!
799243768 评论于:2019-04-13 13:28:23
用readStringUntil()方法没有延时
评论支持使用[code][/code]标签添加代码
返回顶部