回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【Arduino 动手做】Arduino 环境空气质量监测仪 简单

头像 驴友花雕 2025.07.09 14 0

我想建造一个环境监测器。部分原因是为了了解每天发生的情况,也因为我想比较所有不同的 MQ 传感器,看看它们如何响应不同的事物。使用 Linkit 可以让我添加 GPS 记录,使其成为一个移动平台。

第 1 步:外部天线
我碰巧有一些来自 Zigbee 板的剩余 U.fl 到 RP-SMA 适配器,以及来自我的 SDR 无线电板的几根 U.fl 到 SMA 电缆。这些天线似乎是替代套件中带板天线的完美天线。GPS 天线现在的样子很好。我只需要一个保护壳来保护它,所以我打印了一个......

如果您想自己制作一个,我已经包含了 SCAD 源文件和 STL 文件。

第 2 步:制作 ADC 扩展器护套
Linkit 只有 3 个模拟输入。我需要 9 个!我添加了一个来自 TI 的 TLC1540CN 11 通道 ADC 芯片。我使用了 Arduino Mega Prototype Shield。我只填充了与 Linkit One 匹配的引脚。我将其他引脚用于芯片的 I/O。我还在前边缘添加了一个额外的 I2C 连接器,以防我以后想添加 LCD。

第 3 步:如何让它变得漂亮
为了让它看起来更好看,我决定把它安装在一块牌匾上,让所有东西都几乎可见。我将电路板后面的所有电源线都进行了总线连接。我把第二块木板剪成完全相同的大小,这样我就可以把一些 1/2 方形的木条夹起来做一个盒子。

为了让它看起来更好看,我决定在 CNC 铣床上刻下牌匾的所有图例。快速涂抹黑色油漆以突出它,然后用一些 WD-40 滑动以去除多余的油漆,这确实使它看起来不错。

第 4 步:原理图和代码
TLC1540 的代码有点粗糙。我做了一点蛮力,有点摆弄,但它确实有效。

我必须画一个漂亮的原理图,但现在在这里,我的手画了一个,我在 Fritzing 中尝试了一个......

我将 ADC 中的所有 11 个通道发送到 CSV 文件。最后两个通道没有连接到任何东西,所以你会在那里得到随机的噪音。我很快就会使用它们。

该代码将文件记录到 SD 卡中,其中包含名称的当前日期。每天它运行时,您都会得到一个新文件。我可能会将其更改为删除日期,只使用 Month-Year。这样我每个月都只能收到一个新文件。它是一个 CSV 文件,所以我可以使用 Office 来作它。

第 5 步:接线
我使用了一些 Telco 交叉连接线和 Dupont 压接连接器。一点热胶将连接器固定到位,就是这样......

这样,每个传感器都可以拆卸以进行测试或更换。这是我另一个关心的问题,即它们对持续使用的保持能力如何。我想我会在 2016 年知道......

第 6 步:未来的增强功能
盖革计数器,为什么不呢。我必须制作一个 PIC 微控制器 I2C 从器件来跟踪 CPM。我可能必须用 Plexiglas 屏蔽罩覆盖这部分,以防止手指远离高压。在某个地方我也有一根云母开窗管。我甚至可能在我父亲的陆军测量仪中有一个煎饼管。我得去看看他的储物柜。这样我就可以比较管子类型。

我还没有一些 MQ 传感器,所以它们在列表中。我选择了 5V 传感器,以便于接线。该扩展板上还有足够的区域用于我可能需要的任何支持电路,以切换真正奇怪的传感器的电源水平。

大约 8 周前,我还订购了 ML8511 UVB 传感器。如果我在 1 月 10 日之前没有收到,我将不得不提出索赔并从其他供应商处订购......

 

01.jpg
02.jpg
03.jpg
04.jpg
05.jpg
06.jpg
07.jpg
08.jpg
09.jpg
10.jpg

项目代码
 

代码
//****************************************************************
//*  Name    : Air Quality Monitor                               *
//*  Author  : Robert Joseph Korn                                *
//*  Notice  : Copyright (c) 2015 Open Valley Consulting Corp    *
//*  Date    : 10/18/15                                          *
//*  Version : 1.1                                               *
//*  Notes   :                                                   *
//*          :                                                   *
//****************************************************************
#include <LFlash.h>
#include <LSD.h>
#include <LStorage.h>
#include <LGPS.h>
#include "LDHT.h"
#include <Wire.h>
#include "Barometer.h"
#include <BH1750FVI.h>

//uncomment the storage you want to use
// #define Drv LFlash          // use Internal 10M Flash
#define Drv LSD           // use SD card
#define DEBUG true  // Comment to disable debug
#define DHTPIN 6     // what pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT22   // DHT 11 21 22

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

gpsSentenceInfoStruct info; //needed to get GPS data

int da = 5; // Device Address
int ck = 3; // Clock
int di = 4; // Data In
int cs = 2; // Chip Select

int val = 0;
int adcv[12];
int val1 = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
int val5 = 0;
int val6 = 0;
int val7 = 0;
int val8 = 0;
int val9 = 0;
int val10 = 0;
int val11 = 0;
int dbl = 0;
int tmp = 0;
byte chn = 0;

float hum = 0;
float tem = 0;
float far = 0;
float hi = 0;
float dew = 0;
float temperature = 0;
float pressure = 0;
float alt;
uint16_t lux = 0;
double latitude = 0.00;
double longitude = 0.00;
float altitude = 0.00;
float dop = 100.00; //dilution of precision
float geoid = 0.00;
float k_speed = 0.00, m_speed = 0.00; //speed in knots and speed in m/s
float track_angle = 0.00;
int fix = 0;
int hour = 0, minute = 0, second = 0;
int sat_num = 0; //number of visible satellites
int day = 0, month = 0, year = 0;
String time_format = "00:00:00", date_format = "00:00:0000";
String lat_format = "0.00000", lon_format = "0.00000";
char file[15] = "";
int pause = 5000; //time in milliseconds between two logs

BH1750FVI LightSensor;

Barometer myBarometer;

LDHT dht(DHTPIN, DHTTYPE);

void getadcval() {

 for(dbl=0;dbl<2;dbl++) { 
    val = 0 ;
    digitalWrite(cs, LOW); 
    pulseck(2);  //Strobe CS 
    dataxfer();   
    digitalWrite(cs, HIGH);   
    pulseck(50); // Conversion Clock 44 cycles needed  
 }
}

void dataxfer(){

 for(tmp=0;tmp<4;tmp++) { 

   if (bitRead(chn, 3 - tmp) ){
      digitalWrite(da, HIGH); 
   } else {  
      digitalWrite(da, LOW);     
   }

   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
      if(digitalRead(di) > 0){
     val++;
   }
   val=val<<1; 

 }
 for(tmp=0;tmp<6;tmp++) {  
   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
      if(digitalRead(di) > 0){
     val++;
   }
   val=val<<1; 
 }
    val=val>>1; 
}

void pulseck(uint8_t cnt) {
 for(tmp=0;tmp<cnt;tmp++) {  
   digitalWrite(ck, HIGH);   
   digitalWrite(ck, LOW);   
 }
}

void setup()
{

 pinMode(ck, OUTPUT);     
 pinMode(da, OUTPUT);     
 pinMode(cs, OUTPUT);     
 pinMode(di, INPUT);     
 digitalWrite(cs, HIGH);   
 digitalWrite(ck, LOW);   
 digitalWrite(da, LOW);   
 
  Serial1.begin(9600);
  Serial1.println();
  Serial1.print("Initializing...");
  
  Serial.begin(115200);
  
  Serial.print("Initializing memory...");
  
  pinMode(10, OUTPUT); //needed for SD card
  
  if(!Drv.begin())
  {
    Serial.println("Error initalizing memory.");  
    while(true);
  }
  
  Serial.println("OK.");
  
  myBarometer.init();
  
  LightSensor.begin();
  
 /*
 Set the address for this sensor 
 you can use 2 different address
 Device_Address_H "0x5C"
 Device_Address_L "0x23"
 you must connect Addr pin to A3 .
 */
  LightSensor.SetAddress(Device_Address_H);//Address 0x5C
  // lightMeter.SetAddress(Device_Address_L); //Address 0x23
 //-----------------------------------------------
  /*
   set the Working Mode for this sensor 
   Select the following Mode:
    Continuous_H_resolution_Mode
    Continuous_H_resolution_Mode2
    Continuous_L_resolution_Mode
    OneTime_H_resolution_Mode
    OneTime_H_resolution_Mode2
    OneTime_L_resolution_Mode
    
    The data sheet recommanded To use Continuous_H_resolution_Mode
  */

  LightSensor.SetMode(Continuous_H_resolution_Mode);
   
  LGPS.powerOn();
  Serial.println("GPS started.");
    dht.begin();
  Serial.println("Setup Done");
  Serial.println("");

}

void loop()
{
     Serial1.println();
     Serial1.print("Loop");
    
    Serial.println("");
    Serial.println("");
    Serial.println("------------------------------------------------------------------");
    Serial.println("");
    Serial.println("BMP Sensor");

   temperature = myBarometer.bmp085GetTemperature(myBarometer.bmp085ReadUT()); //Get the temperature, bmp085ReadUT MUST be called first
   pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP()) ;//Get the ressure
   alt = myBarometer.calcAltitude(pressure); //Uncompensated caculation - in Meters
   pressure = pressure / 100 ;
   alt = alt + 60 ;
   
  Serial.print("Temperature: ");
  Serial.print(temperature, 2); //display 2 decimal places
  Serial.println(" deg C");

  Serial.print("Pressure: ");
  Serial.print(pressure, 2); //whole number only.
  Serial.println(" KPa");

  Serial.print("Altitude: ");
  Serial.print(alt, 2); //display 2 decimal places
  Serial.println(" m");

  Serial.println();

    Serial.println("");
    Serial.println("DHT Sensor");
   if(dht.read())
    {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  hum = dht.readHumidity();
  // Read temperature as Celsius
  tem = dht.readTemperature();
  // Read temperature as Fahrenheit
  far = dht.readTemperature(false);
  } 
  // Check if any reads failed and exit early (to try again).
  if (isnan(hum) || isnan(tem) || isnan(far)) {
    Serial.println("Failed to read from DHT sensor!");
  }
  else 
  {
  // Compute heat index
  // Must send in temp in Fahrenheit!
  hi = dht.readHeatIndex(tem, hum);

  Serial.print("Humidity: "); 
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temperature: "); 
  Serial.print(tem);
  Serial.println(" *C ");
  Serial.print("Temperature: "); 
  Serial.print(far);
  Serial.println(" *F");
  Serial.print("Heat index: ");
  Serial.print(hi);
  Serial.println(" *C");
  Serial.print("DewPoint = ");
  dew = dht.readDewPoint(tem,hum);
  Serial.print(dew);
  Serial.println("C");
  }
  
  Serial.println("");
  Serial.println("BH1750 Sensor "); 
  lux = LightSensor.GetLightIntensity();// Get Lux value
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lux");
  Serial.println("");
  Serial.println("");

   for(chn=0;chn<11;chn++) { 
      getadcval();
      getadcval();
      adcv[chn] = val ;
      Serial.print("Channel: ");
      Serial.print(chn);
      Serial.print(" - ");
      Serial.println(val);
      Serial.println();
   }

   Serial.println();
  
  if (getData(&info) > 3)
  {
    String str = "";
    str += date_format;
    str += ",";
    str += time_format;
    str += ",";
    str += lat_format;
    str += ",";
    str += lon_format;
    str += ",";
    str += altitude;
    str += ",";
    str += dop;
    str += ",";
    str += geoid;
    str += ",";
    str += track_angle;
    str += ",";
    str += m_speed;
    str += ",";
    str += k_speed;
    str += ",";
    str += fix;
    str += ",";
    str += sat_num;
    str += ",";
    str += hum;
    str += ",";
    str += tem;
    str += ",";
    str += far;
    str += ",";
    str += hi;
    str += ",";
    str += pressure;
    str += ",";
    str += temperature;
    str += ",";
    str += alt;
    str += ",";
    str += lux;
    str += ",";

    for(chn=0;chn<11;chn++) { 
       str += adcv[chn];
       str += ",";
   }

    Serial1.print(str);
    Serial.println(str);
    String file_name = date_format;
    file_name += ".txt";
    file_name.toCharArray(file, 15);
    Serial.println(file);
    LFile dataFile = Drv.open(file, FILE_WRITE);
    if (dataFile)
    {
      dataFile.println(str);
      dataFile.close();
      Serial.println("File written.");
    }
    else Serial.println("Error opening file.");


  }
  else Serial.println("Less then 4 satelites.");


  delay(pause);
}

/**
*Converts degrees from (d)ddmm.mmmm to (d)dd.mmmmmm
*@param str the string rappresentation of the angle in (d)ddmm.mmmm format
*@param dir if true the direction is south, and the angle is negative.
*@return the given angle in dd.mmmmmm format.
*/
float convert(String str, boolean dir)
{
  double mm, dd;
  int point = str.indexOf('.');
  dd = str.substring(0, (point - 2)).toFloat();
  mm = str.substring(point - 2).toFloat() / 60.00;
  return (dir ? -1 : 1) * (dd + mm);
}

/**
*Gets gps informations
*@param info gpsSentenceInfoStruct is a struct containing NMEA sentence infomation
*@return the number of hooked satellites, or 0 if there was an error getting informations
*/
int getData(gpsSentenceInfoStruct* info)
{
  Serial.println("Collecting GPS data.");
  LGPS.getData(info);
  Serial.println((char*)info->GPGGA);
  if (info->GPGGA[0] == '$')
  {
    Serial.print("Parsing GGA data....");
    String str = (char*)(info->GPGGA);
    str = str.substring(str.indexOf(',') + 1);
    hour = str.substring(0, 2).toInt();
    minute = str.substring(2, 4).toInt();
    second = str.substring(4, 6).toInt();
    time_format = "";
    time_format += hour;
    time_format += ":";
    time_format += minute;
    time_format += ":";
    time_format += second;
    str = str.substring(str.indexOf(',') + 1);
    latitude = convert(str.substring(0, str.indexOf(',')), str.charAt(str.indexOf(',') + 1) == 'S');
    int val = latitude * 1000000;
    String s = String(val);
    lat_format = s.substring(0, (abs(latitude) < 100) ? 2 : 3);
    lat_format += '.';
    lat_format += s.substring((abs(latitude) < 100) ? 2 : 3);
    str = str.substring(str.indexOf(',') + 3);
    longitude = convert(str.substring(0, str.indexOf(',')), str.charAt(str.indexOf(',') + 1) == 'W');
    val = longitude * 1000000;
    s = String(val);
    lon_format = s.substring(0, (abs(longitude) < 100) ? 2 : 3);
    lon_format += '.';
    lon_format += s.substring((abs(longitude) < 100) ? 2 : 3);

    str = str.substring(str.indexOf(',') + 3);
    fix = str.charAt(0) - 48;
    str = str.substring(2);
    sat_num = str.substring(0, 2).toInt();
    str = str.substring(3);
    dop = str.substring(0, str.indexOf(',')).toFloat();
    str = str.substring(str.indexOf(',') + 1);
    altitude = str.substring(0, str.indexOf(',')).toFloat();
    str = str.substring(str.indexOf(',') + 3);
    geoid = str.substring(0, str.indexOf(',')).toFloat();
    Serial.println("done.");
    
    if (info->GPRMC[0] == '$')
    {
      Serial.print("Parsing RMC data....");
      str = (char*)(info->GPRMC);
      int comma = 0;
      for (int i = 0; i < 60; ++i)
      {
        if (info->GPRMC[i] == ',')
        {
          comma++;
          if (comma == 7)
          {
            comma = i + 1;
            break;
          }
        }
      }

      str = str.substring(comma);
      k_speed = str.substring(0, str.indexOf(',')).toFloat();
      m_speed = k_speed * 0.514;
      str = str.substring(str.indexOf(',') + 1);
      track_angle = str.substring(0, str.indexOf(',')).toFloat();
      str = str.substring(str.indexOf(',') + 1);
      day = str.substring(0, 2).toInt();
      month = str.substring(2, 4).toInt();
      year = str.substring(4, 6).toInt();
      date_format = "20";
      date_format += year;
      date_format += "-";
      date_format += month;
      date_format += "-";
      date_format += day;
      Serial.println("done.");
      return sat_num;
    }
  }
  else
  {
    Serial.println("No GGA data");
  }
  return 0;
}

【Arduino 动手做】Arduino 环境空气质量监测仪
项目链接:https://www.instructables.com/Environmental-Monitor/
项目作者:rjkorn

项目代码:https://content.instructables.com/FYC/C6UW/IIEWPOCV/FYCC6UWIIEWPOCV.ino
3D打印文件:
https://content.instructables.com/FOP/QGE7/IIEYWQMA/FOPQGE7IIEYWQMA.stl
https://content.instructables.com/F1Y/M3NW/IIEYWQKC/F1YM3NWIIEYWQKC.stl

 

00.jpg

评论

user-avatar
icon 他的勋章
    展开更多