前面几篇介绍了一些传感器和代码,这篇介绍一下把它们组合起来。之所以单独列出这部分,原因在于组合更多功能的时候发现使用软串口库驱动ESP8266时由于内存过小导致发送失败甚至整个系统无法工作的情况。所以,我只组合了DHT11、火焰传感、MQ-9这几个传感器。今天优化了ESP8266部分的代码之后,实际测试时还可以用起一个GP2Y10,再多就不行了,而且包括DHT11、GP2Y10都不是使用现成的库文件,而是自己写了一些代码。暂时确实没有更多精力去自己写软串口通讯的部分了。首先看一下DHT11的代码:
// DHT11SimpleRead.h #ifndef _DHT11SIMPLEREAD_h #define _DHT11SIMPLEREAD_h #if defined(ARDUINO) && ARDUINO >= 100 #include "arduino.h" #else #include "WProgram.h" #endif class DHT11SimpleRead { public: DHT11SimpleRead(unsigned int p); bool read(); float temperature=5.0; float humidity=50.0; private: unsigned int pin; unsigned int bits[5]; }; #endif
// // // #include "DHT11SimpleRead.h" DHT11SimpleRead::DHT11SimpleRead(unsigned int p) { pin = p; } bool DHT11SimpleRead::read() { int cnt = 7; int idx = 0; //发送命令开始工作 pinMode(pin, OUTPUT); digitalWrite(pin, LOW); delay(20); //至少18毫秒拉低 digitalWrite(pin, HIGH); delayMicroseconds(40); //20-40微秒拉高 //转换到主机接收 pinMode(pin, INPUT); unsigned int loopCnt = 10000; //等待80微秒左右的拉高结束 while (digitalRead(pin) == LOW) if (loopCnt-- == 0) return; loopCnt = 10000; //等待80微秒左右的拉低结束 while (digitalRead(pin) == HIGH) if (loopCnt-- == 0) return; //开始接收40位数据 for (int i = 0; i<40; i++) { loopCnt = 10000; while (digitalRead(pin) == LOW) //每一位都是从低开始,当低结束时,根据电平长短来确定是0还是1 if (loopCnt-- == 0) return; unsigned long t = micros(); //开始计时 loopCnt = 10000; while (digitalRead(pin) == HIGH) //等待新号变低的时间决定了位的高低 if (loopCnt-- == 0) return; if ((micros() - t) > 40) bits[idx] |= (1 << cnt); //一般,26-28微秒是0,29-70微秒是1 //接收满8位开始下一字节 if (cnt == 0) { cnt = 7; idx++; } else cnt--; } //传输完成之后,DHT11会拉低单总线50微秒。不处理了。 //接收完成写入数据 temperature = bits[2]; humidity= bits[0]; //进行校验 return (unsigned int)bits[0] + bits[1] + bits[2] + bits[3] == (unsigned int)bits[4]; }
根据时序写驱动并不是很麻烦。这样就得到了两个数值,今天在测试的时候发现有时读取的值并不正确,但是刚刚上电的时候是正确的,反复检查并优化了一些代码之后没有再出现这个问题,如果再出现可能就是电路设计有问题了。
然后针对ESP8266发送数据比较长进行了一点优化,当然这部分完全可以做的更好一些,但是感觉没有什么必要了,毕竟就是当一个玩意玩的,即使付出更多努力结果可能也只是多加一个传感器——而我并不打算得到温湿度、火焰、燃气以外的数据。包括颗粒物传感器,我也只是打算放到另一块Arduino上,与语音识别和红外发射放到一起做一个简单的语音控制器来控制一些红外遥控的设备,例如自动开关空气净化,语音控制电视、窗帘等。这个优化主要是针对POST部分的数据比较长,把它按行拆开透传;也可以限定每次透传的数据量。当然,无论如何,减少字符串占用的堆栈、尽早的回收它们是努力的方向:
bool ESP8266SoftwareSerialHTTPPOST::postString(String line) { if (doATCommand("AT+CIPSEND=" + (String)(line.length()+2), ">", deffStr, 1000)) { if (doATCommand(line, "SEND OK", "FAIL", 1000)) { return true; } else { Serial.println("Send:err"); Serial.println(resultLine); } } else { Serial.println("Post:ERROR" + Crlf + line + Crlf + line.length()); Serial.println(resultLine); } return false; }
需要注意的是,长度的计算多2字节,因为我使用的是println,而line并没有加上 。
另外,为了加速处理,除了原来对正确返回值"OK“等、超时处理之外,也对"ERROR"、"No AP"等进行了处理,这样可以快速从对串口的等待中返回。
最后,对这些功能进行组合,得到的结果还是比较令人满意的,它已经连续工作了12小时以上,并没有出现什么其他问题。