2016-07-14 144 views
1

我正在一个项目中使用arduino uno和ESP8266ex作为wifi模块。电线连接:Arduino ESP8266 Softwareserial HTTP获取请求没有足够的缓冲区大小

Arduino 5V→3.3V稳压器→ESP:CH_PD(带10k电阻)和VCC Arduino GND→3.3V稳压器→ESP:GND和RST(复位已连接通过一个按钮和电阻)Arduino RX - > ESP TX Arduino TX - >分压器(2k 1k电阻) - > ESP RX 5uF电容 - >电压调节器,防止ESP自身复位。

现在让我解释我遇到的问题。我有两个代码工作,我使用ESP8266作为arduino uno的wifi模块。

#define ard_rx_esp_tx 2 
#define ard_tx_esp_rx 3 

#include <SoftwareSerial.h> 

SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX 

void setup() 
{ 
    int i = 0; 
    Serial.begin(9600);  // communication with the host computer 
    while (!Serial); 

    // Start the software serial for communication with the ESP8266 
    ESPserial.begin(9600); 
    Serial.println(""); 
    Serial.println(F("Remember to to set Both NL & CR in the serial monitor.")); 
    Serial.println(F("Ready")); 
    Serial.println(F("")); 
    Serial.println(F("start")); 
    delay(1000); 
} 
void loop() 
{ 

    if (ESPserial.available()) { 
    char c = ESPserial.read(); 
    Serial.print(c); 
    } 

    if (Serial.available()) { 
    ESPserial.write(Serial.read()); 
    } 
} 

我成功地打开与服务器的TCP连接,发送具有长(超过600个字符)的GET请求,并处理所有的长响应通过SoftwareSerial阅读:在我的第一个程序我的手发出的命令()函数并将它们全部打印到串行监视器。总之,这个代码能够处理这是一个服务器的600 +炭响应:

enter image description here

目的是发送这些AT经由“SoftwareSerial.print()”命令,并把在字符整个响应数组来解析它的API-KEY。我为此编写的代码至今为止:

#define ard_rx_esp_tx 2 
#define ard_tx_esp_rx 3 
char response[625]; 
#include <SoftwareSerial.h> 
SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX 
int i; 

void setup() 
{ 

    Serial.begin(9600);  // communication with the host computer 
    while (!Serial); 

    // Start the software serial for communication with the ESP8266 
    ESPserial.begin(9600); 

    Serial.println(""); 
    Serial.println(F("Remember to to set Both NL & CR in the serial monitor.")); 
    Serial.println(F("Ready")); 
    Serial.println(F("")); 
    Serial.println(F("start")); 
    delay(1000); 

    ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80"); 
    delay(5000); 

    i = 0; 
    while (ESPserial.available()) { 
     response[i] = ESPserial.read(); 
     i++; 
    } 
    response[i++] = '\0'; 
    Serial.println(response); 
    for (i = 0; i < 625; i++) { 
     response[i] = '\0'; 
    } 

    ESPserial.println("AT+CIPSEND=107"); 
    delay(5000); 

    i = 0; 
    while (ESPserial.available()) { 
     response[i] = ESPserial.read(); 
     i++; 
    } 
    response[i++] = '\0'; 
    Serial.println(response); 
    for (i = 0; i < 625; i++) { 
     response[i] = '\0'; 
    } 

    ESPserial.println("GET request to the server which has length 107 as indicated"); 
    delay(5000); 

    i = 0; 
    while (ESPserial.available()) { 
     response[i] = ESPserial.read(); 
     i++; 
    } 
    response[i++] = '\0'; 
    Serial.println(response); 
    for (i = 0; i < 625; i++) { 
     response[i] = '\0'; 
    } 
} 
void loop() { 
    // put your main code here, to run repeatedly: 

} 

它在“setup()”作用域的末尾打印响应。让我也把输出的照片:

enter image description here

总之,问题是:SoftwareSerial具有64字节的缓冲区,可提高到256个字节,当我增加它的程序能够打印然而,这次是256个字符,然而,在我的第一个手动发送AT命令的代码中,它可以处理整个响应,尽管它具有64字节的缓冲区,并且可以将它打印到串行监视器。在第二个我无法处理和存储整个响应到一个字符数组。

我希望我能解释我的问题,并指出我在我的过程中的具体细节。

你建议我做什么。在处理这个大响应并将其放入字符数组中时,我能做些什么?我该如何处理整个响应,它始终保留在ESP8266ex'缓冲区中,并且通过SoftwareSerial类读取Arduino RX引脚,其中函数read()具有64字节数组,并且可以增加到256但不再增加?

回答

4

所以,这里的问题都是关于时机。您知道,对于软件串行(对于任何硬件UART也是如此),您的缓冲区大小有256个字节的限制,波特率为9600位/秒。由于有一个起始位,8个数据位和一个停止位(假设你在这里使用9600 8N1,因为它是最常见的),所以你将每接收一个数据字节(1/9600)* 10 - 秒或1.04毫秒。因此,要接收256个字节,应该需要大约266毫秒。这意味着在266毫秒之后,您的缓冲区将完全满,并且之后收到的任何内容都将开始移除先前接收的数据。

问题的关键在于 - 您正在向ESP发送命令以接收来自服务器的数据,然后休眠5秒,这意味着什么都不会从缓冲区中提取数据,因此它会绕过导致数据丢失。串行缓冲区的重点不是保存您将在一个点上收到的整个数据集,而是保持它足够长的时间直到您可以读出它,这就是为什么它们通常很小。

你需要做的就是发送命令,并让你的Arduino立即运行代码,以尽可能快地从缓冲区检索数据,直到它找到预期的结束或超时。

一些基本的东西一样,这将让你去:

char espBuffer[1024] = {0}; 
int readCount = 0; 
long startTime = millis(); 

ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80"); 

while (millis() - startTime < 5000) { // Run for at least 5 seconds 
    // Check to make sure we don't exceed espBuffer's boundaries 
    if (ESPserial.available() > readCount + sizeof espBuffer - 1) 
    break; 
    readCount += ESPserial.readBytes(espBuffer + readCount, ESPserial.available()); 
} 

Serial.println(espBuffer); 

现在,你想要修改此代码时,它已经收到的所有预计的数据结束。此外,这个简单的设置将响应的最大大小限制为1023字节,这也不是太有用。理想情况下,你会继续阅读,直到找到HTTP主体,然后放弃其他所有内容,这意味着查找数据的缓冲区很小,实际存储主体的缓冲区可能更大。

+0

谢谢你的好解释 – 4JaoDeka