极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 73758|回复: 48

【第二弹】基于dht22+dsm501A+enc28J60+arduino+lcd1602+yeelink+实现家居环境监控

[复制链接]
发表于 2012-8-29 08:35:16 | 显示全部楼层 |阅读模式
本帖最后由 zcbzjx 于 2012-9-3 10:13 编辑

2012年9月3日:更新dhcp租约到期问题。

上一次做了个基于18B20+enc28j60+arduino+yeelink的远程温度监控,觉得yeelink这个平台还凑合,能很好的展示和记录各个机房温度值,超过阈值还能激活email和新浪微博进行提醒,详细请看北京联合大学生物化学工程学院网络机房远程监控系统,enc28j60以平易的价格够用(10M)的带宽也基本能满足需求,性能稳定。所以这次也以这个模块和yeelink平台当然还有arduino做了个家居环境监控系统。lcd实时显示,第一排显示温度 湿度 灰尘浓度,第二排显示实时时间,这个时间自动和internet时间校准,大概间隔 TIME_SET_TIMER*5s,我程序设置的是4000*5s也就是差不多5个半小时自动校准一次。

硬件同样看图。洞洞板,估计也只有我能看明白。不过这次用eagle6.1.0做了个原理图。


代码:[pre lang="arduino" line="1" file="ethercard_dsm501_00_sujudian_lcd_dns.ino"]/*
Yeelink sensor client
by zcb
2012.08.27
*/
#include <EtherCard.h>
#include <dht.h>
#include <LiquidCrystal.h>
#include <Time.h>

#define IN
#define OUT

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

#define DHT_PIN A0
#define DSM_PIN_10 A4
#define DSM_PIN_25 A2

///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
////传感器个数及对应传感器ID
#define N 4
const uint16_t PostingInterval = 5000;
// 发送到服务器时间间隔,N大了可以适当缩短,
//每个传感器发送时间间隔为PostingInterval*N

const uint16_t SensorID[N] = {
  XXX,XXX,XXX,XXX}; // replace your sensor ID

const uint8_t MyMac[6] = {
  0x74,0x69,0x69,0x20,0x07,0xAA };

////////////////////////////////////////////////////////////

// for yeelink api
char APIKey[] PROGMEM = "XXXXXXXXXXXXXXXXXXXXXXX"; // replace your yeelink api key here
char DeviceID[] PROGMEM = "XXX"; // replace your device ID


// 固定的网关

char website[] PROGMEM = "api.yeelink.net";


uint32_t lastConnectionTime = 0;          // last time you connected to the server, in milliseconds

//上传数据的字符串变量及字符串长度变量
char sensorData[N][30];
uint8_t dataLength[N];

uint8_t Ethernet::buffer[700];
Stash stash;

//ASM2302
DHT sensor = DHT();

//轮流向服务器发送相应传感器变量 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


void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);

  // start serial port:
  // start the Ethernet connection:
  if (ether.begin(sizeof Ethernet::buffer, MyMac) == 0)
    Serial.println( "Failed to access Ethernet controller");

  Serial.println("Setting up DHCP");
  if (!ether.dhcpSetup())
    Serial.println( "DHCP failed");

  ether.printIp("My IP: ", ether.myip);
  ether.printIp("Netmask: ", ether.mymask);
  ether.printIp("GW IP: ", ether.gwip);
  ether.printIp("DNS IP: ", ether.dnsip);
  ether.dnsLookup(website);
  sensor.attach(DHT_PIN);

  pinMode(DSM_PIN_10, INPUT);

}

void loop() {
  if (!ether.dhcpValid() && !ether.dhcpSetup())
Serial.println("DHCP failed");
  ether.packetLoop(ether.packetReceive());
  if( millis() < lastConnectionTime || millis() - lastConnectionTime > PostingInterval){
    Serial.println(i);
    get_Send_String(i);
    send_Data(i);
    i++;
    if (i == N) i=0;  
  }
  else dsmStatistics();
}

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,APIKey,dataLength,sensorData);

  if(timeNeedSet){
    setupTime();      
  }
  else{
    ether.tcpSend();
    displayClock();
  }
  lastConnectionTime = millis();  
}

void switchtoEthercard(){
  word len;
  do{
    len = ether.packetReceive();
    ether.packetLoop(len);
  }
  while(len != 0);
}
[/code]

[pre lang="arduino" line="1" file="Time.ino"]#define REQEST_TIMEOUT 10000

void setupTime(){
  lcd.setCursor(0,1);
  lcd.print("                ");
  lcd.setCursor(0,1);
  lcd.print("Update time...");
  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);
      lcd.print("OK");
      timeNeedSet=false;
      break;
    }
  }
}
void displayClock(){
  // digital clock display of the time
  timeSetTimer++;
  if (timeSetTimer>TIME_SET_TIMER) {
    timeSetTimer=0;
    timeNeedSet=true;
  }
  lcd.setCursor(0,1);
  lcd.print(year());
  lcd.print("-");
  printDigits(month());
  lcd.print("-");
  printDigits(day());
  lcd.print(" ");
  printDigits(hour());
  lcd.print(":");
  printDigits(minute());
}
void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10)
    lcd.print("0");
  lcd.print(digits);
}
[/code]

[pre lang="arduino" line="1" file="TimeConvert.ino"]//比较周数,成功返回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)==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;
}

[/code]
[pre lang="arduino" line="1" file="dsm501A.ino"]//dsm501统计变量
uint32_t dsmStatTimes10 = 0; //DSM
uint32_t sumTimeofLow10 = 0;
uint32_t dsmStatTimes25 = 0;
uint32_t sumTimeofLow25 = 0;
uint8_t switch1025 = 0;
//递推滤波变量
#define FILT_N 10
#define FILT_I 2
uint8_t filtI[FILT_I]={
  0,0};
uint16_t filtDsm[FILT_I][FILT_N];
uint32_t filtSum[FILT_I] = {
  0,0};

void dsmStatistics(){
  if(switch1025){
    dsmStatTimes10 ++;
    sumTimeofLow10 += !digitalRead(DSM_PIN_10);
    switch1025 = 0;
  }
  else{
    dsmStatTimes25 ++;
    sumTimeofLow25 += !digitalRead(DSM_PIN_25);
    switch1025 = 1;
  }
}

uint16_t filteringDsm(uint8_t l,uint16_t _dsmData){
  filtSum[l] =filtSum[l]- filtDsm[l][filtI[l]];
  filtSum[l] =filtSum[l]+ _dsmData;
  filtDsm[l][filtI[l]] = _dsmData;
  filtI[l]=filtI[l]+1;
  if (filtI[l] >= FILT_N) filtI[l] = 0;
  return filtSum[l]/FILT_N;
}
[/code]

[pre lang="arduino" line="1" file="sensor01.ino"]
float dsmTemp25;

void get_Send_String(uint8_t k){
  switch(k){
  case 0: //DSM501
    {
      float dsmTemp0 = (sumTimeofLow10*100.0)/dsmStatTimes10;
      float dsmTemp10 = 0.1776*pow(dsmTemp0,3) - 0.24*pow(dsmTemp0,2) + 94.003*dsmTemp0;
      lcd.setCursor(12,0);
      lcd.print(dsmTemp10);
    dataLength[k] = sprintf(sensorData[k],"{\"value\":%d}",filteringDsm(k,int(dsmTemp10)));
      sumTimeofLow10=0;
      dsmStatTimes10=0;
      dsmTemp0 = (sumTimeofLow25*100.0)/dsmStatTimes25;
      dsmTemp25 = 0.1776*pow(dsmTemp0,3) - 0.24*pow(dsmTemp0,2) + 94.003*dsmTemp0;
      dsmTemp25 = dsmTemp10-dsmTemp25;
      sumTimeofLow25=0;
      dsmStatTimes25=0;
      switchtoEthercard();
      break;  
    }
  case 1://pm25
    {
      dataLength[k] = sprintf(sensorData[k],"{\"value\":%d}",filteringDsm(k,int(dsmTemp25)));
      break;
    }
  case 2://Asm2302 temperature
    {
      sensor.update();
      uint16_t tempData = (sensor.getTemperatureInt() << 8) | sensor.getTemperatureFrac();
      lcd.setCursor(0,0);
      lcd.print(tempData/10);
      lcd.print(".");
      lcd.print(tempData%10);
      lcd.print("C");
      format_String(k,tempData);
      break;
    }
  case 3://Asm2302 humidity
    {
      sensor.update();
      uint16_t humiData = (sensor.getHumidityInt() << 8) | sensor.getHumidityFrac();
      lcd.setCursor(6,0);
      lcd.print(humiData/10);
      lcd.print(".");
      lcd.print(humiData%10);
      lcd.print("%");
      format_String(k,humiData);
      break;
    }

  }
}

void format_String(uint8_t l,uint16_t sensor_Data){
  uint16_t Tc_100 = sensor_Data;
  uint8_t whole, fract;
  whole = Tc_100/10 ;  // separate off the whole and fractional portions
  fract = Tc_100 % 10;
  dataLength[l] = sprintf(sensorData[l],"{\"value\":%d.%d}",whole,fract);
}
[/code]同样对洞洞板电路简单说下,左边14*2排针是接的ft232Rl转接板接的。 4个圆形排母其实是打眼固定enc28j60模块,下面2*2排针接方形usb口(和uno那个口一样);右边4*1排针接dsm501a,3*1排针接dht22(asm2302),5*2排针接enc模块,下面16*1接lcd1602,缺口是安dsm501A的,整个装在11.5cm宽5.5cm高7深的铝合金盒子中。整个arduino相当于一个nano,刷的nano 328的bootloader。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-8-29 08:51:25 | 显示全部楼层
还没看过第一弹,先占个沙发吧。看标题很有货的感觉
回复 支持 反对

使用道具 举报

发表于 2012-8-29 09:00:38 | 显示全部楼层
牛逼!张老师威武啊!
回复 支持 反对

使用道具 举报

发表于 2012-8-29 09:07:25 | 显示全部楼层
还凑合这个是什么情况...Yeelink不凑和!{:soso_e130:} 幸福与金钱无关,与内心相连,刚刚的...
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-29 09:40:42 | 显示全部楼层
还凑合是督促进步嘛,不要自满!
回复 支持 反对

使用道具 举报

发表于 2012-8-29 09:55:53 | 显示全部楼层
张老师多批评指导..{:soso_e183:},哪里不对咱们改改改,呵呵
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-29 10:43:05 | 显示全部楼层




































极客工坊太抠了,3M的图片都说太大。{:soso_e118:} ,放163相册了!
点击查看更多高清图片

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2012-8-29 22:04:18 | 显示全部楼层
盒子很漂亮
回复 支持 反对

使用道具 举报

发表于 2012-8-29 23:44:05 | 显示全部楼层
zcbzjx 发表于 2012-8-29 10:43
极客工坊太抠了,3M的图片都说太大。 ,放163相册了!
点击查看更多高清图片


额。。。压缩压缩嘛。。。。现在照片限制的是400K~~~~有没有必要。。开放高清无码大图呢{:soso_e113:} 163的高清图不错。。。我帮你全转过来,哈哈
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-30 06:13:13 | 显示全部楼层
谢谢 郝老板!
回复 支持 反对

使用道具 举报

发表于 2012-8-30 09:35:55 | 显示全部楼层
高科技啊!具体怎么用,怎么操作能在讲的详细些吗。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-30 10:33:11 | 显示全部楼层
插上usb和网线就行了啊,不用操作。
回复 支持 反对

使用道具 举报

发表于 2012-8-30 10:38:28 | 显示全部楼层
这个产品特点就是一个按钮也没有...
回复 支持 反对

使用道具 举报

发表于 2012-8-30 14:22:04 | 显示全部楼层
本帖最后由 acdc0616 于 2012-8-30 14:24 编辑

eagle6.1.0是破解版吗?我安装完了,怎么还要选择试用的还是注册的呢,软件里好多英文。。。晕
在附送个eagle视频教程http://eagle.timll.com/eagle_video_1.asp
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-30 18:07:02 | 显示全部楼层
我们用免费版本就够了,现在基本掌握了用法,还可以自己做库文件了,就是不太清楚如何布局和走pcb线比较合理
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-27 21:20 , Processed in 0.043946 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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