ESP8266 DHT11 OneNET 舵机控制 - Arduino 代码解析与优化

本代码使用ESP8266和DHT11传感器采集温度湿度数据,并将数据上传到OneNET平台,同时根据OneNET平台的光线数据流的值控制舵机的的位置。

代码解析

//引入ESP8266.h头文件,建议使用教程中修改后的文件
#include 'ESP8266.h'
#include 'dht11.h'
#include 'SoftwareSerial.h'
#include<WiFi.h>
#include<Servo.h>

//配置ESP8266WIFI设置
#define SSID 'HONOR Play4T'    //填写2.4GHz的WIFI名称,不要使用校园网
#define PASSWORD '12345678'//填写自己的WIFI密码
#define HOST_NAME 'api.heclouds.com'  //API主机名称,连接到OneNET平台,无需修改
#define DEVICE_ID '1099655073'       //填写自己的OneNET设备ID
#define HOST_PORT (80)                //API端口,连接到OneNET平台,无需修改
String APIKey = 'IiJSs17atNND2C77wumz03w63hw='; //与设备绑定的APIKey
String lightDatastreamId = 'light'; //光线数据流ID
#define INTERVAL_SENSOR 5000 //定义传感器采样及发送时间间隔

//创建dht11示例

dht11 DHT11;
//创建舵机
Servo myservo;
int servoPin=7;
int light=0;
int servoPos=0;
//定义DHT11接入Arduino的管脚
#define DHT11PIN 4

//定义ESP8266所连接的软串口
/*********************
 * 该实验需要使用软串口
 * Arduino上的软串口RX定义为D3,
 * 接ESP8266上的TX口,
 * Arduino上的软串口TX定义为D2,
 * 接ESP8266上的RX口.
 * D3和D2可以自定义,
 * 但接ESP8266时必须恰好相反
 *********************/
SoftwareSerial mySerial(3, 2);
ESP8266 wifi(mySerial);

 void handleCommand(String command) {
  Serial.print('Command received: ');
  Serial.println(command);

  if (command == '0') { //控制舵机转到0度位置
    myservo.write(0);
    servoPos = 0;
    light=0;
    Serial.println('Servo position: 0');
    myservo.write(servoPos);
  } 
   else if (command == '1') { //控制舵机转到180度位置
    myservo.write(180);
    servoPos = 180;
    light=1;
    Serial.println('Servo position: 180');
    myservo.write(servoPos);
  } else {
    Serial.println('Invalid command');
  }
}


void setup()
{
  mySerial.begin(115200); //初始化软串口
  Serial.begin(9600);     //初始化串口
  Serial.print('setup begin\r\n');

   myservo.attach(servoPin);
   myservo.write(0);
   
  //以下为ESP8266初始化的代码
  Serial.print('FW Version: ');
  Serial.println(wifi.getVersion().c_str());

  if (wifi.setOprToStation()) {
    Serial.print('to station ok\r\n');
  } else {
    Serial.print('to station err\r\n');
  }

  //ESP8266接入WIFI
  if (wifi.joinAP(SSID, PASSWORD)) {
    Serial.print('Join AP success\r\n');
    Serial.print('IP: ');
    Serial.println(wifi.getLocalIP().c_str());
  } else {
    Serial.print('Join AP failure\r\n');
  }
  Serial.println('');
  Serial.print('DHT11 LIBRARY VERSION: ');
  Serial.println(DHT11LIB_VERSION);

  mySerial.println('AT+UART_CUR=9600,8,1,0,0');
  mySerial.begin(9600);
  Serial.println('setup end\r\n');
  
}

unsigned long net_time1 = millis(); //数据上传服务器时间
unsigned long net_time2= millis(); //获取命令时间
void loop(){

  if (net_time1 > millis())
    net_time1 = millis();
  
  if (millis() - net_time1 > INTERVAL_SENSOR) //发送数据时间间隔
  {

    int chk = DHT11.read(DHT11PIN);

    Serial.print('Read sensor: ');
    switch (chk) {
      case DHTLIB_OK:
        Serial.println('OK');
        break;
      case DHTLIB_ERROR_CHECKSUM:
        Serial.println('Checksum error');
        break;
      case DHTLIB_ERROR_TIMEOUT:
        Serial.println('Time out error');
        break;
      default:
        Serial.println('Unknown error');
        break;
    }

    /*float sensor_hum = (float)DHT11.humidity;
    float sensor_tem = (float)DHT11.temperature;
    Serial.print('Humidity (%): ');
    Serial.println(sensor_hum, 2);

    Serial.print('Temperature (oC): ');
    Serial.println(sensor_tem, 2);
    Serial.println('');

    if (wifi.createTCP(HOST_NAME, HOST_PORT)) { //建立TCP连接,如果失败,不能发送该数据
      Serial.print('create tcp ok\r\n');
      char buf[10];

      //拼接发送data字段字符串
      String jsonToSend = '{\'Temperature\':';
      dtostrf(sensor_tem, 1, 2, buf);
      jsonToSend += '\'' + String(buf) + '\'';
      jsonToSend += ',\'Humidity\':';
      dtostrf(sensor_hum, 1, 2, buf);
      jsonToSend += '\'' + String(buf) + '\'';
      jsonToSend += '}';

      //拼接POST请求字符串
      String postString = 'POST /devices/';
      postString += DEVICE_ID;
      postString += '/datapoints?type=3 HTTP/1.1';
      postString += '\r\n';
      postString += 'api-key:';
      postString += APIKey;
      postString += '\r\n';
      postString += 'Host:api.heclouds.com\r\n';
      postString += 'Connection:close\r\n';
      postString += 'Content-Length:';
      postString += jsonToSend.length();
      postString += '\r\n';
      postString += '\r\n';
      postString += jsonToSend;
      postString += '\r\n';
      postString += '\r\n';
      postString += '\r\n';

      const char *postArray = postString.c_str(); //将str转化为char数组

      Serial.println(postArray);
      wifi.send((const uint8_t *)postArray, strlen(postArray)); //send发送命令,参数必须是这两种格式,尤其是(const uint8_t*)
      Serial.println('send success');*/

//请求获取光线数据流的值
      String getCmd = 'GET /devices/1099655073/datastreams?datastreams_id=light HTTP/1.1\r\napi-key:IiJSs17atNND2C77wumz03w63hw=\r\nHost: api.heclouds.com\r\nConnection: close\r\n\r\n';
   
      wifi.send((const uint8_t *)getCmd.c_str(), getCmd.length());
      Serial.println('get light datastream value');

      uint8_t buffer[512] = {0};
      uint32_t len = wifi.recv(buffer, sizeof(buffer), 20000);
      
        Serial.print(F('['));
        for (uint32_t i = 0; i < len; i++) {
          Serial.print((char)buffer[i]);
        }
        Serial.println(F(']'));

        String datastreamValue = '';
        for (uint32_t i = 0; i < len; i++) {
          if (buffer[i] == ':') { //找到冒号,说明值在冒号后面
            i += 2; //跳过冒号和引号
            while (buffer[i] != ''') { //找到下一个引号,说明值的结束
              datastreamValue += (char)buffer[i];
              i++;
            }
            break; //找到值后退出循环
          }
        }

        Serial.print('Light value: ');
        Serial.println(datastreamValue);

        if (datastreamValue == '1') { //根据光线值控制舵机位置
          handleCommand('1');
        } else {
          handleCommand('0');
        }
      
     
      if (wifi.releaseTCP()) { //释放TCP连接
        Serial.print('release tcp ok\r\n');
      } else {
        Serial.print('release tcp err\r\n');
      }
//postArray = NULL; 
}//清空数组,等待下次传输数据

    Serial.println('');
 net_time1 = millis();
  } wifi.recv为什么不能给buffer输入数据
  
          内容:根据代码的逻辑,wifi.recv()函数是用来接收从OneNET平台返回的数据的,需要传入一个指向接收数据缓存区的指针(即buffer),并指定接收数据的最大长度。如果函数成功接收到数据,则返回接收到的数据长度。因此,应该在调用wifi.recv()函数之前,先定义一个缓存区,并确保其大小足够存放接收到的数据。如果缓存区大小不够,可能会导致接收到的数据被截断,或者程序崩溃。在代码中,定义了一个大小为512的缓存区,用来存放从OneNET平台返回的数据。如果wifi.recv()函数不能给buffer输入数据,可能是因为缓存区大小不够,或者网络连接出现了问题。可以尝试增大缓存区的大小,或者检查网络连接是否正常。

优化建议

  1. 代码规范性: 使用更加规范的代码格式,例如使用缩进、空格等,使代码更易读。
  2. 注释清晰: 完善代码注释,解释每个代码段的功能,方便理解代码逻辑。
  3. 优化数据上传: 代码中原本存在数据上传的功能,但是被注释掉了。建议重新启用数据上传功能,并优化上传数据格式,例如使用JSON格式,方便数据解析。
  4. 错误处理: 代码中缺少错误处理机制,例如网络连接错误、数据接收错误等。建议添加相应的错误处理代码,提高代码的稳定性。
  5. 调试工具: 使用串口调试工具,观察代码执行过程中的输出信息,帮助定位和解决问题。
  6. 平台文档: 仔细阅读OneNET平台的文档,了解如何使用OneNET平台的API,以及数据上传和接收的规范。

通过以上优化,可以提高代码的质量和效率,使代码更易于理解和维护。

wifi.recv() 函数问题

代码中wifi.recv() 函数用来接收从OneNET平台返回的数据。如果该函数不能给buffer 输入数据,可能是以下原因:

  1. 缓存区大小不够: buffer 的大小为512字节,可能不足以存放接收到的所有数据。尝试增大buffer 的大小。
  2. 网络连接问题: 检查网络连接是否正常,例如WiFi连接是否稳定。
  3. OneNET平台问题: 检查OneNET平台是否正常工作,例如是否有错误消息提示。
  4. 数据接收超时: wifi.recv() 函数设置了超时时间,如果在超时时间内没有接收到数据,则会返回0。尝试增大超时时间,或者检查代码逻辑是否正确。

建议尝试以上方法解决wifi.recv() 函数不能给buffer 输入数据的问题。

总结

本代码通过ESP8266、DHT11传感器和舵机实现了温度湿度数据采集和远程控制的功能,并使用了OneNET平台进行数据上传和接收。通过对代码进行解析和优化,可以更深入地了解代码逻辑,并提高代码质量和效率。

希望本代码能够帮助您理解ESP8266、DHT11传感器、OneNET平台和舵机的工作原理,并成功实现自己的项目。

ESP8266 DHT11 OneNET 舵机控制  - Arduino 代码解析与优化

原文地址: https://www.cveoy.top/t/topic/oMxf 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录