2016年3月12日

Arduino 二氧化碳感測器MG811 校正計算

==============================
MG811
半年多前,幾個朋友都買了二氧化碳感測器,我也上網去買了一個MG811 ,可是買了之後,就沒再動過了。最近對空氣品質很感興趣,所以就把這個感測器挖出來,想要來利用一下。

接的方式很容易,感測器是類比輸出,所以就把Signal接A0,其他的紅線就接5V,黑線接Gnd。但這個氣體偵測器的內部需要加熱,所以arduino要再接上9V外接電源(至少需要7~12V,>500mA )

arduino+MG811

接好之後,用最簡單的程式碼就可以用arduino得到傳來的類比數值
==============================

void setup(){
   
  Serial.begin(9600);
   
}
void loop(){
  Serial.print("Sample value:");
  Serial.println(analogRead(0));
  delay(100);
}


==============================

但問題是,這傳來的數值,要怎麼轉換成二氧化碳濃度?

Datasheet中可以看到二氧化碳濃度的對數值和輸出電壓成反比,所以我要作的事情有以下幾步。利用已知的二氧化碳濃度(至少兩個)得到校正線的公式,再把輸出電壓套進公式裡,就可以得到未知的二氧化碳濃度了。


datasheet


如何得知已知的二氧化碳濃度?我從以下文章看到作法
A Prototype Carbon Dioxide (CO2) Indoor Air Quality Monitor with Digital Display and SD Card Data Logger for under £55

可用室外空氣和人體呼氣來進行校正,室外空氣的二氧化碳濃度是400ppm,而人體呼氣的二氧化碳濃度是40000ppm(4%),所以我只要用上頭那個程式碼去偵測這兩個濃度時,感測器的輸出電壓是多少就可以計算了。

說是簡單,但校正其實挺費時的。
1.上傳讀出A0數值的程式碼
2.把3.3v接入A0,看看呈現的數值是否穩定,應該要是(3.3/5)*1024=675.84,約是676左右。
3.讓讓感測器進入穩定的狀態,擺在無人房間內運作至少48小時,在讀值前至少讓元件加熱兩小時。
4.確保房間無人且通風,此時測出的類比值為400ppm的數值
5.準備一個大型塑膠袋,把感測器不關機放入塑膠袋裡,利用吹管向裡頭吐氣,記得封好塑膠袋口,避免環境氣體進入。五分鐘後,看看讀值是否穩定,此為40000ppm下的讀值。

有了這兩個數值之後,就可以進行校正了,公式計算就如下面幾張圖所示

HowTo1
HowTo2
HowTo3


在這兩個網頁中,都有校正二氧化碳的程式碼,可以參考
http://www.dfrobot.com/wiki/index.php/CO2_Sensor_SKU:SEN0159
http://www.veetech.org.uk/Prototype_CO2_Monitor.htm


我根據我這邊的程序修改第一個網址裡的程式碼,如下所示,如需重新校正,只要更改下面(984)和(745)裡的數值。當發現感測器測量室外空氣,沒有辦法得到400ppm左右的數值,就需要重新校正了。
#define         V400        (984)                 //測量室外空氣得到的AnalogValue(400ppm)
#define         V40000   (745)                  //測量呼氣得到的AnalogValue(40000ppm)


plot1


plot2


程式碼可由此下載,或是下面複製貼上

另外,以下兩篇也有提及分析方式,






==============================
/*******************Demo for MG-811 Gas Sensor Module V1.1*****************************
Author:  Tiequan Shao: tiequan.shao@sandboxelectronics.com
         Peng Wei:     peng.wei@sandboxelectronics.com
          
Lisence: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
 
Note:    This piece of source code is supposed to be used as a demostration ONLY. More
         sophisticated calibration is required for industrial field application. 
          
                                                    Sandbox Electronics    2012-05-31

Modify by ChihhsiangChien
************************************************************************************/
 
/************************Hardware Related Macros************************************/
#define         MG_PIN                       (0)     //define which analog input channel you are going to use
#define         BOOL_PIN                     (2)
#define         DC_GAIN                      (8.5)   //define the DC gain of amplifier
 
 
/***********************Software Related Macros************************************/
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interval(in milisecond) between each samples in 
                                                     //normal operation
 
/**********************Application Related Macros**********************************/
//These two values differ from sensor to sensor. user should derermine this value.
#define         V400        (984)                 //測量室外空氣得到的AnalogValue(400ppm)
#define         V40000   (745)                  //測量呼氣得到的AnalogValue(40000ppm)
 
/*****************************Globals***********************************************/
 float slope=(V40000-V400)/(4.602-2.602);
           //校正線的斜率計算
           //log40000=4.602
           //log400=2.602

int DisplayMode=2; //1是呈現資訊  2是只有二氧化碳濃度,可供Serial Plot
void setup()
{
    Serial.begin(9600);                              //UART setup, baudrate = 9600bps
    pinMode(BOOL_PIN, INPUT);                        //set pin to input
    digitalWrite(BOOL_PIN, HIGH);                    //turn on pullup resistors


}
 
void loop()
{
    int percentage;
    float analogValue;
    float volts;
     
    
    analogValue = MGRead(MG_PIN);
    volts=analogValue*5/1024;
    percentage = MGGetPercentage(analogValue);

if (DisplayMode==1){
    Serial.print(analogValue);
    Serial.print( "\t" );
    
    Serial.print(volts); 
    Serial.print( "V" );
    Serial.print( "\t" );
    
    Serial.print("CO2:");
    Serial.print(percentage);
    Serial.print( "ppm" );  
    Serial.print( "\t" );
    
    Serial.print( "Time point:" );
    Serial.print(millis());
    Serial.print("\n"); 
  }else{
    Serial.println(percentage);
  }
     
    delay(200);
}
 
 
 
/*****************************  MGRead *********************************************
Input:   mg_pin - analog channel
Output:  output of SEN-000007
Remarks: This function reads the output of SEN-000007
************************************************************************************/
float MGRead(int mg_pin)
{
    int i;
    float v=0;
 
    for (i=0;i<READ_SAMPLE_TIMES;i++) {
        v += analogRead(mg_pin);
        delay(READ_SAMPLE_INTERVAL);
    }
    v =v/READ_SAMPLE_TIMES ;
    return v;  
}
 
/*****************************  MQGetPercentage **********************************
輸入讀入的AnalogValue,利用公式轉換成二氧化碳濃度
二氧化碳濃度的對數值與AnalogValue相關,
************************************************************************************/
int  MGGetPercentage(float analogValue)
{   
     float logConc=2.602 +(analogValue-V400)/slope; //計算目前二氧化碳的濃度log值
      return pow(10,logConc );
 
}