diff --git a/lib/DHT.cpp b/lib/DHT.cpp new file mode 100644 index 0000000..f3da749 --- /dev/null +++ b/lib/DHT.cpp @@ -0,0 +1,162 @@ +/* DHT library + +MIT license +written by Adafruit Industries +*/ + +#include "DHT.h" +#define NAN 0 + +DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) { + _pin = pin; + _type = type; + _count = count; + firstreading = true; +} + +void DHT::begin(void) { + // set up the pins! + pinMode(_pin, INPUT); + digitalWrite(_pin, HIGH); + _lastreadtime = 0; +} + +//boolean S == Scale. True == Farenheit; False == Celcius +float DHT::readTemperature(bool S) { + float f; + + if (read()) { + switch (_type) { + case DHT11: + f = data[2]; + if(S) + f = convertCtoF(f); + + return f; + case DHT22: + case DHT21: + f = data[2] & 0x7F; + f *= 256; + f += data[3]; + f /= 10; + if (data[2] & 0x80) + f *= -1; + if(S) + f = convertCtoF(f); + + return f; + } + } + Serial.print("Read fail"); + return NAN; +} + +float DHT::convertCtoF(float c) { + return c * 9 / 5 + 32; +} + +float DHT::readHumidity(void) { + float f; + if (read()) { + switch (_type) { + case DHT11: + f = data[0]; + return f; + case DHT22: + case DHT21: + f = data[0]; + f *= 256; + f += data[1]; + f /= 10; + return f; + } + } + Serial.print("Read fail"); + return NAN; +} + + +boolean DHT::read(void) { + uint8_t laststate = HIGH; + uint8_t counter = 0; + uint8_t j = 0, i; + unsigned long currenttime; + + // pull the pin high and wait 250 milliseconds + digitalWrite(_pin, HIGH); + delay(250); + + currenttime = millis(); + if (currenttime < _lastreadtime) { + // ie there was a rollover + _lastreadtime = 0; + } + if (!firstreading && ((currenttime - _lastreadtime) < 2000)) { + return true; // return last correct measurement + //delay(2000 - (currenttime - _lastreadtime)); + } + firstreading = false; + /* + Serial.print("Currtime: "); Serial.print(currenttime); + Serial.print(" Lasttime: "); Serial.print(_lastreadtime); + */ + _lastreadtime = millis(); + + data[0] = data[1] = data[2] = data[3] = data[4] = 0; + + // now pull it low for ~20 milliseconds + pinMode(_pin, OUTPUT); + digitalWrite(_pin, LOW); + delay(20); + //cli(); + digitalWrite(_pin, HIGH); + delayMicroseconds(40); + pinMode(_pin, INPUT); + + // read in timings + for ( i=0; i< MAXTIMINGS; i++) { + counter = 0; + while (digitalRead(_pin) == laststate) { + counter++; + delayMicroseconds(1); + if (counter == 255) { + break; + } + } + laststate = digitalRead(_pin); + + if (counter == 255) break; + + // ignore first 3 transitions + if ((i >= 4) && (i%2 == 0)) { + // shove each bit into the storage bytes + data[j/8] <<= 1; + if (counter > _count) + data[j/8] |= 1; + j++; + } + + } + + //sei(); + + /* + Serial.println(j, DEC); + Serial.print(data[0], HEX); Serial.print(", "); + Serial.print(data[1], HEX); Serial.print(", "); + Serial.print(data[2], HEX); Serial.print(", "); + Serial.print(data[3], HEX); Serial.print(", "); + Serial.print(data[4], HEX); Serial.print(" =? "); + Serial.println(data[0] + data[1] + data[2] + data[3], HEX); + */ + + // check we read 40 bits and that the checksum matches + if ((j >= 40) && + (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) { + return true; + } + + + return false; + +} diff --git a/lib/HP20x_dev.cpp b/lib/HP20x_dev.cpp new file mode 100644 index 0000000..a2cb9a6 --- /dev/null +++ b/lib/HP20x_dev.cpp @@ -0,0 +1,262 @@ +/* + * File name : HP20x_dev.cpp + * Description: Driver for I2C PRECISION BAROMETER AND ALTIMETER [HP206C] + * Author : Oliver Wang from Seeed studio + * Version : V0.1 + * Create Time: 2014/04 + * Change Log : +*/ + +/****************************************************************************/ +/*** Include files ***/ +/****************************************************************************/ +#include "HP20x_dev.h" +#include +#include +#include "KalmanFilter.h" +/****************************************************************************/ +/*** Local Variable ***/ +/****************************************************************************/ + HP20x_dev HP20x; + + +/****************************************************************************/ +/*** Class member Functions ***/ +/****************************************************************************/ +/* + **@ Function name: HP20x_dev + **@ Description: Constructor + **@ Input: none + **@ OutPut: none + **@ Retval: none +*/ +HP20x_dev::HP20x_dev() +{ + OSR_CFG = HP20X_CONVERT_OSR1024; + OSR_ConvertTime = 25; +} + +/* + **@ Function name: begin + **@ Description: Initialize HP20x_dev + **@ Input: none + **@ OutPut: none + **@ Retval: none +*/ +void HP20x_dev::begin() +{ + Wire.begin(); + /* Reset HP20x_dev */ + HP20x.HP20X_IIC_WriteCmd(HP20X_SOFT_RST); +} + +/* + **@ Function name: isAvailable + **@ Description: Indicate whether it's available + **@ Input: none + **@ OutPut: none + **@ Retval: uchar +*/ +uchar HP20x_dev::isAvailable() +{ + uchar ret = HP20x.HP20X_IIC_ReadReg(REG_PARA); + return ret; +} +/* + **@ Function name: ReadTemperature + **@ Description: Read Temperature from HP20x_dev + **@ Input: + **@ OutPut: + **@ Retval: +*/ +ulong HP20x_dev::ReadTemperature(void) +{ + uchar Temp; + uchar Temp0; + + HP20X_IIC_WriteCmd(HP20X_WR_CONVERT_CMD|OSR_CFG); //ADC convert + + delay(OSR_ConvertTime); //difference OSR_CFG will be difference OSR_ConvertTime + HP20X_IIC_WriteCmd(HP20X_READ_T); + ulong Temperature = HP20X_IIC_ReadData(); + return Temperature; +} + +/* + **@ Function name: ReadPressure + **@ Description: Read Pressure value + **@ Input: + **@ OutPut: + **@ Retval: value +*/ + +ulong HP20x_dev::ReadPressure(void) +{ + HP20X_IIC_WriteCmd(HP20X_WR_CONVERT_CMD|OSR_CFG); + delay(OSR_ConvertTime); + HP20X_IIC_WriteCmd(HP20X_READ_P); + ulong Pressure = HP20X_IIC_ReadData(); + return Pressure; +} + +/* + **@ Function name: ReadAltitude + **@ Description: Read Pressure value + **@ Input: + **@ OutPut: + **@ Retval: value +*/ +ulong HP20x_dev::ReadAltitude(void) +{ + HP20X_IIC_WriteCmd(HP20X_READ_A); + ulong Altitude = HP20X_IIC_ReadData(); + return Altitude; +} + +/* +void ReadPressureAndTemperature(void) +{ + HP20X_IIC_WriteCmd(HP20X_WR_CONVERT_CMD|OSR_CFG); + Timer_Delayxms(OSR_ConvertTime*2); + HP20X_IIC_WriteCmd(HP20X_READ_PT); + + Temperature=HP20X_IIC_ReadData(); + + Pressure=HP20X_IIC_ReadData3byte(); +} + +void IIC_ReadAltitudeAndTemperature(void) +{ + + HP20X_IIC_WriteCmd(HP20X_WR_CONVERT_CMD|OSR_CFG); + Timer_Delayxms(OSR_ConvertTime*2); + HP20X_IIC_WriteCmd(HP20X_READ_AT); + + Temperature=HP20X_IIC_ReadData(); + IIC_ACK(); + Altitude=HP20X_IIC_ReadData3byte(); + IIC_NoAck(); + IIC_Stop(); + +}*/ +/****************************************************************************/ +/*** Local Functions ***/ +/****************************************************************************/ + +/* + **@ Function name: HP20X_IIC_WriteCmd + **@ Description: + **@ Input: + **@ OutPut: + **@ Retval: +*/ +void HP20x_dev::HP20X_IIC_WriteCmd(uchar uCmd) +{ + /* Port to arduino */ + Wire.beginTransmission(HP20X_I2C_DEV_ID); + Wire.write(uCmd); + Wire.endTransmission(); +} + +/* + **@ Function name: HP20X_IIC_ReadReg + **@ Description: + **@ Input: + **@ OutPut: + **@ Retval: +*/ +uchar HP20x_dev::HP20X_IIC_ReadReg(uchar bReg) +{ + /* Port to arduino */ + uchar Temp = 0; + + /* Send a register reading command */ + HP20X_IIC_WriteCmd(bReg|HP20X_RD_REG_MODE); + + Wire.requestFrom(HP20X_I2C_DEV_ID, 1); + while(Wire.available()) + { + Temp = Wire.read(); + } + + return Temp; +} +/* + **@ Function name: HP20X_IIC_WriteReg + **@ Description: + **@ Input: + **@ OutPut: + **@ Retval: +*/ +void HP20x_dev::HP20X_IIC_WriteReg(uchar bReg,uchar bData) +{ + Wire.beginTransmission(HP20X_I2C_DEV_ID); + Wire.write(bReg|HP20X_WR_REG_MODE); + Wire.write(bData); + Wire.endTransmission(); +} + + +/* + **@ Function name: HP20X_IIC_ReadData + **@ Description: + **@ Input: + **@ OutPut: + **@ Retval: +*/ +ulong HP20x_dev::HP20X_IIC_ReadData(void) +{ + /* Port to arduino */ + ulong Temp = HP20X_IIC_ReadData3byte(); + return Temp; +} + +/* + **@ Function name: HP20X_IIC_ReadData3byte + **@ Description: + **@ Input: + **@ OutPut: + **@ Retval: +*/ +ulong HP20x_dev::HP20X_IIC_ReadData3byte(void) +{ + ulong TempData = 0; + ulong tmpArray[3]={0}; + int cnt = 0; + + /* Require three bytes from slave */ + Wire.requestFrom(HP20X_I2C_DEV_ID, 3); + + while(Wire.available()) // slave may send less than requested + { + uchar c = Wire.read(); // receive a byte as character + tmpArray[cnt] = (ulong)c; + cnt++; + } + + /* MSB */ + TempData = tmpArray[0]<<16 | tmpArray[1]<<8 | tmpArray[2]; + + + if(TempData&0x800000) + { + TempData|=0xff000000; + } + + /* // 24 bit to 32 bit + if(TempData&0x800000) + { + // 1:minus + TempData |= 0x80000000; + TempData &= 0xff7fffff; + } + else + { + // 0:plus + //do noting + } */ + return TempData; +} + + +/**************************************END OF FILE**************************************/ \ No newline at end of file diff --git a/lib/KalmanFilter.cpp b/lib/KalmanFilter.cpp new file mode 100644 index 0000000..4497eea --- /dev/null +++ b/lib/KalmanFilter.cpp @@ -0,0 +1,94 @@ +/* + * File name : KalmanFilter.cpp + * Description: Kalman Filter class + * Author : Oliver Wang from Seeed studio + * Version : V0.1 + * Create Time: 2014/04 + * Change Log : +*/ + +/****************************************************************************/ +/*** Include files ***/ +/****************************************************************************/ +#include +#include +#include +#include +#include + +/* random number table */ +float Rand_Table[100]={ +0.5377,1.8339,-2.2588,0.8622,0.3188,-1.3077,-0.4336,0.342,3.5784, +2.7694,-1.3499,3.0349,0.7254,-0.0631,0.7147,-0.2050,-0.1241,1.4897, +1.4090,1.4172,0.6715,-1.2075,0.7172,1.6302,0.4889,1.0347,0.7269, +-0.3034,0.2939,-0.7873,0.8884,-1.1471,-1.0689,-0.8095,-2.9443,1.4384, +0.3252,-0.7549,1.3703,-1.7115,-0.1022,-0.2414,0.3192,0.3129,-0.8649, +-0.0301,-0.1649,0.6277,1.0933,1.1093,-0.8637,0.0774,-1.2141,-1.1135, +-0.0068,1.5326,-0.7697,0.3714,-0.2256,1.1174,-1.0891,0.0326,0.5525, +1.1006,1.5442,0.0859,-1.4916,-0.7423,-1.0616,2.3505,-0.6156,0.7481, +-0.1924,0.8886,-0.7648,-1.4023,-1.4224,0.4882,-0.1774,-0.1961,1.4193, +0.2916,0.1978,1.5877,-0.8045,0.6966,0.8351,-0.2437,0.2157,-1.1658, +-1.1480,0.1049,0.7223,2.5855,-0.6669,0.1873,-0.0825,-1.9330,-0.439, +-1.7947}; + +/* Extern variables */ +KalmanFilter kalmanFilter; + +KalmanFilter::KalmanFilter() +{ + X_pre = 0; + P_pre = 0; + X_post = 0; + P_post = 0; + K_cur = 0; +} + +float KalmanFilter::Gaussian_Noise_Cov(void) +{ + int index = 0; + float tmp[10]={0.0}; + float average = 0.0; + float sum = 0.0; + /* Initialize random number generator */ + srand((int)analogRead(0)); + + /* Get random number */ + for(int i=0; i<10; i++) + { + index = (int)rand()%100; + tmp[i] = Rand_Table[index]; + sum += tmp[i]; + } + + /* Calculate average */ + average = sum/10; + + /* Calculate Variance */ + float Variance = 0.0; + for(int j = 0; j < 10; j++) + { + Variance += (tmp[j]-average)*(tmp[j]-average); + } + Variance/=10.0; + + return Variance; +} + +float KalmanFilter::Filter(float origin) +{ + float modelNoise = 0.0; + float observeNoise = 0.0; + + /* Get model and observe Noise */ + modelNoise = Gaussian_Noise_Cov(); + observeNoise = Gaussian_Noise_Cov(); + + /* Algorithm */ + X_pre = X_post; + P_pre = P_post + modelNoise; + K_cur = P_pre/(P_pre + observeNoise); + P_post = (1 - K_cur)*P_pre; + X_post = X_pre + K_cur*(origin - X_pre); + + return X_post; +} diff --git a/lib/MutichannelGasSensor.cpp b/lib/MutichannelGasSensor.cpp new file mode 100644 index 0000000..919f451 --- /dev/null +++ b/lib/MutichannelGasSensor.cpp @@ -0,0 +1,683 @@ +/* + MutichannelGasSensor.cpp + 2015 Copyright (c) Seeed Technology Inc. All right reserved. + + Author: Jacky Zhang + 2015-3-17 + http://www.seeed.cc/ + modi by Jack, 2015-8 + + 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. +*/ + +#include +#include +#include +#include "MutichannelGasSensor.h" + +/********************************************************************************************************* +** Function name: begin +** Descriptions: initialize I2C +*********************************************************************************************************/ +void MutichannelGasSensor::begin(int address) +{ + __version = 1; // version 1/2 + r0_inited = false; + + Wire.begin(); + i2cAddress = address; + __version = getVersion(); +} + +unsigned char MutichannelGasSensor::getVersion() +{ + if(get_addr_dta(CMD_READ_EEPROM, ADDR_IS_SET) == 1126) // get version + { + __version = 2; + Serial.println("version = 2"); + return 2; + } + + __version = 1; + Serial.println("version = 1"); + return 1; +} + +void MutichannelGasSensor::begin() +{ + begin(DEFAULT_I2C_ADDR); +} + +/********************************************************************************************************* +** Function name: sendI2C +** Descriptions: send one byte to I2C Wire +*********************************************************************************************************/ +void MutichannelGasSensor::sendI2C(unsigned char dta) +{ + Wire.beginTransmission(i2cAddress); // transmit to device #4 + Wire.write(dta); // sends one byte + Wire.endTransmission(); // stop transmitting +} + + +unsigned int MutichannelGasSensor::get_addr_dta(unsigned char addr_reg) +{ +START: + Wire.beginTransmission(i2cAddress); + Wire.write(addr_reg); + Wire.endTransmission(); // stop transmitting + + Wire.requestFrom(i2cAddress, 2); + + unsigned int dta = 0; + + unsigned char raw[10]; + int cnt = 0; + + while(Wire.available()) + { + raw[cnt++] = Wire.read(); + } + + if(cnt == 0)goto START; + + dta = raw[0]; + dta <<= 8; + dta += raw[1]; + + switch(addr_reg) + { + case CH_VALUE_NH3: + + if(dta > 0) + { + adcValueR0_NH3_Buf = dta; + } + else + { + dta = adcValueR0_NH3_Buf; + } + + break; + + case CH_VALUE_CO: + + if(dta > 0) + { + adcValueR0_CO_Buf = dta; + } + else + { + dta = adcValueR0_CO_Buf; + } + + break; + + case CH_VALUE_NO2: + + if(dta > 0) + { + adcValueR0_NO2_Buf = dta; + } + else + { + dta = adcValueR0_NO2_Buf; + } + + break; + + default:; + } + return dta; +} + +unsigned int MutichannelGasSensor::get_addr_dta(unsigned char addr_reg, unsigned char __dta) +{ + +START: + Wire.beginTransmission(i2cAddress); + Wire.write(addr_reg); + Wire.write(__dta); + Wire.endTransmission(); // stop transmitting + + Wire.requestFrom(i2cAddress, 2); + + unsigned int dta = 0; + + unsigned char raw[10]; + int cnt = 0; + + while(Wire.available()) + { + raw[cnt++] = Wire.read(); + } + + if(cnt == 0)goto START; + + dta = raw[0]; + dta <<= 8; + dta += raw[1]; + + + return dta; +} + +void MutichannelGasSensor::write_i2c(unsigned char addr, unsigned char *dta, unsigned char dta_len) +{ + Wire.beginTransmission(addr); + for(int i=0; i 100) + return -2;//time out + delay(2); + } + if(Wire.available() != 4) + return -3;//rtnData length wrong + buffer[0] = Wire.read(); + buffer[1] = Wire.read(); + buffer[2] = Wire.read(); + buffer[3] = Wire.read(); + checksum = (uint8_t)(buffer[0] + buffer[1] + buffer[2]); + if(checksum != buffer[3]) + return -4;//checksum wrong + rtnData = ((buffer[1] << 8) + buffer[2]); + + return rtnData;//successful +} + +/********************************************************************************************************* +** Function name: readR0 +** Descriptions: read R0 stored in slave MCU +*********************************************************************************************************/ +int16_t MutichannelGasSensor::readR0(void) +{ + int16_t rtnData = 0; + + rtnData = readData(0x11); + + if(rtnData > 0) + res0[0] = rtnData; + else + return rtnData; //unsuccessful + + rtnData = readData(0x12); + if(rtnData > 0) + res0[1] = rtnData; + else + return rtnData; //unsuccessful + + rtnData = readData(0x13); + if(rtnData > 0) + res0[2] = rtnData; + else + return rtnData; //unsuccessful + + return 1;//successful +} + +/********************************************************************************************************* +** Function name: readR +** Descriptions: read resistance value of each channel from slave MCU +*********************************************************************************************************/ +int16_t MutichannelGasSensor::readR(void) +{ + int16_t rtnData = 0; + + rtnData = readData(0x01); + if(rtnData >= 0) + res[0] = rtnData; + else + return rtnData;//unsuccessful + + rtnData = readData(0x02); + if(rtnData >= 0) + res[1] = rtnData; + else + return rtnData;//unsuccessful + + rtnData = readData(0x03); + if(rtnData >= 0) + res[2] = rtnData; + else + return rtnData;//unsuccessful + + return 0;//successful +} + +/********************************************************************************************************* +** Function name: readR +** Descriptions: calculate gas concentration of each channel from slave MCU +** Parameters: + gas - gas type +** Returns: + float value - concentration of the gas +*********************************************************************************************************/ +float MutichannelGasSensor::calcGas(int gas) +{ + + float ratio0, ratio1, ratio2; + if(1 == __version) + { + if(!r0_inited) + { + if(readR0() >= 0) r0_inited = true; + else return -1.0f; + } + + if(readR() < 0) + return -2.0f; + + ratio0 = (float)res[0] / res0[0]; + ratio1 = (float)res[1] / res0[1]; + ratio2 = (float)res[2] / res0[2]; + } + else if(2 == __version) + { + // how to calc ratio/123 + ledOn(); + int A0_0 = get_addr_dta(6, ADDR_USER_ADC_HN3); + int A0_1 = get_addr_dta(6, ADDR_USER_ADC_CO); + int A0_2 = get_addr_dta(6, ADDR_USER_ADC_NO2); + + int An_0 = get_addr_dta(CH_VALUE_NH3); + int An_1 = get_addr_dta(CH_VALUE_CO); + int An_2 = get_addr_dta(CH_VALUE_NO2); + + ratio0 = (float)An_0/(float)A0_0*(1023.0-A0_0)/(1023.0-An_0); + ratio1 = (float)An_1/(float)A0_1*(1023.0-A0_1)/(1023.0-An_1); + ratio2 = (float)An_2/(float)A0_2*(1023.0-A0_2)/(1023.0-An_2); + + } + + float c = 0; + + switch(gas) + { + case CO: + { + c = pow(ratio1, -1.179)*4.385; //mod by jack + break; + } + case NO2: + { + c = pow(ratio2, 1.007)/6.855; //mod by jack + break; + } + case NH3: + { + c = pow(ratio0, -1.67)/1.47; //modi by jack + break; + } + case C3H8: //add by jack + { + c = pow(ratio0, -2.518)*570.164; + break; + } + case C4H10: //add by jack + { + c = pow(ratio0, -2.138)*398.107; + break; + } + case CH4: //add by jack + { + c = pow(ratio1, -4.363)*630.957; + break; + } + case H2: //add by jack + { + c = pow(ratio1, -1.8)*0.73; + break; + } + case C2H5OH: //add by jack + { + c = pow(ratio1, -1.552)*1.622; + break; + } + default: + break; + } + + if(2==__version)ledOff(); + return isnan(c)?-3:c; +} + +/********************************************************************************************************* +** Function name: changeI2cAddr +** Descriptions: change I2C address of the slave MCU, and this address will be stored in EEPROM of slave MCU +*********************************************************************************************************/ +void MutichannelGasSensor::changeI2cAddr(uint8_t newAddr) +{ + Wire.beginTransmission(i2cAddress); // transmit to device + Wire.write(0x23); // sends one byte + Wire.write(newAddr); // sends one byte + Wire.endTransmission(); // stop transmitting + i2cAddress = newAddr; +} + +/********************************************************************************************************* +** Function name: doCalibrate +** Descriptions: tell slave to do a calibration, it will take about 8s + after the calibration, must reread the R0 values +*********************************************************************************************************/ +void MutichannelGasSensor::doCalibrate(void) +{ + + if(1 == __version) + { + START: + + sendI2C(0x22); + if(readR0() > 0) + { + for(int i=0; i<3; i++) + { + Serial.print(res0[i]); + Serial.print('\t'); + } + } + else + { + delay(5000); + Serial.println("continue..."); + for(int i=0; i<3; i++) + { + Serial.print(res0[i]); + Serial.print('\t'); + } + Serial.println(); + goto START; + } + } + else if(2 == __version) + { + unsigned int i, a0, a1, a2; + while(1) + { + a0 = get_addr_dta(CH_VALUE_NH3); + a1 = get_addr_dta(CH_VALUE_CO); + a2 = get_addr_dta(CH_VALUE_NO2); + + Serial.print(a0); + Serial.print('\t'); + Serial.print(a1); + Serial.print('\t'); + Serial.print(a2); + Serial.println('\t'); + ledOn(); + + int cnt = 0; + for(i=0; i<20; i++) + { + if((a0 - get_addr_dta(CH_VALUE_NH3)) > 2 || (get_addr_dta(CH_VALUE_NH3) - a0) > 2)cnt++; + if((a1 - get_addr_dta(CH_VALUE_CO)) > 2 || (get_addr_dta(CH_VALUE_CO) - a1) > 2)cnt++; + if((a2 - get_addr_dta(CH_VALUE_NO2)) > 2 || (get_addr_dta(CH_VALUE_NO2) - a2) > 2)cnt++; + + if(cnt>5) + { + break; + } + delay(1000); + } + + ledOff(); + if(cnt <= 5)break; + delay(200); + } + + Serial.print("write user adc value: "); + Serial.print(a0);Serial.print('\t'); + Serial.print(a1);Serial.print('\t'); + Serial.print(a2);Serial.println('\t'); + + unsigned char tmp[7]; + + tmp[0] = 7; + + tmp[1] = a0>>8; + tmp[2] = a0&0xff; + + tmp[3] = a1>>8; + tmp[4] = a1&0xff; + + tmp[5] = a2>>8; + tmp[6] = a2&0xff; + + write_i2c(i2cAddress, tmp, 7); + } +} + +/********************************************************************************************************* +** Function name: powerOn +** Descriptions: power on sensor heater +*********************************************************************************************************/ +void MutichannelGasSensor::powerOn(void) +{ + if(__version == 1) + sendI2C(0x21); + else if(__version == 2) + { + dta_test[0] = 11; + dta_test[1] = 1; + write_i2c(i2cAddress, dta_test, 2); + } +} + +/********************************************************************************************************* +** Function name: powerOff +** Descriptions: power off sensor heater +*********************************************************************************************************/ +void MutichannelGasSensor::powerOff(void) +{ + if(__version == 1) + sendI2C(0x20); + else if(__version == 2) + { + dta_test[0] = 11; + dta_test[1] = 0; + write_i2c(i2cAddress, dta_test, 2); + } +} + +void MutichannelGasSensor::display_eeprom() +{ + if(__version == 1) + { + Serial.println("ERROR: display_eeprom() is NOT support by V1 firmware."); + return ; + } + + Serial.print("ADDR_IS_SET = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_IS_SET)); + Serial.print("ADDR_FACTORY_ADC_NH3 = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_NH3)); + Serial.print("ADDR_FACTORY_ADC_CO = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_CO)); + Serial.print("ADDR_FACTORY_ADC_NO2 = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_NO2)); + Serial.print("ADDR_USER_ADC_HN3 = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_HN3)); + Serial.print("ADDR_USER_ADC_CO = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_CO)); + Serial.print("ADDR_USER_ADC_NO2 = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_NO2)); + Serial.print("ADDR_I2C_ADDRESS = "); Serial.println(get_addr_dta(CMD_READ_EEPROM, ADDR_I2C_ADDRESS)); +} + +float MutichannelGasSensor::getR0(unsigned char ch) // 0:CH3, 1:CO, 2:NO2 +{ + if(__version == 1) + { + Serial.println("ERROR: getR0() is NOT support by V1 firmware."); + return -1; + } + + int a = 0; + switch(ch) + { + case 0: // CH3 + a = get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_HN3); + Serial.print("a_ch3 = "); + Serial.println(a); + break; + + case 1: // CO + a = get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_CO); + Serial.print("a_co = "); + Serial.println(a); + break; + + case 2: // NO2 + a = get_addr_dta(CMD_READ_EEPROM, ADDR_USER_ADC_NO2); + Serial.print("a_no2 = "); + Serial.println(a); + break; + + default:; + } + + float r = 56.0*(float)a/(1023.0-(float)a); + return r; +} + +float MutichannelGasSensor::getRs(unsigned char ch) // 0:CH3, 1:CO, 2:NO2 +{ + + if(__version == 1) + { + Serial.println("ERROR: getRs() is NOT support by V1 firmware."); + return -1; + } + + int a = 0; + switch(ch) + { + case 0: // NH3 + a = get_addr_dta(1); + break; + + case 1: // CO + a = get_addr_dta(2); + break; + + case 2: // NO2 + a = get_addr_dta(3); + break; + + default:; + } + + float r = 56.0*(float)a/(1023.0-(float)a); + return r; +} + +// 1. change i2c address to 0x04 +// 2. change adc value of R0 to default +void MutichannelGasSensor::factory_setting() +{ + + unsigned char tmp[7]; + + unsigned char error; + unsigned char address = 0; + + for(address = 1; address < 127; address++ ) + { + // The i2c_scanner uses the return value of + // the Write.endTransmisstion to see if + // a device did acknowledge to the address. + Wire.beginTransmission(address); + error = Wire.endTransmission(); + + if (error == 0) + { + // change i2c to 0x04 + + Serial.print("I2C address is: 0x"); + Serial.println(address, HEX); + Serial.println("Change I2C address to 0x04"); + + dta_test[0] = CMD_CHANGE_I2C; + dta_test[1] = 0x04; + write_i2c(address, dta_test, 2); + + i2cAddress = 0x04; + delay(100); + getVersion(); + break; + } + } + + unsigned int a0 = get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_NH3); + unsigned int a1 = get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_CO); + unsigned int a2 = get_addr_dta(CMD_READ_EEPROM, ADDR_FACTORY_ADC_NO2); + + tmp[0] = 7; + tmp[1] = a0>>8; + tmp[2] = a0&0xff; + tmp[3] = a1>>8; + tmp[4] = a1&0xff; + + tmp[5] = a2>>8; + tmp[6] = a2&0xff; + delay(100); + write_i2c(i2cAddress, tmp, 7); + delay(100); +} + +void MutichannelGasSensor::change_i2c_address(unsigned char addr) +{ + dta_test[0] = CMD_CHANGE_I2C; + dta_test[1] = addr; + write_i2c(i2cAddress, dta_test, 2); + + + Serial.print("FUNCTION: CHANGE I2C ADDRESS: 0X"); + Serial.print(i2cAddress, HEX); + Serial.print(" > 0x"); + Serial.println(addr, HEX); + + i2cAddress = addr; +} + +MutichannelGasSensor gas; +/********************************************************************************************************* + END FILE +*********************************************************************************************************/ \ No newline at end of file