Arduino 温度,湿度,PM检测

作者:阿圣(Sfan) 发布于:2013-4-26 13:20 Friday 分类:计算机

    去年就在x宝上买了一套Arduino  的学习套件.一直没做什么东西.

    北京的各种"霾",有了要做一个PM2.5检测小装置的想法.收集各种资料之后.X宝买各种工具和粉尘颗粒传感器.

    基本结构: Arduino +  enc28j60 + Dht11 + GP2Y1010AU0F + nokia 5110 lcd;

    材料: 1.Arduino pro mini  2.ENC28j60以太网模块 3. sharp GP2Y1010AU0F 粉尘传感器 4.DHT11数字温/湿度传感器(这个便宜货精度太差) 5.Nokia 5110 液晶屏模块 6.过线塑料盒 7.各种工具杜帮线.

    功能如下:

                1.读取当前温度,湿度,可入肺颗粒数.并显示出来.

                2.插上网线的话.根据网络环境自动获取IP或设置预设固定IP.并把读取的当前环境数据上传到 yeelink 平台

                3.显示当前时间,日期(时间从网络UTC时间服务器读取)

                4.可以自己定制相关功能.自己烧写程序

 

   上几张图.

点击查看原图

启动状态.右上角一个小图标是网络状态的.

点击查看原图

温/湿度显示.

点击查看原图

PM2.5 显示

 点击查看原图

上传到yeelink平台数据显示

点击查看原图

Enc28j60 ,Arduino pro min ,nokia 5110

点击查看原图

夏普 GP2Y1010AU0F

点击查看原图

点击查看原图

网络接口 和 电源的接口 电源 5V

点击查看原图

粉尘传感器 [GP2Y1010AU0F] 外置 用热熔胶粘在后盖上,可当做整个盒子的支架

点击查看原图

DHT11 温/湿度传感器 内嵌在盒子一侧 盒子顶端预留下载接口 (亲,别吐槽焊工 - -" ,电铬铁神马的都是刚买的有木有)

 

相关代码,库,文档: 写的有点乱

#include <EtherCard.h>
#include <dht11.h>
#include <Time.h>
#include <LCD5110_Graph.h>

#define IN 
#define OUT

char VERSION[] ="v1.8";

//enc28j60
int dcPin=10;
static byte mymac[]={0x74,0x69,0x2D,0x30,0x31};
static byte myip[]={192,168,80,160};
static byte mymask[]={255,255,255,0};
static byte gwip[]={192,168,80,1};
static byte dnsip[]={8,8,8,8};
byte Ethernet::buffer[270];
boolean getDHCP=true;
boolean dnslookup=true;
//enc28j60
Stash stash;

//dht11
dht11 DHT11;
int dht11ReadPin=4;
//dht11

//GP2Y1010AU0F
int dustPin=0;
int ledPower=2;
int delayTime=280;
int delayTime2=40;
float offTime=9680;

int dustVal=0;
int pm_i=0;
float ppm=0;
//char s[32];
float voltage = 0;
static float dustdensity = 0;
float ppmpercf = 0;
int pm2_5=0;
//GP2Y1010AU0F


//yeelink
#define N 3
char website[] PROGMEM="api.yeelink.net";
char APIKey[] PROGMEM = "441033961344aab**************"; //API KEY
char DeviceID[] PROGMEM = "2463";
const uint16_t SensorID[N] = {3277,3278,3279};
char sensorData[N][30];
uint8_t dataLength[N];
//yeelink
uint32_t lastConnectionTime = 0;
const uint16_t PostingInterval = 5000;


//轮流向服务器发送相应传感器变量 0 <= i <N,
uint8_t i=0;//
 
//time
boolean timeNeedSet = true;
uint16_t timeSetTimer = 0;
#define TIME_SET_TIMER 4000 //about TIME_SET_TIMER*5s

//nokia 5110
LCD5110 myGLCD(5,6,7,8,9);
extern uint8_t SmallFont[];
//extern uint8_t TinyFont[];
extern uint8_t BigNumbers[];
//extern uint8_t arduino_logo[];
uint8_t temperature_ico[] PROGMEM={0x02,0x05,0x7A,0x84,0x84,0x48};//
uint8_t net_ico_S[] PROGMEM={0x00,0x03,0x05,0x7D,0x7D,0x05,0x03,0xB8,0xA8,0xE8,0x00,0x00,0x00};
uint8_t net_ico_D[] PROGMEM={0x00,0x03,0x05,0x7D,0x7D,0x05,0x03,0xF8,0x88,0x88,0x70,0x00,0x00};
uint8_t net_ico_err[] PROGMEM={0x00,0xFF,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xFF,0x00,0x00};
uint8_t net_ico_cls[] PROGMEM={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t cls[] PROGMEM={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t pm2_5_ico[] PROGMEM={0x00,0x00,0x00,0xF0,0xF8,0x8C,0x8C,0x8C,0x88,0xF0,0x70,0x00,0x00,0xD0,0x50,0x70,
0x00,0x00,0x00,0x70,0x50,0xD0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3F,0x3F,0x01,0x01,0x39,0x3D,0x08,0x3C,0x08,0x3C,0x39,0x01,0x01,0x00,0x01,
0x00,0x01,0x01,0x01,0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
0x1C,0x10,0x1C,0x00,0x5C,0x54,0x7C,0x00,0x40,0x20,0x1C,0x02,0x39,0x04,0x38,0x04,
0x38,0x04,0x05,0x07,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t sysinit[] PROGMEM={0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8F,0x8F,0x1F,0x1F,0x3D,0xF9,0xF9,0xF3,
0xF7,0x1C,0xFC,0xFC,0xF8,0xC0,0xF0,0xFC,0xFC,0x1C,0x3C,0x7C,0x7C,0x7C,0xEC,0xEC,
0xCC,0x80,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0x01,0xF8,0xFC,0xFC,0xFC,0x1C,0x0C,
0xFC,0xFC,0xFC,0x00,0xFC,0xFC,0xFC,0x04,0x0C,0xFF,0xFF,0xFF,0xFF,0x0C,0x8C,0x80,
0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x80,
0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x01,0x01,0x30,0x30,0x3F,0x3F,0x1F,0x0F,0x03,0x00,0x00,0x03,0x03,
0x03,0x03,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x00,0x01,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x01,0x03,0x03,0x03,0x03,0x00,0x03,0x03,0x03,0x00,0x03,
0x03,0x03,0x00,0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00};
//nokia 5110

void setup()
{
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont);
  Serial.begin(115200);
  //myGLCD.drawBitmap(0, 0, arduino_logo, 84, 48);
 myGLCD.drawLine(0,10,83,10);
 myGLCD.drawLine(70,0,70,10);
 myGLCD.print("--:-- --/--",2,2);
 myGLCD.drawBitmap(0,15, sysinit, 84, 24);
 myGLCD.print(VERSION,55,15);
 myGLCD.drawBitmap(71,1, net_ico_err, 13, 8);
 myGLCD.print("------ By:SFan",0,40);
 myGLCD.update(); 
  pinMode(ledPower,OUTPUT);//ledPower  GP2Y1010AU0F
  Serial.print("Version:");
  Serial.println(VERSION);
  Serial.println("Ethernet init...");
  if(ether.begin(sizeof Ethernet::buffer,mymac,dcPin)==0){
    Serial.println("Failed to access Ethernet controller");  
  }
   else{
     Serial.println("DHCP");
     myGLCD.drawBitmap(71,1, net_ico_D, 13, 8);
     myGLCD.update();
     if(!ether.dhcpSetup()){
     myGLCD.drawBitmap(71,1, net_ico_S, 13, 8);
     myGLCD.update();
     getDHCP=false;
     Serial.println("DHCP failed");
     ether.staticSetup(myip,gwip);
     ether.copyIp(ether.dnsip,dnsip);
     ether.copyIp(ether.mymask,mymask);
     }
     ether.printIp("My IP:",ether.myip);
    // ether.printIp("Netmask:",ether.mymask);
     ether.printIp("GW IP:",ether.gwip); 
     ether.printIp("Dns:",ether.dnsip);  
     if(!ether.dnsLookup(website)){
     myGLCD.drawBitmap(71,1, net_ico_err, 13, 8);
     myGLCD.update();
     dnslookup=false;
     }
     ether.printIp("website:",ether.hisip);
   }

}

void loop()
{
  
  ether.packetLoop(ether.packetReceive());
 // pmLoop();
  if( millis() < lastConnectionTime || millis() - lastConnectionTime > PostingInterval){
    Serial.println(i);
    get_Send_String(i);
    if(dnslookup){
    send_Data(i);
    }else{
    lastConnectionTime=millis();
    }
    i++;
    if (i == N) i=0;  
  }
  
}

static void dht11Read(){
 // Serial.println("\n");
  int chk = DHT11.read(dht11ReadPin);
  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;
  }
  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);
  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature-2, 2);
  myGLCD.drawBitmap(0,15, cls, 84, 25);
  myGLCD.update();
  myGLCD.drawBitmap(35, 30, temperature_ico, 6, 8);
  myGLCD.setFont(SmallFont);
  myGLCD.print("%",73,32);
  myGLCD.setFont(BigNumbers);
  myGLCD.printNumI(DHT11.temperature-2,5,15);
  myGLCD.printNumI(DHT11.humidity,45,15);
  myGLCD.update();
}

static void pmData(){
  pmLoop();
  Serial.println(dustVal);  
  voltage = ppm/pm_i*0.0049;
  dustdensity = 0.17*voltage-0.1;
  ppmpercf = (voltage-0.0256)*120000;
  if (ppmpercf < 0)
    ppmpercf = 0;
  if (dustdensity < 0 )
    dustdensity = 0;
  if (dustdensity > 0.5)
    dustdensity = 0.5;  
  pm_i=0;
  ppm=0;  
  pm2_5=dustdensity*1000;
  Serial.print("voltage :");
  Serial.println(voltage);
  Serial.print("dustdensity :");
  Serial.println(dustdensity);
  Serial.print("ppmpercf :");
  Serial.println(ppmpercf);
  myGLCD.drawBitmap(0,15, cls, 84, 25);
  myGLCD.update();
  myGLCD.drawBitmap(8,15, pm2_5_ico, 30, 24);
  myGLCD.setFont(BigNumbers);
  myGLCD.printNumI(pm2_5,40,15);
  myGLCD.update();
}

void pmLoop(){
  pm_i=pm_i+1;
  digitalWrite(ledPower,LOW); // power on the LED
  delayMicroseconds(delayTime);
  dustVal=analogRead(dustPin); // read the dust value
  ppm = ppm+dustVal;
  delayMicroseconds(delayTime2);
  digitalWrite(ledPower,HIGH); // turn the LED off
  delayMicroseconds(offTime);  
}

void get_Send_String(uint8_t k){ 
 switch(k){
 case 0:{
  dht11Read();
 dataLength[k]=sprintf(sensorData[k],"{\"value\":%d}",DHT11.temperature-2);
 break;} 
 case 1:{
   dht11Read();
  dataLength[k]=sprintf(sensorData[k],"{\"value\":%d}",DHT11.humidity);
  break;}
  case 2:{
    pmData();
   // Serial.println(dustdensity*1000);
    dataLength[k]=sprintf(sensorData[k],"{\"value\":%d}",pm2_5);
  }
 
 }
}

void send_Data(uint8_t j) {
  // Create a Post for yeelink server,
  // and send request saving sessionID
  Serial.println(sensorData[j]);
  Serial.println(SensorID[j]);
  Serial.println();
  Stash::prepare(PSTR("POST /v1.0/device/$F/sensor/$D/datapoints HTTP/1.1" "\r\n" 
    "Host: api.yeelink.net" "\r\n" 
    "U-ApiKey: $F" "\r\n" 
    "Content-Length: $D" "\r\n"
    "Content-Type: application/x-www-form-urlencoded" "\r\n" "\r\n"                       
    "$S" "\r\n"),
  DeviceID,SensorID[i],APIKey,dataLength[i],sensorData[i]);
 
// ether.tcpSend();
  if(timeNeedSet){
    setupTime();      
  }
  else{
    ether.tcpSend();
    displayClock();
  }
  lastConnectionTime = millis();  
}

#define REQEST_TIMEOUT 10000
void setupTime(){
  uint8_t session_id;
  session_id = ether.tcpSend();
  uint32_t requestTimer = millis() + REQEST_TIMEOUT;
  while(millis() < requestTimer){
    ether.packetLoop(ether.packetReceive());
    char bufx[21];
    const char* reply = ether.tcpReply(session_id);
    if(reply !=0){
      for(uint8_t I=0;I<21;I++){
        bufx[I]=reply[50+I];       
      }
      tmElements_t time1;
      timeconvert(bufx,&time1);
      time_t second = makeTime(time1);        
      setTime(second);
      adjustTime(8*60*60);
      timeNeedSet=false;
      break;
    }
  }
}

void displayClock(){
  // digital clock display of the time
  timeSetTimer++;
  if (timeSetTimer>TIME_SET_TIMER) {
    timeSetTimer=0;
    timeNeedSet=true;
  }
    myGLCD.setFont(SmallFont);
    int h=hour();
    int m=minute();
    int mo=month();
    int d=day();
    int x=2;
    if(h<10){
    myGLCD.print("0",x,2);
    x+=6;
    myGLCD.printNumI(h,x,2);
    x+=6;
    }else{
    myGLCD.printNumI(h,x,2);
    x+=12;
    }
    
    myGLCD.print(":",x,2);
    x+=6;
    
    if(m<10){
    myGLCD.print("0",x,2);
    x+=6;
    myGLCD.printNumI(m,x,2);
    x+=6;
    }else{
    myGLCD.printNumI(m,x,2);
    x+=12;
    }
    
    myGLCD.print(" ",x,2);
    x+=6;
    
    if(mo<10){
    myGLCD.print("0",x,2);
    x+=6;
    myGLCD.printNumI(mo,x,2);
    x+=6;
    }else{
    myGLCD.printNumI(mo,x,2);
    x+=12;
    }
    
    myGLCD.print("/",x,2);
    x+=6;
    
    if(d<10){
    myGLCD.print("0",x,2);
    x+=6;
    myGLCD.printNumI(d,x,2);
    x+=6;
    }else{
    myGLCD.printNumI(d,x,2);
    x+=12;
    }
    myGLCD.update();
  Serial.print(year());
  Serial.print("-");
  Serial.print(month());
  Serial.print("-");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());

}
//比较周数,成功返回0-6的数,错误返回7
//p代表周数,取周数前3个字母,如Mon代表周1,以此类推
//改动周几不影响返回的时间值,可以通过改动日期的日数来达到修改时间
 
//比较月份,成功返回0-11的数,错误返回12
//P 为月份的前三个字母,如Feb代表二月,以此类推
int monthcmp( IN char *p)
{
  char *month[]={
    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"            };
 
  int i;
  for(i=0;i<12;i++){
    if(strcmp(p,month[i])==0)
      break;
  }
  if(i==12)
  {
    return i;
  }
  return i;
}
//将字串格式的时间转换为结构体,返回距离1970年1月1日0:0:0的秒数,当字符串格式错误或超值时返回0
//BUF 为类似Tue May 15 14:46:02 2007格式的,p为时间结构体
void timeconvert(IN char *buf,OUT tmElements_t *p)
{
  char cmonth[4];
  int16_t td,th,tm,ts,ty;
  sscanf(buf,"%d %s %d %d:%d:%d",&td,cmonth,&ty,&th,&tm,&ts);
  //sscanf("2012 Aug " ,"%4d %s",&ty,cmonth);
  p->Year = ty - 1970;
  p->Month = monthcmp(cmonth) + 1;
  p->Day = td;
  p->Hour = th;
  p->Minute = tm;
  p->Second = ts;
}

libraries.rar (DHT11,ethercard,LCD5110_Graph 相关库)

gp2y1010au_e.rar (Sharp GP2Y1010AU0F Spec sheet)

Sharp Dust Sensor and Arduino 

 

标签: Arduino

et_highlighter

评论:

TAIT
2016-03-24 15:13
刚好学习中,正是我需要的资料,谢谢。
hardy
2015-05-26 16:24
Serial.println(dustVal);
228
  voltage = ppm/pm_i*0.0049;
229
  dustdensity = 0.17*voltage-0.1;
230
  ppmpercf = (voltage-0.0256)*120000;
231
  if (ppmpercf < 0)
232
    ppmpercf = 0;
233
  if (dustdensity < 0 )
234
    dustdensity = 0;
235
  if (dustdensity > 0.5)
236
    dustdensity = 0.5;
237
  pm_i=0;
238
  ppm=0;
239
  pm2_5=dustdensity*1000;
240
  Serial.print("voltage :");
241
  Serial.println(voltage);
242
  Serial.print("dustdensity :");
243
  Serial.println(dustdensity);
244
  Serial.print("ppmpercf :");
245
  Serial.println(ppmpercf);
246
  myGLCD.drawBitmap(0,15, cls, 84, 25);
247
  myGLCD.update();
248
  myGLCD.drawBitmap(8,15, pm2_5_ico, 30, 24);
249
  myGLCD.setFont(BigNumbers);
250
  myGLCD.printNumI(pm2_5,40,15);
251
  myGLCD.update();
252
}
请问这个算法什么意思
阿圣(Sfan)
2015-05-27 08:59
@hardy:算法来自这边 ,http://www.howmuchsnow.com/arduino/airquality/
飞舞银河
2013-06-04 13:31
请问pro mini和enc28j60是怎么连接的?
阿圣(Sfan)
2013-06-05 21:59
@飞舞银河:是用ISP连的,pro mini 的ISP定义对应是 13:sck,12:miso,11:mosi, 对应接 enc28j60 就行.enc28j60初始化有指定SS/dc Pin:10
zhuce74566@163.com
2013-05-23 21:29
您好 我正在尝试学习使用夏普GP2Y1010AUOF传感器,您写的arduino代码有些我不是很清楚,希望您能指教下我,不胜感激。我的联系方式QQ:21561263

发表评论:

Powered by emlog 湘ICP备08103487号