ESP8266节点MCU can';t发送TCP命令-相同的代码在Arduino Uno上工作?
我在这方面很在行,所以希望这是一个愚蠢的显而易见的问题 我正在尝试创建一个简单的温度/湿度传感器,从DHT22获取读数,并使用ESP8266将其ping到Thingspeak的API,然后绘制/存储等 我已经在下面粘贴了代码——它在Arduino Uno上工作,我正在尝试将其缩小到ESP8266上,这样我就可以为房子周围生产许多小型温度传感器 症状ESP8266节点MCU can';t发送TCP命令-相同的代码在Arduino Uno上工作?,tcp,arduino,esp8266,esp8266wifi,Tcp,Arduino,Esp8266,Esp8266wifi,我在这方面很在行,所以希望这是一个愚蠢的显而易见的问题 我正在尝试创建一个简单的温度/湿度传感器,从DHT22获取读数,并使用ESP8266将其ping到Thingspeak的API,然后绘制/存储等 我已经在下面粘贴了代码——它在Arduino Uno上工作,我正在尝试将其缩小到ESP8266上,这样我就可以为房子周围生产许多小型温度传感器 症状 无线网络连接正常 它正在生成正确的API字符串(我已经通过手动剪切并粘贴到浏览器中进行了测试) 温度传感器也产生正确的读数 它返回“数据失败!”在
- 无线网络连接正常
- 它正在生成正确的API字符串(我已经通过手动剪切并粘贴到浏览器中进行了测试)
- 温度传感器也产生正确的读数
- 它返回“数据失败!”在串行监视器中,表明错误发生在代码中的这一点
22:16:50.266->**************
22:16:57.579->Wifi连接成功
22:16:57.579->传感器的IP地址为:192.168.1.211
22:16:57.579->湿度:41.50
22:16:57.579->温度:21.70
22:16:57.579->AT+CIPSTART=“TCP”,“api.thingspeak.com”,80
22:17:00.574->AT+CIPSEND=63
22:17:01.561->AT+CIP关闭
22:17:02.577->数据失败!
22:17:02.577->获取/更新?apikey=&field1=21.70&field2=41.50
#包括
#包括“DHT.h”
#包括
#定义SSID“”//您的网络名称
#定义PASS”“//您的网络密码
#定义API“”//API字符串
#定义IP“api.thingspeak.com”//thingspeak.com
#定义DHTPIN 4//DHT传感器连接到的引脚
#定义DHTTYPE DHT22//如果您有DHT22,则更改为DHT22
#定义波特率115200//另一个常用值是9600
#定义延迟时间300000//将数据发布到ThingSpeak之间的时间(毫秒)
//也可以使用post
String GET=String(“GET/update?apikey=”)+API+“&field1=”;
字符串FIELD2=“&FIELD2=”;
//如果您想添加更多字段,这就是
//字符串FIELD3=“&FIELD3=”;
布尔更新;
DHT-DHT(DHTPIN,DHTTYPE);
//这只运行一次
无效设置()
{
延迟(5000);
串行开始(波特率);
//连接到WIFI
WiFi.begin(SSID,PASS);
while(WiFi.status()!=WL_已连接)
{
延迟(500);
序列号。打印(“*”);
}
Serial.println(“”);
Serial.println(“Wifi连接成功”);
串行打印(“传感器的IP地址为:”);
Serial.println(WiFi.localIP());//打印IP地址
//初始化DHT传感器
dht.begin();
}
//这件事一再发生
void循环(){
浮动h=dht.read湿度();
连续打印(“湿度:”);
序列号println(h);
//将温度读数为华氏度(伊斯华氏度=真)
浮点数c=dht.readTemperature();
连续打印(“温度:”);
序列号println(c);
//检查是否有读取失败并提前退出(以重试)。
if(isnan(h)| | isnan(c)){
Serial.println(“读取DHT22失败,正在退出”);
返回;
}
//使用新值更新ThingSpeak频道
updated=updateTemp(字符串(c),字符串(h));
//等待延迟时间,然后再次尝试发布
延迟(延迟时间);
}
bool updateTemp(字符串临时性,字符串潮湿){
//初始化AT命令字符串
String cmd=“AT+CIPSTART=\“TCP\”,\”;
//添加IP地址和端口
cmd+=IP;
cmd+=“\”,80”;
//连接
Serial.println(cmd);
延迟(2000年);
if(Serial.find(“Error”)){
返回false;
}
//build GET命令,ThingSpeak获取Post或更新的GET命令,我使用GET
cmd=GET;
cmd+=tempC;
cmd+=FIELD2;
cmd+=潮湿;
cmd+=“\r\n”;
//如果有更多字段(如光传感器),请继续在此处添加数据
//cmd+=FIELD3;
//cmd+=
//Serial.println(cmd);
//使用AT命令发送数据
Serial.print(“AT+CIPSEND=”);
Serial.println(cmd.length());
if(Serial.find(“>”){
//通过命令发送以更新值
串行打印(cmd);
}否则{
Serial.println(“AT+CIPCLOSE”);
}
if(Serial.find(“OK”)){
//成功!您最近的价值观应该在线。
Serial.println(“数据已发送!”);
返回true;
}否则{
Serial.println(“数据失败!”);
Serial.println(cmd);
返回false;
}
}
布尔连接WiFi(){
//使用AT命令设置ESP8266模式
Serial.println(“AT+CWMODE=1”);
延迟(2000年);
//生成连接命令
字符串cmd=“AT+CWJAP=\”;
cmd+=SSID;
cmd+=“\”,\”;
cmd+=通过;
cmd+=“\”;
//连接到WiFi网络并等待5秒钟
Serial.println(cmd);
延迟(5000);
//如果连接,则返回true,否则返回false
if(Serial.find(“OK”)){
Serial.println(“WIFI连接”);
返回true;
}否则{
Serial.println(“未连接WIFI”);
返回false;
}
}
您必须解决三个问题:去掉delay(),我的意思并不是说你不应该只是不时地调用例程来不影响你的服务器。原因:delay()函数在指定的时间内停止CPU
设置中的OK用于等待某些硬件初始化,OK用于简单例程中的快速测试/调试。在服务器/客户机场景(通信任务与用户任务并行运行)中,这是一个坏主意,在例如带有2个CPU的ESP32上是致命的。一个简短的如何为你的程序
unsigned long previousMillis = 0;
setup() {
....
}
loop(){
if (millis() - previousMillis > DELAY_TIME) { // we check for elapsed time
// What ever needs to be done all DELAY_TIME ms
previousMillis = millis(); // we "reset" the timer
}
// other code which needs no delayed execution
}
同时更改Arduino的代码并将其提升到一个新的级别-第二点:摆脱String类,改用固定字符。
原因String类内存管理不好,导致堆破裂,导致ESP迟早会崩溃,字符被编译为flash,没有这个问题。下面是一个简短的示例,说明如何使用其中一个命令/函数:
// instead of #define API "<REMOVED>" //api String use
const char* API = "<REMOVED>" // pointer to the char API
//Can use a post also
char fixPartGET[128] = '\0'; // takes 255 chars and the terminator, if needed enlarge
char cmd[256] = '\0'; // takes 127 chars and the terminator, if needed enlarge
char numBuffer [16] = '\0'; // we use for float conversions
strcpy (fixPartGET, "GET /update?apikey="); // Copy empties
strcat (fixPartGET, API);
strcat (fixPartGET, "&field1=");
const char* FIELD2 = "&field2=";
setup(){
....
}
loop(){
....
}
bool updateTemp( float c, float h) {
if (WiFi.status() != WL_CONNECTED) {
return false;
}
//build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
strcpy(cmd, fixPartGET); // start building the GET command
// The dtostrf() function converts the double value passed in into an ASCII representation
dtostrf(c, 6, 2, numBuffer); // change to what you need as precision
strcat(cmd, numBuffer);
strcat(cmd, FIELD2);
dtostrf(h, 6, 2, numBuffer); // change to what you need as precision
strcat(cmd, numBuffer);
strcat(cmd, "\r\n");
//continue to add data here if you have more fields such as a light sensor
//strcat(cmd, FIELD3);
//Some other code to discuss
return true;
}
//而不是#define API”“//使用API字符串
const char*API=”“//指向char API的指针
//也可以使用post
char fixPartGET[128]='\0';//助教
unsigned long previousMillis = 0;
setup() {
....
}
loop(){
if (millis() - previousMillis > DELAY_TIME) { // we check for elapsed time
// What ever needs to be done all DELAY_TIME ms
previousMillis = millis(); // we "reset" the timer
}
// other code which needs no delayed execution
}
// instead of #define API "<REMOVED>" //api String use
const char* API = "<REMOVED>" // pointer to the char API
//Can use a post also
char fixPartGET[128] = '\0'; // takes 255 chars and the terminator, if needed enlarge
char cmd[256] = '\0'; // takes 127 chars and the terminator, if needed enlarge
char numBuffer [16] = '\0'; // we use for float conversions
strcpy (fixPartGET, "GET /update?apikey="); // Copy empties
strcat (fixPartGET, API);
strcat (fixPartGET, "&field1=");
const char* FIELD2 = "&field2=";
setup(){
....
}
loop(){
....
}
bool updateTemp( float c, float h) {
if (WiFi.status() != WL_CONNECTED) {
return false;
}
//build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
strcpy(cmd, fixPartGET); // start building the GET command
// The dtostrf() function converts the double value passed in into an ASCII representation
dtostrf(c, 6, 2, numBuffer); // change to what you need as precision
strcat(cmd, numBuffer);
strcat(cmd, FIELD2);
dtostrf(h, 6, 2, numBuffer); // change to what you need as precision
strcat(cmd, numBuffer);
strcat(cmd, "\r\n");
//continue to add data here if you have more fields such as a light sensor
//strcat(cmd, FIELD3);
//Some other code to discuss
return true;
}
#include <DHT.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#define SSID "<REMOVED>" //your network name
#define PASS "<REMOVED>" //your network password
#define API "<REMOVED>" //api string
#define IP "api.thingspeak.com" // thingspeak.com
#define PORT 80
#define DHTPIN 4 // what pin the DHT sensor is connected to
#define DHTTYPE DHT22 // Change to DHT22 if that's what you have
#define BAUD_RATE 115200 //Another common value is 9600
#define DELAY_TIME 300000 //time in ms between posting data to ThingSpeak
DHT dht(DHTPIN, DHTTYPE);
//this runs once
void setup()
{
Serial.begin(BAUD_RATE);
// Connect to WIFI
WiFi.begin(SSID, PASS);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print("*");
}
Serial.println("");
Serial.println("Wifi Connection Successful");
Serial.print("The IP Address of the Sensor is:");
Serial.println(WiFi.localIP());
//initalize DHT sensor
dht.begin();
}
//this runs over and over
void loop() {
float h = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(h);
// Read temperature as Fahrenheit (isFahrenheit = true)
float c = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(c);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(c)) {
Serial.println("Reading DHT22 Failed, exiting");
return;
}
//update ThingSpeak channel with new values
updateTemp(c, h);
//wait for delay time before attempting to post again
delay(DELAY_TIME);
}
bool updateTemp(float tempC, float humid) {
WiFiClient client; // Create a WiFiClient to for TCP connection
if (!client.connect(IP, PORT)) {
Serial.println("HTTP connection failed");
return false;
}
Serial.println("Sending data to server");
if (client.connected()) {
client.print("GET /update?api_key="); client.print(API);
client.print("&field1="); client.print(String(tempC));
client.print("&field2="); client.print(String(humid));
client.println(" HTTP/1.1");
client.print("Host: "); client.println(IP);
client.println("Connection: close");
client.println(); //extra "\r\n" as per HTTP protocol
}
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("HTTP Client Timeout !");
client.stop();
return false;
}
}
Serial.println("Receiving HTTP response");
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
Serial.println();
Serial.println("Closing TCP connection");
client.stop();
return true;
}