2017年5月3日 星期三

Arduino MQ-3 MQ-4 MQ-8 氣體感測器

     MQ 系列感測器又稱為半導體式感測器一般都是用二氧化錫(SnO2) 為基材,二氧化錫在清潔空氣中(含80的氮氣20%的氧氣與少許CO2)導電率非常低,氧化物特點就是本身的活性常低,可長時間保持在同一種狀態,MQ系列感測器壽命可超過20年,二氧化錫(SnO2) 在可燃氣體的催化導電率會升高。MQ系列的結構如下 H 是加溫結構,在加溫後活性氣體通過二氧化錫(SnO2) 時就會改變導電率,只要監測導電率就能判別氣體濃度。

   這是Winsensor 出品的 MQ8 感測器的導電率曲線,MQ8是針對氫氣開發出來的感測器,這圖表能看到紅色的空氣不管濃度多高都不會影響MQ8的導電率,氫氣濃度增加時導電率也會跟著升高,其他顏色是所謂的干擾氣體,也就是乙醇、一氧化碳、甲烷等都會干擾到MQ8的導電率。

下圖是MQ8的溫溼度與導電率的曲線,由此表可看出溫度濕度會影響MQ8的導電率。


   這張圖表是指出當氣體濃度增加時感測器輸出的電壓值,在這張圖表可發現當氣體濃度增加到300ppm後曲線開始平緩到1500ppm時幾乎快成直線。


這是反應時間曲線。

   這是時間變化曲線,把MQ8放在300ppm濃度的氫氣下的輸出電壓變化,由此圖再配合輸出電壓曲線可知MQ8的在300ppm後幾乎不可使用。
 MQ 系列雖然在高濃度時超級不準確但是還有以下優點

1.壽命超長
2.使用簡單
3.價格便宜

     也就是有以上這些優點MQ系列感測器大量應用在氣體洩漏、煙霧感測警報器,這些本來自然界就不該存在的氣體一但洩漏在空氣中超過200ppm~300ppm就發出警報很多人都能接受,只是要拿來當定量使用幾乎不太可能,以下的程式還是照著Datasheet 的曲線期望解出MQ系列的濃度曲線,注意這只是理論!!在上圖MQ8的輸出曲線可得知當超過1500ppm後的電壓變化輸入到只有10bit A/D 轉換器的Arduino根本沒意義。


// 載入 LCD  Library
#include <LiquidCrystal.h>

//      LCD 接腳:  rs, enable, d4, d5, d6, d7
LiquidCrystal  lcd(13, 12, 11, 10 , 9, 8);

/********************* 硬體設定  *************************************/

#define         MQ_3_PIN                         (0)     // MQ_3 輸入腳
#define         MQ_8_PIN                         (1)     // MQ_8 輸入腳
#define         MQ_4_PIN                         (2)     // MQ_4 輸入腳
#define         RL_VALUE                         (5)    // RL電阻為 10K歐姆
#define         MQ_3_Ro_CLEAN_AIR_FACTOR         (1)    //MQ_3在乾淨空氣中的電阻/MQ_3_Ro,
#define         MQ_8_Ro_CLEAN_AIR_FACTOR         (1)    //MQ_8在乾淨空氣中的電阻/MQ_8_Ro,
#define         MQ_4_Ro_CLEAN_AIR_FACTOR         (1)    //MQ_4在乾淨空氣中的電阻/MQ_4_Ro,
                                                   

/*********************** 軟體設定  ************************************/

#define         CALIBARAION_SAMPLE_TIMES     (50)    //設定校準時樣品讀取次數
#define         CALIBRATION_SAMPLE_INTERVAL  (100)   //設定較準時每次讀取採樣的時間間隔(ms)
                                                   
#define         READ_SAMPLE_INTERVAL         (50)    //測試時用幾次的檢測值的平均值
#define         READ_SAMPLE_TIMES            (5)         //測試時每次取樣的間隔時間(ms)
                                         
#define         GAS_Alcohol                  (0)
#define         GAS_H2                       (1)
#define         GAS_CH4                      (2)

/*****************************Globals***********************************************/

float           AlcoholCurve[3]   =  {1.7, -0.77,-1};      // 這斜率參考MQ-3的 Datasheet
                                                                                 
float           MQ_3_Ro           =  10;                           //MQ_3_Ro 的預設值

float           H2Curve[3]        =  {2, -0.6,-1};         // 這斜率參考MQ-8的 Datasheet
                                                                         
float           MQ_8_Ro           =  10;                       //MQ_8_Ro 的預設值

float           CH4Curve[3]       =  {2.48, -0.62,-0.4};   // 這斜率參考MQ-4的 Datasheet
                                                         

float           MQ_4_Ro           =  10;                    //MQ_4_Ro 的預設值


void setup()
{
  lcd.begin(20, 4);                                   //設定 LCM 為 20*4
  lcd.print("Calibrating..");                         //LCM 輸出 Calibrating...
  MQ_3_Ro = MQ_3Calibration(MQ_3_PIN);                //開機校正要確保這段時間內為乾淨空氣
  MQ_8_Ro = MQ_8Calibration(MQ_8_PIN);                //開機校正要確保這段時間內為乾淨空氣
  MQ_4_Ro = MQ_4Calibration(MQ_4_PIN);                //開機校正要確保這段時間內為乾淨空氣
}

void loop()
{
lcd.setCursor(0, 0);                                                 // LCM 游標移到位置 0,0
   lcd.print("Alcohol: ");                                           //顯示文字 Alcohol
   lcd.setCursor(8,0);                                               //LCM 游標移到位置 8,0
   lcd.print(MQ_3GetGasPercentage(MQ_3Read(MQ_3_PIN)/MQ_3_Ro,GAS_Alcohol )); //顯示測到的Alcohol值
   lcd.print(" ppm     ");                                           //LCM 顯示 PPm
   lcd.setCursor(0, 1);                                                 // LCM 游標移到位置 0,0
   lcd.print("  H2  :  ");                                           //顯示文字 H2
   lcd.setCursor(8,1);                                             //LCM 游標移到位置 8,0
   lcd.print(MQ_8GetGasPercentage(MQ_8Read(MQ_8_PIN)/MQ_8_Ro,GAS_H2 )); //顯示測到的H2值
   lcd.print(" ppm     ");                                           //LCM 顯示 PPm
   lcd.setCursor(0, 2);                                                 // LCM 游標移到位置 0,0
   lcd.print("  CH4 :  ");                                           //顯示文字 CH4
   lcd.setCursor(8,2);                                               //LCM 游標移到位置 8,0
   lcd.print(MQ_4GetGasPercentage(MQ_4Read(MQ_4_PIN)/MQ_4_Ro,GAS_CH4 )); //顯示測到的CH4值
   lcd.print(" ppm     ");                                           //LCM 顯示 PPm
   delay(1000);
}

/****************** MQ_Sensor 電阻值換算 ****************************************/



 float MQ_3ResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}

float MQ_8ResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));

}

float MQ_4ResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}

/***************************** MQ_Sensor 校正 ****************************************/

float MQ_3Calibration(int MQ_3_pin)
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {          
    val += MQ_3ResistanceCalculation(analogRead(MQ_3_pin));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                

  val = val/MQ_3_Ro_CLEAN_AIR_FACTOR;                      

  return val;
}

float MQ_8Calibration(int MQ_8_pin)
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {          
    val += MQ_8ResistanceCalculation(analogRead(MQ_8_pin));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                

  val = val/MQ_8_Ro_CLEAN_AIR_FACTOR;                      

  return val;
}

float MQ_4Calibration(int MQ_4_pin)
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {          
    val += MQ_4ResistanceCalculation(analogRead(MQ_4_pin));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                

  val = val/MQ_4_Ro_CLEAN_AIR_FACTOR;                      

  return val;
}


/*****************************  MQ_Sensor 讀取*********************************************/


 float MQ_3Read(int MQ_3_pin)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQ_3ResistanceCalculation(analogRead(MQ_3_pin));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;
}

float MQ_8Read(int MQ_8_pin)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQ_8ResistanceCalculation(analogRead(MQ_8_pin));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;
}

float MQ_4Read(int MQ_4_pin)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQ_4ResistanceCalculation(analogRead(MQ_4_pin));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;
}

/*****************************  MQ_Sensor 換算ppm **********************************/


int MQ_3GetGasPercentage(float rs_MQ_3_Ro_ratio, int gas_id)
{
  if ( gas_id == GAS_Alcohol) {
     return MQ_3GetPercentage(rs_MQ_3_Ro_ratio,AlcoholCurve);
  }
  return 0;
}

int MQ_8GetGasPercentage(float rs_MQ_8_Ro_ratio, int gas_id)
{
  if ( gas_id == GAS_H2) {
     return MQ_8GetPercentage(rs_MQ_8_Ro_ratio,H2Curve);
  }
  return 0;
}


int MQ_4GetGasPercentage(float rs_MQ_4_Ro_ratio, int gas_id)
{
  if ( gas_id == GAS_CH4) {
     return MQ_4GetPercentage(rs_MQ_4_Ro_ratio,CH4Curve);
  }
  return 0;
}

/*****************************   計算RS MQ_Ro 百分比  **********************************/


int  MQ_3GetPercentage(float rs_MQ_3_Ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_MQ_3_Ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}

int  MQ_8GetPercentage(float rs_MQ_8_Ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_MQ_8_Ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}


int  MQ_4GetPercentage(float rs_MQ_4_Ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_MQ_4_Ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}


上傳後就會顯示個感測器的值,注意這是沒校正過的只能當參考 !!


     當然還有其他氣體感測器可選擇,比如有比較好的高濃度曲線的平面半導體製程MP系列,催化燃燒的MC系列,幾乎可線性輸出的電化學系列,還有使元紅外線的NDIR技術。會常用來半定量使用的是電化學與NDIR技術,只是電化學感測器(NT$ 1500~4000 )壽命只有兩年!!不管有沒有使用出廠後就只有兩年壽命,NDIR技術雖然貴一點(NT$ 3000~5000 ) 可用5年,MQ售價只要 NT$ 50~3002。

1 則留言: