努力让 Arduino Uno 上的 ESP8266 与 AT 通信可靠地工作

Posted

技术标签:

【中文标题】努力让 Arduino Uno 上的 ESP8266 与 AT 通信可靠地工作【英文标题】:Struggling to get ESP8266 on Arduino Uno working reliably with AT communication 【发布时间】:2020-03-16 04:46:59 【问题描述】:

我正在努力将 ESP8266 连接到作为网络服务器可靠工作的 Arduino Uno。我的 ESP8266 的固件是 1.1.1 - 我目前没有更新它的选项(或知识)。下面是我的代码。如果我提供一个小字符串,它几乎不会起作用。但是,如果我尝试从浏览器加载页面三到四次,它通常会关闭连接或永远加载(崩溃?)。最终,我需要提供一个嵌入了 json 的网页,该网页将加载由 esp8266 提供的第二个页面,一个 json 文件。我有一个工作演示,但在几次检索后它崩溃了。我知道我的 html 页面对于字符串来说太长了,所以一直试图转移到 PROGMEM,最初只用一个短字符串进行测试。我正在正确地存储和检索它(我认为,至少我可以Serial.print 它)但是一旦我尝试将它写入 ESP8266,我的浏览器中就会出现永无止境的负载。

我哪里错了?是导致问题的字符串/PROGMEM 还是我在 AT 命令中缺少的其他内容(例如某种 ping 以保持连接打开)?

//load softserial library
#include <SoftwareSerial.h>

#include <avr/pgmspace.h>


//set a boolean constant variable to true
//#define DEBUG true
const boolean DEBUG = true;

//RX (pin 2) goes to TX on esp8266, TX (pin 3) goes to RX on esp8266
SoftwareSerial esp8266(2, 3);

//input from the photoresistor
//int photoresistorpin = 0;

//create a PROGMEM variable
//String WEBPAGE = "hello";
static const char PROGMEM WEBPAGE[] = "hello";

/*
static const char WEBPAGE[] PROGMEM = R"rawliteral(
<html>
<head>
<meta name="viewport" content="width=device-width, minimumscale=1, maximum-scale=1, initial-scale=1">
</head>
  <h1>Light:</h1><div id="light"></div>
<script>
function loadDoc()

  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() 
    if (this.readyState == 4 && this.status == 200) 
    
      var obj = JSON.parse(this.responseText);
      document.getElementById('light').innerHTML = obj.data[0].datavalue;
    
  ;
xhttp.open('GET', 'data.json', true); xhttp.send();

var timedEvent = setInterval(function()  loadDoc(); , 5000);
</script>
</body>
</html>
)rawliteral";
*/
//const int WEBPAGE_len = sizeof(WEBPAGE)/sizeof(WEBPAGE[0]);



void setup()

  //open the serial port
  Serial.begin(115200);

  //print setup started in the serial monitor
  Serial.println("Setup started");

  //start esp8266 module (note: your esp's baud rate might be different)
  esp8266.begin(115200);

  //reset esp8266 module
  senddata("AT+RST\r\n", 2000, DEBUG); 

  //set esp8266 as access point mode
  //1 = Station mode (client)
  //2 = Access point mode (host)
  //3 = Access point mode + Station mode
  senddata("AT+CWMODE=2\r\n", 1000, DEBUG); 

  //get ip address for esp8266
  senddata("AT+CIFSR\r\n", 2000, DEBUG);

  //configure esp8266 for multiple connections
  senddata("AT+CIPMUX=1\r\n", 1000, DEBUG);

  //turn on esp8266 server on port 80
  senddata("AT+CIPSERVER=1,80\r\n", 1000, DEBUG);

  //setup completed
  Serial.println("Setup done");



void loop()

  //take a reading from the photoresistor
  //int lightval = analogRead(photoresistorpin);
  int lightval = random(1000);

  //to test
  //Serial.println(lightval);

  //is the esp8266 sending a message 
  if (esp8266.available())
  
    //if received data from esp8266
    if (esp8266.find("+IPD,"))
    
      //subtract 48 because the read() function returns the ASCII decimal 
      //value and 0 (the first decimal number) starts at 48
      int connectionid = esp8266.read() - 48;

//Serial.println("");
//Serial.println("*****");
//Serial.print("string = ");

      //read the url sent by the client, look for the variable (/)
      String msg;
      esp8266.find("/");
      delay(100);
      msg = esp8266.readStringUntil(' ');
      String pathrequested = msg.substring(0);

Serial.println("*****");
Serial.println(pathrequested);
Serial.println("*****");


        //create a senddata string to send the webpage to the esp8266
        String cipsend = "AT+CIPSEND=" + String(connectionid) + ",";

        //cipsend += WEBPAGE.length();
        cipsend += strlen_P(WEBPAGE);
        cipsend += "\r\n";
        Serial.println(cipsend);

        char buffer[1000];
        strcpy_P(buffer, WEBPAGE);
        Serial.println(buffer);

        //senddata(cipsend, 500, DEBUG);
        //senddata(WEBPAGE, 500, DEBUG);
        senddata(buffer, 500, DEBUG);

        //create a string closecommand with the connection id and send it
        String closecommand = "AT+CIPCLOSE=" + String(connectionid) + "\r\n";
        senddata(closecommand, 500, DEBUG);

        //increment the count
        //count++;

    
  





void senddata(String command, const int timeout, boolean debug)

  //send the received command to the esp8266
  esp8266.print(command);

  //set int variable to the number of millisends since Arduino began
  long int time = millis();

  //while the time and the timeout is less than the number of millisends since Arduino began
  while((time + timeout) > millis())
  
    //while the esp8266 is sending messages
    while(esp8266.available())
    
      //display output in the serial window 
      Serial.write(esp8266.read());
      
  

【问题讨论】:

编译代码后,Arduino IDE 上显示的动态内存使用情况如何? 我在这里看到两个问题,1)您使用了很多 String 类和一个大缓冲区 [1000],这可能会导致大量堆碎片和内存不足。你不需要那个缓冲区[1000],你需要做的是使用pgm_read_byte_near()直接从程序内存中直接读取网页数据。 2)另一个不稳定来自您的senddata(),它在发送下一个命令之前从不解析来自 esp8266 的返回确认。例如,当你发送AT+CIPSEND 命令时,它应该等到你收到&gt; 的确认后才发送WEBPAGE。 @hcheung 等待退货是我没有发现的一个问题,我会在周末尝试解决这个问题。我已经尝试了您提出的其他建议,但没有取得多大成功。 【参考方案1】:

假设“在我的浏览器中获得永无止境的负载”意味着浏览器中没有显示 - 请检查以下内容: 1. 去掉代码中的 String 和 String 构造函数(+=),用一个固定的 char 数组替换它来构建消息。阅读更多:https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/ 2. 我对 AT 接口的经验是 - 超过 9600 波特不可靠,这不足以满足您的需求。 3. 如果您的 Esp 模块的最小 512kb(很可能高达 4Mb)在此处托管您的代码,并且仅将 UNO 用作来自附加硬件/传感器的信号接收器/发送器。为自己省去很多麻烦和问题 - AT com 的大多数示例都没有真正起作用,而且更痛苦。我在 2 天内放弃了 AT 界面,并且在过去 4 年中从未错过任何东西。 通过将代码闪烁到 Esp 模块,您还可以完全控制和查看由于调试可能性而发生的事情,您甚至可以托管 html文件系统上的 /css/js (LittleFS / SPIFFS)

【讨论】:

1.字符串 - 明天将尝试再次回到这个问题,并为 char 数组和 PROGMEM 删除所有字符串。我已经测试了 PROGMEM,它似乎没有任何改善,但会重新尝试。 2. > 9600 波特 - 是的,到处都可以阅读,但我的经验似乎与此相矛盾。是的,它会吐出一些垃圾,但它确实有效(至少在一段时间内)。我尝试使用 AT 命令重置波特率,即从 115200 开始,设置为 9600,然后在 9600 处重新启动。ESP8266 没有响应。 3. 将对此进行探索,但目前没有 ESP8266 到 USB 连接。 @3.如果您有 Uno(或克隆),则可以在没有 TTL 适配器的情况下使用三个选项来闪光。 cordobo.com/2300-flash-esp8266-01-with-arduino-uno 或 create.arduino.cc/projecthub/pratikdesai/… 或更复杂的 tttapa.github.io/Pages/Arduino/ESP8266/Flashing/… 至少将您的 ESP AT 固件刷新到最新的稳定版本 2.1(Espressif 也放弃了它 - 所以自 2019 年中期以来没有更新,大约 70 个未解决的问题)。 Bin 和更多信息:github.com/espressif/ESP8266_NONOS_SDK

以上是关于努力让 Arduino Uno 上的 ESP8266 与 AT 通信可靠地工作的主要内容,如果未能解决你的问题,请参考以下文章

arduino UNO r3和arduino mega2560 用esp8266 01的WiFi模块可以接入百度天工物联网平台吗?

我的 ESP32 代码在 Arduino uno 之间建立 UART 通信是不是正确?

Arduino Uno 上的两个 ISR

blinker控制步进电机起保停,正反转,加减速(Arduino uno+esp8266+TB6600驱动器)

物联网Arduino Uno开发板连接阿里云实现云端远程控制LED灯开关

求教ESP8266使用ARDUINO1.66烧写