极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 20669|回复: 9

DHT22+PPD42NS+Arduino+Yeelink 问题请教

[复制链接]
发表于 2015-4-11 14:15:42 | 显示全部楼层 |阅读模式
根据网上的教程拼凑了一段通过DHT22和PPD42NS向Yeelink发送家庭温湿度和室内颗粒物的程序,但是颗粒物的数据始终无法正确获得(传感器和接线都没问题,因为单独使用PPD42S的例程是可以显示颗粒物浓度的),温湿度数据倒是可以正确获得并上传yeelink,本人对编程一窍不通,请各位高手看一下是哪里不对,谢谢....


#include <SPI.h>
#include <Ethernet.h>
#include <DHT22.h>

#define DHT22_PIN 3 //DHT22 连接UNO PIN3
DHT22 myDHT22(DHT22_PIN);

#define APIKEY         "**************************" // replace your yeelink api key here
#define DEVICEID                ***** // replace your device ID
#define TEMPERATURE_SENSORID    ***** // temperature
#define HUMIDITY_SENSORID       ***** //humidity
#define DUST_SENSORID          ***** //dust

int dustpin = 7;    //PPD42NS  连接UNO PIN 7
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;

// assign a MAC address for the ethernet controller.
byte mac[] = { 0x00, 0x1D, 0x72, 0x82, 0x35, 0x9D};
// initialize the library instance:
EthernetClient client;
char server[] = "api.yeelink.net";   // name address for yeelink API

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 30*1000; // delay between 2 datapoints, 30s


int sensor = 0;   //which sesor to read
                  //0 temperature
                  //1 humidity
                  //2 dust


void setup()
{
  Serial.begin(9600);
  pinMode(dustpin,INPUT);
  starttime = millis();
   
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    for(;;)
      ;
  }
  else {
    Serial.println("Ethernet configuration OK");
  }


}

void loop()
{

  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    // read sensor data, replace with your code
    //int sensorReading = readLightSensor();
    //int tempC = analogRead(0)*500/1024;
    //send data to server


      switch(sensor){
        case 0:
          sendData(readSensor(HUMIDITY_SENSORID), HUMIDITY_SENSORID);
          break;
        case 1:
          sendData(readSensor(TEMPERATURE_SENSORID), TEMPERATURE_SENSORID);
          break;
        case 2:
          sendData(readSensor(DUST_SENSORID), DUST_SENSORID);
          break;
      }

      if(++sensor > 2) sensor = 0;


  }
  // store the state of the connection for next time through
  // the loop:
  //

  lastConnected = client.connected();
}

int readSensor(long sensor_id){
  Serial.println("\n");
        
   if (sensor_id == DUST_SENSORID)
  {
      duration = pulseIn(dustpin, LOW);
      lowpulseoccupancy = lowpulseoccupancy+duration;

       if ((millis()-starttime) > sampletime_ms)
      {
        ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100
        concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
        Serial.print("Dust Density (pcs/cf): ");
        Serial.println(concentration);
        lowpulseoccupancy = 0;
        starttime = millis();
        return concentration;
      }  
  }

  DHT22_ERROR_t errorCode; //定义errorCode接受错误代码
  errorCode = myDHT22.readData(); //读取errorCode
  
  Serial.print("Read sensor: ");
  switch(errorCode)
  {
     case DHT_ERROR_NONE:
                Serial.println("OK");
                break;
     case DHT_ERROR_CHECKSUM:
                Serial.println("Check sum error");
                break;
     case DHT_BUS_HUNG:
                Serial.println("BUS Hung");
                break;
     case DHT_ERROR_NOT_PRESENT:
                Serial.println("Not Present ");
                break;
     case DHT_ERROR_ACK_TOO_LONG:
                Serial.println("ACK time out ");
                break;
     case DHT_ERROR_SYNC_TIMEOUT:
                Serial.println("Sync Timeout ");
                break;
     case DHT_ERROR_DATA_TIMEOUT:
                Serial.println("Data Timeout ");
                break;
     case DHT_ERROR_TOOQUICK:
                Serial.println("Polled to quick ");
                break;
  }
   
  if(sensor_id == HUMIDITY_SENSORID){
    Serial.print("Humidity (%): ");
    Serial.println(myDHT22.getHumidity());
    return myDHT22.getHumidity();
  }else{
    Serial.print("Temperature (C): ");
    Serial.println(myDHT22.getTemperatureC());
    return myDHT22.getTemperatureC();
  }
        
}


void sendData(int thisData, long sensor_id) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.print("POST /v1.1/device/");
    client.print(DEVICEID);
    client.print("/sensor/");
    client.print(sensor_id);
    client.print("/datapoints");
    client.println(" HTTP/1.1");
    client.println("Host: api.yeelink.net");
    client.print("Accept: *");
    client.print("/");
    client.println("*");
    client.print("U-ApiKey: ");
    client.println(APIKEY);
    client.print("Content-Length: ");

    // calculate the length of the sensor reading in bytes:
    // 8 bytes for {"value":} + number of digits of the data:
    int thisLength = 10 + getLength(thisData);
    client.println(thisLength);

    client.println("Content-Type: application/x-www-form-urlencoded");
    client.println("Connection: close");
    client.println();

    // here's the actual content of the PUT request:
    client.print("{\"value\":");
    client.print(thisData);
    client.println("}");
  }
  else {
    // if you couldn't make a connection:
    //

    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }
   // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}

// This method calculates the number of digits in the
// sensor reading.  Since each digit of the ASCII decimal
// representation is a byte, the number of digits equals
// the number of bytes:
int getLength(int someValue) {
  // there's at least one byte:
  int digits = 1;
  // continually divide the value by ten,
  // adding one to the digit count for each
  // time you divide, until you're at 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }
  // return the number of digits:
  return digits;
}
回复

使用道具 举报

发表于 2015-4-11 17:59:02 | 显示全部楼层
我也刚刚学,看不出错在那
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-11 18:17:53 | 显示全部楼层
很高兴看到有人回复,谢谢.....应该就是下面这段有问题, 算出来的ratio值一直是0


if (sensor_id == DUST_SENSORID)
   {
       duration = pulseIn(dustpin, LOW);
       lowpulseoccupancy = lowpulseoccupancy+duration;

        if ((millis()-starttime) > sampletime_ms)
       {
         ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100
         concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
         Serial.print("Dust Density (pcs/cf): ");
         Serial.println(concentration);
         lowpulseoccupancy = 0;
         starttime = millis();
         return concentration;
       }  
   }
回复 支持 反对

使用道具 举报

发表于 2015-4-16 09:09:47 | 显示全部楼层
rexon 发表于 2015-4-11 18:17
很高兴看到有人回复,谢谢.....应该就是下面这段有问题, 算出来的ratio值一直是0

我也遇到相同问题:单独使用红外距离传感器的例程可以上传,多个传感器同时工作,红外不能上传
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-16 13:49:09 | 显示全部楼层
suoma 发表于 2015-4-16 09:09
我也遇到相同问题:单独使用红外距离传感器的例程可以上传,多个传感器同时工作,红外不能上传

我用夏普的灰尘传感器GP2Y1010AU0F替换PPD42NS倒是可以同时上传温湿度和颗粒物密度的。因为PPD42NS获取颗粒物密度需调用millis()指令,而上传Yeelink的程序里也调用这个指令,我试过将starttime = millis(); 这个语句放在不同的位置出来的结果也不一样。本人实在没什么编程基础看不出来问题到底在哪?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-16 13:51:55 | 显示全部楼层
另外所有数据都是可以上传Yeelink的,只是上传的颗粒物密度都是错误的
回复 支持 反对

使用道具 举报

发表于 2015-4-16 15:02:14 | 显示全部楼层
suoma 发表于 2015-4-16 09:09
我也遇到相同问题:单独使用红外距离传感器的例程可以上传,多个传感器同时工作,红外不能上传

期待你早日解决
回复 支持 反对

使用道具 举报

发表于 2015-4-17 03:18:54 | 显示全部楼层
rexon 发表于 2015-4-16 13:49
我用夏普的灰尘传感器GP2Y1010AU0F替换PPD42NS倒是可以同时上传温湿度和颗粒物密度的。因为PPD42NS获取颗 ...




因为该 Dust sensor 测量方式是:
   计算 lowpulseoccupancy =  LOW 的时间 ; 总共测量 30 秒
    该 LOW 时间的来源是 累加 pulseIn(dustpin, LOW);
   注意 duration = pulseIn(dustpin, LOW); 意思是
     等待 dustpin 变 LOW, 开始计时, 如果一开始就 LOW, 则立即开始计时,
     注意此时 pulseIn(dustpin, LOW) 不会回来,
     会一直等到 dustin 变 HIGH 才会回来,
     此时回传 pulseIn( ) 这函数停留看到 dustpin 是 LOW 的时间( 几个 ms);
   依照原范例的意思是:
     必须看看 30秒内 (30000 ms), 该 pin 在 LOW 的时间是几个 ms,
     此即 lowpulseoccupancy,
     注意该句子  lowpulseoccupancy = lowpulseoccupancy+duration; 就是在累加 dustpin 是 LOW 的时间!
     然后 ratio = lowpulseoccupancy/( 30000*10.0);
   换句话说,
   原则上在该 30 秒内必须"相当专心" 看着 dustpin 的变化, 不可以去做别的事情,
   否则你想想看,
   在该 30 秒内 dustpin 可能变化了 100次, 然后你因做其他事,
   只来看了一次或两次, 漏掉了其他九十九次或九十八次 dustpin 变为 LOW  的时间 !!
   这样除以 ( 30000*10.0) 当然得到 0 啦 !
所以,
解决方法是, 遇到要量测 Dust sensor, 就专心测量 30 秒:
写成函数如下:
/// 先把你那个 if 改为如下调用 concentAns( ) 函数比较容易看懂 !
   if (sensor_id == DUST_SENSORID)
   {
      return (int)concentAns( );  // 因为你的函数是 int
   }

////// 把使用到以下函数写到整个程序最后面, 不要混入其他函数喔 !
////// 函数如下:
float concentAns( ) {  // 计算 concentration; 注意会花掉 30 秒
   lowpulseoccupancy = 0; // dustpin 是 LOW 的时间
   starttime = millis();
   while(38==38) { // loop forever, 用里面的 if 判断是否做完 30 秒了
      duration = pulseIn(dustpin, LOW);
      lowpulseoccupancy = lowpulseoccupancy+duration;
      if ((millis()-starttime) > sampletime_ms) break; // 离开 while Loop
   } // while(38==38
   // 已经量测 30 秒 (sampletime_ms), 检查 dustpin 在 LOW 的时间总共占的比率 ratio
   ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100
   concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
   Serial.print("Dust Density (pcs/cf): ");
   Serial.println(concentration);
   return concentration;   // 你的 concentration 是 float, 所以我写成 float 函数
} // float  concentAns(

回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-17 07:16:23 | 显示全部楼层
tsaiwn 发表于 2015-4-17 03:18
因为该 Dust sensor 测量方式是:
   计算 lowpulseoccupancy =  LOW 的时间 ; 总共测量 30 秒
   ...

太好了,刚起床就看到你的回复,程序更新后运行完美,非常感谢! 先上班去咯,回头再慢慢研究。。。。。
回复 支持 反对

使用道具 举报

发表于 2016-5-24 16:24:44 | 显示全部楼层
版主  寫不進去呢 !
想詢問  一次要用開關與溫度要怎樣上傳YEELINK
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-15 14:39 , Processed in 0.040778 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表