有几天没写了,这次写一个完整的例子——环境监测。它包含温湿度、火焰、可燃气体检测,并发送数据到乐为网。乐为网用起来比OneNet(中国移动物联网平台)要简单很多,只是很多功能是收费的,但是不用自己开发APP只需关注公众号就可以接收到消息,图简单玩玩体验一下可以尝试。
一、硬件
1、Arduino Uno(如果你要连接很多传感器或者以后还会扩展那么应该选择Mega2560)
2、DHT11(DHT22要准确一些,价格也能接受,两者使用完全一样)
3、火焰传感器
4、可燃气体传感器(我的是MQ9)
5、Esp8266模块(这里用的是AT命令操作比较麻烦)
6、杜邦线、面包板
二、编写程序
这些传感器使用都非常简单,基本都是一根线就可以了。DHT11使用的是DHT库,关于单总线通讯原理可以自行百度一下。火焰和可燃气体传感器都是读取模拟电压——analogRead即可。
简单的解释一下程序中的一些代码:
void upDate() {
ehPost.infos[0].Value =0;
ehPost.infos[1].Value = 0;
ehPost.infos[2].Value = 0;
ehPost.infos[3].Value = 0;
for (int i = 0; i < buffLen;i++) {
ehPost.infos[0].Value += dtBuff[i];
ehPost.infos[1].Value += dhBuff[i];
ehPost.infos[2].Value += flBuff[i];
ehPost.infos[3].Value += mqBuff[i];
}
ehPost.infos[0].Value /= buffLen;
ehPost.infos[1].Value /= buffLen;
ehPost.infos[2].Value /= buffLen;
ehPost.infos[3].Value /= buffLen;
}
该函数用于更新传感器数据,我们知道传感器的数据是有一定的波动的,有时候可能瞬间变为不平滑的曲线,这主要来源于传感器自身、连接线的稳固、供电是否稳定以及是否有强电磁扰动等一些原因。哪怕对于这样简单的工程也要仔细考虑电路的排布,供电的稳定性。消除这些扰动的方法有很多,这里进行了简单的取平均。可以用其他的一些平滑方法,例如缓存数组保存前10秒和后5秒的内容(程序10秒上传一次)——当缓存数组指针达到数组末尾时回到第一个元素。
代码中使用的其他方法都没有太多需要解释的地方,EEPROM部分之前介绍过,所以就不重复。接下来关注一下使用AT命令来控制ESP8266上传数据到乐为物联:
//
//
//
#include "ESP8266SoftwareSerialHTTPPOST.h"
SoftwareSerial wifi_SoftSerial(rxPin, txPin);
ESP8266SoftwareSerialHTTPPOST::ESP8266SoftwareSerialHTTPPOST()
{
wifi_SoftSerial.begin(9600);
}
int ESP8266SoftwareSerialHTTPPOST::initESP8266()
{
int errcnt = 0;
if (!doATCommand(F("AT+CIPMODE=1"), deftStr, deffStr, 10)) { errcnt++; }
if (!doATCommand(F("AT+RST"), deftStr, deffStr, 100)) { errcnt++; }
if (!doATCommand(F("AT+CIPMUX=0"), deftStr, deffStr, 10)) { errcnt++; }
if (!doATCommand(F("AT+CWMODE=1"), deftStr, deffStr, 10)) { errcnt++; }
return errcnt;
}
bool ESP8266SoftwareSerialHTTPPOST::initWifi()
{
//测试Wifi连接
if (!doATCommand(F("AT+CWJAP?"),wifi_ssid, F("No AP"),100)) {
//连接到WIFI
if (!doATCommand("AT+CWJAP=\"" + wifi_ssid + "\",\"" + wifi_password + "\"", deftStr,deffStr,10000)) {
Serial.println(F("AT+CWJAP:ERROR:"));
Serial.println(resultLine);
return false;
}
}
return true;
}
bool ESP8266SoftwareSerialHTTPPOST::httpPost()
{
bool result = true;
//连接服务器
result = doATCommand("AT+CIPSTART=\"TCP\",\"" + HostAddress + "\"," + HostPort, deftStr, deffStr, 1000);
if (!result) {
Serial.println(F("AT+CIPSTART:ERROR:"));
Serial.println(resultLine);
return false;
}
/*
POST /api/V1/gateway/Updatesensors/01 HTTP/1.1
userkey:000009999778878979789
Host:www.lewei50.com
Content-Length:30
[{"Name":"H1","Value":"22"}]
*/
String curData = mathData();
//Post数据
result = postString("POST " + HostApiPath + " HTTP/1.1" );
if (result) {
result = postString("userkey:" + UserKey );
}
if (result) {
result = postString("Host: " + HostAddress );
}
if (result) {
result = postString("Content-Length:" + (String)curData.length());
}
if (result) {
result = postString("");
}
if (result ) {
result = postString(curData);
}
curData = "";
//退出透传
doATCommand(F("+++"), deftStr, deffStr, 20);
//关闭TCP/UDP连接
doATCommand(F("AT+CIPCLOSE"), deftStr, deffStr, 20);
return result;
}
bool ESP8266SoftwareSerialHTTPPOST::doATCommand(String cmd, String tStr, String fStr, unsigned long outTime)
{
unsigned long LastTime = 0UL; //过去的时间
unsigned long StartTime; //开始时间
int result = -1;
//发送命令
wifi_SoftSerial.println(cmd);
//等待数据返回
while (result==-1)
{
StartTime = micros();
if (wifi_SoftSerial.available()>0) {
while (wifi_SoftSerial.available()>0)
{
resultLine = wifi_SoftSerial.readStringUntil('\n') + '\n';
//Serial.print(resultLine);
if (resultLine.lastIndexOf(tStr)>-1) {
result = 0;
}
if (resultLine.lastIndexOf(fStr)>-1) {
result = 1;
}
}
}
LastTime += micros()-StartTime; //增加经过的时间
if (LastTime > outTime*1000) {
break;
}
}
delay(100);
return result == 0;
}
String ESP8266SoftwareSerialHTTPPOST::mathData()
{
String curData = "[";
int count = sizeof(infos) / sizeof(infos[0]);
for (int i = 0; i<count; i++)
{
curData += "{\"Name\":\"" + (String)infos[i].Name + "\",\"Value\":\"" + (String)infos[i].Value + "\"},";
}
curData[curData.length()-1]= ']';
return curData;
}
bool ESP8266SoftwareSerialHTTPPOST::postString(String line)
{
if (doATCommand("AT+CIPSEND=" + (String)(line.length()+2), ">", deffStr, 1000)) {
if (doATCommand(line, F("SEND OK"), F("FAIL"), 1000)) {
return true;
}
else {
Serial.println(F("Send:err"));
Serial.println(resultLine);
}
}
else {
Serial.println("Post:ERROR" + Crlf + line + Crlf + line.length());
Serial.println(resultLine);
}
return false;
}
这部分代码相对长一些,最好对照AT命令表来进行查看。首先,我们进入透传模式,所谓的透传就是我们发送给ESP8266什么内容,ESP8266就发送什么内容给服务器。而后进行身份验证、上传数据、等待返回、退出透传并关闭连接。整个过程中会遇到非常多的问题,例如数据包走丢了、服务器睡着了、ESP8266帕金森了……所以我们需要处理超时,这非常重要在DoCommand函数中我们进行计时,如果超时那么就返回失败,否则很可能程序不知道跑了几分钟就翘辫子。
下面附上完整的程序代码,传感器和ESP8266连接都非常简单,自行百度教程很多。

本文详细介绍了一个基于Arduino Uno、多种传感器及ESP8266模块的环境监测系统搭建过程。系统可检测温湿度、火焰和可燃气体,并通过ESP8266将数据上传至乐为网。文章提供了传感器连接指导、程序代码解析及AT命令控制ESP8266的具体实现。

被折叠的 条评论
为什么被折叠?



