diff --git a/air_sensor.ino.ino b/air_sensor.ino.ino new file mode 100644 index 0000000..aaee770 --- /dev/null +++ b/air_sensor.ino.ino @@ -0,0 +1,202 @@ +#include +#include +#include "DHT.h" +#include +#include +#include "MutichannelGasSensor.h" +#include "HP20x_dev.h" +#include "KalmanFilter.h" + +unsigned char ret = 0; + +/* Instance */ +KalmanFilter t_filter; //temperature filter +KalmanFilter p_filter; //pressure filter +KalmanFilter a_filter; //altitude filter + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +IPAddress server(192, 168, 0, 30); // numeric IP for Google (no DNS) +//char server[] = "www.google.com"; // name address for Google (using DNS) + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 40); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + + +#define Vc 4.95 +//the number of R0 you detected just now +#define R0 35.54 +#define DHTPIN A1 // what pin we're connected to + +// Uncomment whatever type you're using! +//#define DHTTYPE DHT11 // DHT 11 +#define DHTTYPE DHT22 // DHT 22 (AM2302) +//#define DHTTYPE DHT21 // DHT 21 (AM2301) + +DHT dht(DHTPIN, DHTTYPE); + +int pin = 8; +unsigned long duration; +unsigned long starttime; +unsigned long sampletime_ms = 2000;//sampe 30s ; +unsigned long lowpulseoccupancy = 0; +float ratio = 0; +float concentration = 0; +String data = ""; + +void setup() { + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + delay(150); + HP20x.begin(); + delay(100); + + /* Determine HP20x_dev is available or not */ + ret = HP20x.isAvailable(); + + pinMode(8, INPUT); + starttime = millis();//get the current time; + //Serial.println("power on!"); + + + pinMode(4, OUTPUT); + digitalWrite(4, HIGH); + + //if (Ethernet.begin(mac) == 0) { + // Serial.println("Failed to configure Ethernet using DHCP"); + // try to congifure using IP address instead of DHCP: + Ethernet.begin(mac, ip); + + // give the Ethernet shield a second to initialize: + delay(10000); + // Serial.println("connecting..."); + //} + // give the Ethernet shield a second to initialize: + //delay(1000); + //Serial.println("connecting..."); + + + + // Serial.println(Ethernet.localIP()); + + + gas.begin(0x04);//the default I2C address of the slave is 0x04 + gas.powerOn(); + //Serial.print("Firmware Version = "); + //Serial.println(gas.getVersion()); + //Serial.println("Particles\tRS\tHCHO (PPM)\tNH3 (PPM)\tCO (PPM)\tNO2 (PPM)\tC3H8 (PPM)\tC4H10 (PPM)\tCH4 (PPM)\tH2 (PPM)\tC2H5OH (PPM)"); + dht.begin(); + delay(10000); + +} + +void loop() { + + if (client.available()) { + char c = client.read(); + // Serial.print(c); + } + + float HATemp2; + float HAPres2; + float HAAlt2; + float d; + + if (OK_HP20X_DEV == ret) + { + unsigned long HATemp = HP20x.ReadTemperature(); + d = HATemp / 100.0; + HATemp2 = t_filter.Filter(d); + + unsigned long HAPres = HP20x.ReadPressure(); + d = HAPres / 100.0; + HAPres2 = p_filter.Filter(d); + + unsigned long HAAlt = HP20x.ReadAltitude(); + d = HAAlt / 100.0; + HAAlt2 = a_filter.Filter(d); + + } + + duration = pulseIn(pin, LOW); + lowpulseoccupancy = lowpulseoccupancy + duration; + + + + if ((millis() - starttime) >= sampletime_ms) //if the sampel time = = 30s + { + ratio = lowpulseoccupancy / (sampletime_ms * 10.0); // Integer percentage 0=>100 + + d = 1.1 * pow(ratio, 3) - 3.8 * pow(ratio, 2) + 520 * ratio + 0.62; // using spec sheet curve + //Serial.print("concentration = "); + + lowpulseoccupancy = 0; + starttime = millis(); + } + //Serial.print("\t"); + //HCHO + + int sensorValue = analogRead(A0); + double Rs = (1023.0 / sensorValue) - 1; + + double ppm = pow(10.0, ((log10(Rs / R0) - 0.0827) / (-0.4807))); + //Serial.print("HCHO ppm = "); + + //MultiChannel Gas + float NH3 = gas.measure_NH3(); + float CO = gas.measure_CO(); + float NO2 = gas.measure_NO2(); + float C3H8 = gas.measure_C3H8(); + float C4H10 = gas.measure_C4H10(); + float CH4 = gas.measure_CH4(); + float H2 = gas.measure_H2(); + float C2H5OH = gas.measure_C2H5OH(); + + + // Reading temperature or humidity takes about 250 milliseconds! + // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + float h = dht.readHumidity(); + float t = dht.readTemperature(); + + data = String("dust=") + d + "&rs=" + Rs + "&hcho=" + ppm + "&nh3=" + NH3 + "&co=" + CO + "&no2=" + NO2 + "&c3h8=" + C3H8 + "&c4h10=" + C4H10 + "&ch4=" + CH4 + "&h2=" + H2 + "&c2h5oh=" + C2H5OH + "&temp=" + t + "&hum=" + h + "&HATemp=" + HATemp2 + "&HAPres=" + HAPres2 + "&HAAlt=" + HAAlt2; + + //Serial.println(data); + + + if (client.connect(server, 80)) { + Serial.println(F("connected")); + client.println(F("POST /air_add.php HTTP/1.1")); + client.println(F("Host: 192.168.0.30")); + client.println(F("User-Agent: Arduino/1.0")); + client.println(F("Connection: close")); + client.println(F("Content-Type: application/x-www-form-urlencoded;")); + client.print(F("Content-Length: ")); + client.println(data.length()); + client.println(); + client.println(data); + } + else + { + Serial.println(F("could not connect")); + } + + Serial.println(data); + + if (client.connected()) { + client.stop(); + } + + + delay(300000); +} diff --git a/lib/DHT.h b/lib/DHT.h new file mode 100644 index 0000000..101a07d --- /dev/null +++ b/lib/DHT.h @@ -0,0 +1,49 @@ +#ifndef DHT_H +#define DHT_H +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +// 8 MHz(ish) AVR --------------------------------------------------------- +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) +#define COUNT 3 +// 16 MHz(ish) AVR -------------------------------------------------------- +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) +#define COUNT 6 +#else +#error "CPU SPEED NOT SUPPORTED" +#endif + +/* DHT library + +MIT license +written by Adafruit Industries +*/ + +// how many timing transitions we need to keep track of. 2 * number bits + extra +#define MAXTIMINGS 85 + +#define DHT11 11 +#define DHT22 22 +#define DHT21 21 +#define AM2301 21 + +class DHT { + private: + uint8_t data[6]; + uint8_t _pin, _type, _count; + boolean read(void); + unsigned long _lastreadtime; + boolean firstreading; + + public: + DHT(uint8_t pin, uint8_t type, uint8_t count=COUNT); + void begin(void); + float readTemperature(bool S=false); + float convertCtoF(float); + float readHumidity(void); + +}; +#endif diff --git a/lib/HP20x_dev.h b/lib/HP20x_dev.h new file mode 100644 index 0000000..993be47 --- /dev/null +++ b/lib/HP20x_dev.h @@ -0,0 +1,101 @@ +/* + * File name : HP20x_dev.h + * Description: Driver for I2C PRECISION BAROMETER AND ALTIMETER [HP206C] + * Author : Oliver Wang from Seeed studio + * Version : V0.1 + * Create Time: 2014/04 + * Change Log : +*/ +#ifndef _HP20X_DEV_H +#define _HP20X_DEV_H +/****************************************************************************/ +/*** Including Files ***/ +/****************************************************************************/ +#include +#include +/****************************************************************************/ +/*** Macro Definitions ***/ +/****************************************************************************/ +typedef unsigned int uint; +typedef unsigned char uchar; +typedef unsigned long ulong; + +#define HP20X_I2C_DEV_ID (0xEC)>>1 //CSB PIN is VDD level(address is 0x76) +#define HP20X_I2C_DEV_ID2 (0XEE)>>1 //CSB PIN is GND level(address is 0x77) +#define HP20X_SOFT_RST 0x06 +#define HP20X_WR_CONVERT_CMD 0x40 +#define HP20X_CONVERT_OSR4096 0<<2 +#define HP20X_CONVERT_OSR2048 1<<2 +#define HP20X_CONVERT_OSR1024 2<<2 +#define HP20X_CONVERT_OSR512 3<<2 +#define HP20X_CONVERT_OSR256 4<<2 +#define HP20X_CONVERT_OSR128 5<<2 + +#define HP20X_READ_P 0x30 //read_p command +#define HP20X_READ_A 0x31 //read_a command +#define HP20X_READ_T 0x32 //read_t command +#define HP20X_READ_PT 0x10 //read_pt command +#define HP20X_READ_AT 0x11 //read_at command +#define HP20X_READ_CAL 0X28 //RE-CAL ANALOG + +#define HP20X_WR_REG_MODE 0xC0 +#define HP20X_RD_REG_MODE 0x80 + +#define ERR_WR_DEVID_NACK 0x01 +#define ERR_RD_DEVID_NACK 0x02 +#define ERR_WR_REGADD_NACK 0x04 +#define ERR_WR_REGCMD_NACK 0x08 +#define ERR_WR_DATA_NACK 0x10 +#define ERR_RD_DATA_MISMATCH 0x20 + +#define I2C_DID_WR_MASK 0xFE +#define I2C_DID_RD_MASK 0x01 + +#define T_WIN_EN 0X01 +#define PA_WIN_EN 0X02 +#define T_TRAV_EN 0X04 +#define PA_TRAV_EN 0X08 +#define PA_RDY_EN 0X20 +#define T_RDY_EN 0X10 + +#define T_WIN_CFG 0X01 +#define PA_WIN_CFG 0X02 +#define PA_MODE_P 0X00 +#define PA_MODE_A 0X40 + +#define T_TRAV_CFG 0X04 + +#define OK_HP20X_DEV 0X80 //HP20x_dev successfully initialized +#define REG_PARA 0X0F //Status register + +/****************************************************************************/ +/*** Class Definitions ***/ +/****************************************************************************/ +class HP20x_dev : public TwoWire +{ + /* Public variables and functions */ + public: + uchar OSR_CFG; + uint OSR_ConvertTime; + /* Constructor */ + HP20x_dev(); + void begin(); + uchar isAvailable(); + + /* Read sensor data */ + ulong ReadTemperature(void); + ulong ReadPressure(void); + ulong ReadAltitude(void); + + /* Private variables and functions */ + private: + /* Write a command to HP20x */ + void HP20X_IIC_WriteCmd(uchar uCmd); + /* Read register value */ + uchar HP20X_IIC_ReadReg(uchar bReg); + void HP20X_IIC_WriteReg(uchar bReg,uchar bData); + ulong HP20X_IIC_ReadData(void); + ulong HP20X_IIC_ReadData3byte(void); +}; +extern HP20x_dev HP20x; +#endif \ No newline at end of file diff --git a/lib/KalmanFilter.h b/lib/KalmanFilter.h new file mode 100644 index 0000000..ba188df --- /dev/null +++ b/lib/KalmanFilter.h @@ -0,0 +1,37 @@ +/* + * File name : kalmanFilter.h + * Description: + * Author : Oliver Wang from Seeed studio + * Version : V0.1 + * Create Time: 2014/04 + * Change Log : +*/ + +#ifndef _KALMANFILTER_H +#define _KALMANFILTER_H +/****************************************************************************/ +/*** Include files ***/ +/****************************************************************************/ +#include +#include +/****************************************************************************/ +/*** Local variables ***/ +/****************************************************************************/ + + +/****************************************************************************/ +/*** Class Definitions ***/ +/****************************************************************************/ +class KalmanFilter +{ + public: + KalmanFilter(); + float Filter(float); + private: + /* variables */ + float X_pre, X_post, P_pre, P_post, K_cur; + float Gaussian_Noise_Cov(void); + +}; +extern KalmanFilter kalmanFilter; +#endif \ No newline at end of file diff --git a/lib/MutichannelGasSensor.h b/lib/MutichannelGasSensor.h new file mode 100644 index 0000000..e646b5c --- /dev/null +++ b/lib/MutichannelGasSensor.h @@ -0,0 +1,151 @@ +/* + MutichannelGasSensor.h + 2015 Copyright (c) Seeed Technology Inc. All right reserved. + + Author: Jacky Zhang + 2015-3-17 + http://www.seeed.cc/ + modi by Jack, 2015-8 + + V2 by Loovee + 2016-11-11 + + The MIT License (MIT) + + Copyright (c) 2015 Seeed Technology Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef __MUTICHANNELGASSENSOR_H__ +#define __MUTICHANNELGASSENSOR_H__ + +#define DEFAULT_I2C_ADDR 0x04 + +#define ADDR_IS_SET 0 // if this is the first time to run, if 1126, set +#define ADDR_FACTORY_ADC_NH3 2 +#define ADDR_FACTORY_ADC_CO 4 +#define ADDR_FACTORY_ADC_NO2 6 + +#define ADDR_USER_ADC_HN3 8 +#define ADDR_USER_ADC_CO 10 +#define ADDR_USER_ADC_NO2 12 +#define ADDR_IF_CALI 14 // IF USER HAD CALI + +#define ADDR_I2C_ADDRESS 20 + +#define CH_VALUE_NH3 1 +#define CH_VALUE_CO 2 +#define CH_VALUE_NO2 3 + +#define CMD_ADC_RES0 1 // NH3 +#define CMD_ADC_RES1 2 // CO +#define CMD_ADC_RES2 3 // NO2 +#define CMD_ADC_RESALL 4 // ALL CHANNEL +#define CMD_CHANGE_I2C 5 // CHANGE I2C +#define CMD_READ_EEPROM 6 // READ EEPROM VALUE, RETURN UNSIGNED INT +#define CMD_SET_R0_ADC 7 // SET R0 ADC VALUE +#define CMD_GET_R0_ADC 8 // GET R0 ADC VALUE +#define CMD_GET_R0_ADC_FACTORY 9 // GET FACTORY R0 ADC VALUE +#define CMD_CONTROL_LED 10 +#define CMD_CONTROL_PWR 11 + +enum{CO, NO2, NH3, C3H8, C4H10, CH4, H2, C2H5OH}; + +class MutichannelGasSensor{ + +private: + + int __version; + unsigned char dta_test[20]; + + unsigned int readChAdcValue(int ch); + unsigned int adcValueR0_NH3_Buf; + unsigned int adcValueR0_CO_Buf; + unsigned int adcValueR0_NO2_Buf; + +public: + + uint8_t i2cAddress; //I2C address of this MCU + uint16_t res0[3]; //sensors res0 + uint16_t res[3]; //sensors res + bool r0_inited; + + + inline unsigned int get_addr_dta(unsigned char addr_reg); + inline unsigned int get_addr_dta(unsigned char addr_reg, unsigned char __dta); + inline void write_i2c(unsigned char addr, unsigned char *dta, unsigned char dta_len); + + void sendI2C(unsigned char dta); + int16_t readData(uint8_t cmd); + int16_t readR0(void); + int16_t readR(void); + float calcGas(int gas); + +public: + + void begin(int address); + void begin(); + void changeI2cAddr(uint8_t newAddr); + void powerOn(void); + void powerOff(void); + void doCalibrate(void); + + //get gas concentration, unit: ppm + float measure_CO(){return calcGas(CO);} + float measure_NO2(){return calcGas(NO2);} + float measure_NH3(){return calcGas(NH3);} + float measure_C3H8(){return calcGas(C3H8);} + float measure_C4H10(){return calcGas(C4H10);} + float measure_CH4(){return calcGas(CH4);} + float measure_H2(){return calcGas(H2);} + float measure_C2H5OH(){return calcGas(C2H5OH);} + + float getR0(unsigned char ch); // 0:CH3, 1:CO, 2:NO2 + float getRs(unsigned char ch); // 0:CH3, 1:CO, 2:NO2 + +public: + + void ledOn() + { + dta_test[0] = CMD_CONTROL_LED; + dta_test[1] = 1; + write_i2c(i2cAddress, dta_test, 2); + } + + void ledOff() + { + dta_test[0] = CMD_CONTROL_LED; + dta_test[1] = 0; + write_i2c(i2cAddress, dta_test, 2); + } + + void display_eeprom(); + void factory_setting(); + void change_i2c_address(unsigned char addr); + unsigned char getVersion(); +}; + +extern MutichannelGasSensor gas; + +#endif + +/********************************************************************************************************* + END FILE +*********************************************************************************************************/ \ No newline at end of file