PM2.5检测仪设计

目前市场上的大多数空气净化器的传感器采用烟尘传感器,例如夏普的GP2Y1010AU, 该传感器能够检测出大于0.8um直径的灰尘,因为我们现在空气中的主要污染物为PM2.5,所以通过一定的算法能够大致让其表示出当前的空气质量指数。下图为CC2540最小系统与GP2Y1010AU组合起来的PM2.5检测仪,房间里计算出来的空气质量指数似乎比官方通报的差一级。


下面是GPY1010AU的采样电路与采样方式,该传感器通过光探测灰尘浓度,需要MCU一个PIN脚产生低脉冲,然后在低脉冲0.32ms的位置进行ADC的转换。



下图为该传感器的外围设计电路,也就是上图中转接板的电路


通过一个三极管控制第3个引脚产生低脉冲,将第5引脚输出的烟尘数据通过R14,R15进行分压以适应MCU ADC的参考电压。

下面是GPY1010AU在CC2540裸机上的核心代码

#include<ioCC2540.h>
#include<stdio.h>

#include "gp2y1010au.h"

int dustPin=0;
 
int ledPower=2;
int delayTime=10;
int delayTime2=3;
int offTime=15000;

void delayMicroseconds(unsigned int microSec)
{
  unsigned int i,j;
  for(i=0;i<microSec;i++)
    for(j=0;j<5;j++);
  return;
}

void InitGp2y1010au(void)
{
  ADCCON1 = 0x33;//软件启动转换
  ADCCON3 = 0x30;//AVIN0
  //TR0 = 0x01; //avin, not internal 
  //ATEST = 0x01;
//  ADCCON1 |= 0x40;//软件启动转换
  
   P1DIR |= 0X01;/*output mode*/
}

void ledPowerSet(unsigned char val)
{
  LED_POWER_CTRL = val;
}

unsigned short somkeValAdcRead(void)
{
  unsigned short AdValue=0;
  unsigned char ADCVal_L,ADCVal_H;
  
  //InitGp2y1010au();
  //ADCCON1 = 0x33;
  ADCCON3 = 0x30;//AVIN0
  ADCCON1 = 0x73;
  while(!(ADCCON1 & 0x80));
  ADCVal_L = ADCL;
  ADCVal_H = ADCH;
  AdValue = ADCVal_L >>2;
  AdValue |= ADCVal_H <<6;
  
  return AdValue; 
}
 
unsigned short smokeDetect(void){
  unsigned short dustVal=0;
  
  // ledPower is any digital pin on the arduino connected to Pin 3 on the sensor
  ledPowerSet(1); 
  delayMicroseconds(delayTime);
  dustVal=somkeValAdcRead(); 
  delayMicroseconds(delayTime2);
  ledPowerSet(0); 
  delayMicroseconds(offTime);
 
  //delayMicroseconds(1000);
  /*if (dustVal>36.455)
    Serial.println((float(dustVal/1024)-0.0356)*120000*0.035);*/
  return dustVal;
}


 

>


上面的代码读出的是ADC的码字,需要转换为烟尘的浓度,转换方法参看datasheet提供的烟尘与电压关系曲线,如下图所示



转换的浓度信息为mg/m3, 在天气预报中的空气质量是叫一种空气质量指数的指标表示的,也就是AQI.

 

空气质量指数(Air Quality Index,简称AQI),是一个用来定量描述空气质量水平的数值。AQI的取值范围位于0 – 500 之间。


空气质量指数是根据各种污染物的浓度值换算出来的。要计算AQI,就需要事先确定各污染物在不同空气质量水平下的浓度限值。例如,美国环保局(EPA)针对PM2.5的限值定义如下:



AQI的计算公式如下:



其中:
I = 空气质量指数,即AQI,输出值;
C = 污染物浓度,输入值;
Clow= 小于或等于C的浓度限值,常量;
Chigh= 大于或等于C的浓度限值,常量;
Ilow= 对应于Clow的指数限值,常量;
Ihigh= 对应于Chigh的指数限值,常量。


转换部分的核心代码如下


unsigned short rawVal2_to_ugPerM3(unsigned short rawVal)
{
  unsigned int ugPerM3Val;
  unsigned int adc_mVolt;
  unsigned long temp;
  
  temp = (long)2300*(long)rawVal;
  adc_mVolt = (long)temp/(long)8192;
  
  temp = (long)10000*(long)(adc_mVolt - 625);//ug * 10times for float compute
  
  ugPerM3Val = temp/5750;
  
  return (unsigned short)ugPerM3Val;
}

unsigned short ugPerM3_to_AQI(unsigned short ugPerM3)
{
  unsigned short AQI;
  unsigned short Clow, Chigh, Ilow, Ihigh;
  
  
  if((ugPerM3>C_LOW_1)&&(ugPerM3<C_HIGH_1))
  {
    Clow= C_LOW_1;
    Chigh = C_HIGH_1;
    Ilow = I_LOW_1;
    Ihigh = I_HIGH_1;
  }
  else if((ugPerM3>C_LOW_2)&&(ugPerM3<C_HIGH_2))
  {
    Clow= C_LOW_2;
    Chigh = C_HIGH_2;
    Ilow = I_LOW_2;
    Ihigh = I_HIGH_2;
  }
  else if((ugPerM3>C_LOW_3)&&(ugPerM3<C_HIGH_3))
  {
    Clow= C_LOW_3;
    Chigh = C_HIGH_3;
    Ilow = I_LOW_3;
    Ihigh = I_HIGH_3;
  }
  else if((ugPerM3>C_LOW_4)&&(ugPerM3<C_HIGH_4))
  {
    Clow= C_LOW_4;
    Chigh = C_HIGH_4;
    Ilow = I_LOW_4;
    Ihigh = I_HIGH_4;
  }
  else if((ugPerM3>C_LOW_5)&&(ugPerM3<C_HIGH_5))
  {
    Clow= C_LOW_5;
    Chigh = C_HIGH_5;
    Ilow = I_LOW_5;
    Ihigh = I_HIGH_5;
  }
  else if((ugPerM3>C_LOW_6)&&(ugPerM3<C_HIGH_6))
  {
    Clow= C_LOW_6;
    Chigh = C_HIGH_6;
    Ilow = I_LOW_6;
    Ihigh = I_HIGH_6;
  }
  else if((ugPerM3>C_LOW_7)&&(ugPerM3<C_HIGH_7))
  {
    Clow= C_LOW_7;
    Chigh = C_HIGH_7;
    Ilow = I_LOW_7;
    Ihigh = I_HIGH_7;
  }
  else//full
  {
    return I_HIGH_7;
  }
  
  AQI = (long)(Ihigh-Ilow)*(long)(ugPerM3-Clow)/(long)(Chigh-Clow) + (long)Ilow;
  
  return AQI;
}

/***************************
          主函数
***************************/
void main(void)
{
  unsigned short smokeVal;
  unsigned short ugPerM3Val;
  unsigned short AQIval;
  //LED端口初始化
  OLED_Init();			//初始化OLED  
  OLED_Clear();
  InitGp2y1010au();
  
  oledDisplayLabel();
  while(1)
  {
    smokeVal = smokeDetect();
    ugPerM3Val = rawVal2_to_ugPerM3(smokeVal);
    AQIval = ugPerM3_to_AQI(ugPerM3Val);
    gp2y1010auDisplay(AQIval);
  }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章