单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:6371|回复:2
打印上一主题下一主题

基于夏普DN7C3CA002及arduino UNO的PM2.5监测装置

[复制链接]
跳转到指定楼层
楼主
ID:113207发表于 2016-4-11 01:41|只看该作者|只看大图回帖奖励
DN7C3CA001是夏普新发布的PM2.5传感器,次传感器能够切割滤除粒径大于2.5微米的粒子通过光传感器元件,从而真正实现对粒径小于等于2.5微米的颗粒物的监测,具体介绍请参考。


图1. 粒径切割原理图


拿到手的型号是DN7C3CA002改进版。根据传感器手册中的接线方法可以发现,除了物理排线线序相反以及需要接风扇的供电电路外,其它引脚接线方法与GP2Y1010AU0F相同。


图2. 接线原理图


DN7C3CA002与GP2Y1010AU0F的脉冲采样参数和采样时长都是一样的,猜测两者采用的是类似的光学器件。


图3. 采样脉冲



图4. 采样时间


传感器采用电压输出方式,手册中给出了输出电压与PM2.5质量浓度之间的关系:


图5. 输出电压与质量浓度关系


其中Vo是输出电压(电压单位都是mV),Vs是基准电压,Vs基准电压的获取有两种方式,一种方式是从传感器的序列号中读出,由于我拿到的这颗传感器无序列号,所以只有采用第二种方式,通过不接风扇电源将传感器垂直放置几分钟后读出的输出电压。

同时传感器需要对Vs基准电压进行温度补偿,修正参考值同样除了可以从传感器序列号中读出外也可以通过测量得到。


图6. 温度修正曲线


在-10~40℃约6mV/℃,40~60℃约1.5mV/℃。测量拿到的这颗传感器的Vs基准电压非常低,远远达不到图6中两条曲线的电压值,不知道是电路问题还是传感器自身的问题。

为了能够根据实时温度修正Vs基准电压,使用sht10获取温度和湿度数据。同时使用lcd1602作为显示输出,基于Arduino UNO组成主控电路。


图7. 装置运行



图8. 内部结构


程序代码在arduino IDE 0023上通过: pmkit.rar(1.47 KB, 下载次数: 9),需要sht1x库的支持。
  1. #include
  2. #include

  3. #define LCD_led 9
  4. #define clockPin A0
  5. #define dataPin  A1
  6. #define DUSTOUTpin A2       //read dust value from this pin
  7. #define DUSTLEDpin A3     //control dust led through this pin

  8. LiquidCrystal lcd(2, 4, 5, 6, 7, 8);
  9. SHT1x sht1x(dataPin, clockPin);

  10. const int delayTime=280;
  11. const int delayTime2=40;
  12. const float offTime=9680;

  13. float temp_c=0.0;
  14. float humidity=0.0;
  15. double dustVal=0.0;
  16. double voteChange = 5000.0 /1024.0;   //mV
  17. #define FREEPMVALUE 3
  18. #define FREEPMTEMP 31.0
  19. #define BASERATIO40 6   //mV
  20. #define BASERATIO60 1.5   //mV
  21. #define PMFIX 0 // 25 ug/m3
  22. #define PMRATIO 0.6
  23. #define DOBASEFIX false

  24. #define NSAMPLES 100
  25. uint8_t sampleCount = 0;
  26. int sampleSumPm = 0;
  27. int dustLevel=0;

  28. //moving average filter
  29. #define NULLVALUE -1.0
  30. #define MOVINGAVERAGECOUT 10
  31. double pm2_5[MOVINGAVERAGECOUT];
  32. uint8_t arrNewPoint = 0;

  33. static void initFilterArray()
  34. {
  35.   for(int i=0;i<movingaveragecout;i++)
  36.   {
  37.    pm2_5[i]=NULLVALUE;
  38.   }
  39. }

  40. int readPM(){
  41.   // ledPower is any digital pin on the arduino connected to Pin 3 on the sensor
  42.   digitalWrite(DUSTLEDpin,LOW);// power on the LED
  43.   delayMicroseconds(delayTime);
  44.   int Val = analogRead(DUSTOUTpin); // read the dust value via pin 5 on the sensor
  45.   delayMicroseconds(delayTime2);
  46.   digitalWrite(DUSTLEDpin,HIGH); // turn the LED off
  47.   delayMicroseconds(offTime);  
  48.   return Val;
  49. }

  50. void setup() {
  51.   pinMode(LCD_led, OUTPUT);
  52.   digitalWrite(LCD_led, HIGH);

  53.   pinMode(DUSTLEDpin,OUTPUT);
  54.   digitalWrite(DUSTLEDpin,HIGH);// turn the LED off

  55.   initFilterArray();

  56.   lcd.begin(16, 2);

  57.   lcd.print("System Warming!");
  58.   //Serial.begin(9600);
  59.   delay(5000);
  60.   lcd.clear();
  61.   lcd.setCursor(0, 0);
  62.   lcd.print("PM2.5:");
  63.   lcd.setCursor(11, 0);
  64.   lcd.print("ug/m3");

  65.   lcd.setCursor(5, 1);
  66.   lcd.print("C");
  67.   lcd.setCursor(15, 1);
  68.   lcd.print("%");
  69. }

  70. void loop() {
  71.   dustLevel =readPM();
  72.   sampleCount++;
  73.   sampleSumPm = sampleSumPm + dustLevel;
  74.   if(sampleCount==NSAMPLES)
  75.   {
  76.    showTempHumiData();

  77.    getPMdata(sampleSumPm / sampleCount);

  78.    sampleCount=0;
  79.    sampleSumPm=0;
  80.   }
  81. }

  82. void getPMdata(int avgPm) {
  83.   double dustVolt = avgPm * voteChange;  //mV

  84.   if(DOBASEFIX)
  85.   {
  86.    double baseVot = FREEPMVALUE * voteChange; //mV
  87.    double baseChg = 0.0;
  88.    if(temp_c< = 40.0&& temp_c>= -10.0)
  89.    {
  90.      baseChg=BASERATIO40;
  91.    }
  92.    else if(temp_c > 40.0&& temp_c< = 60.0)
  93.    {
  94.      baseChg=BASERATIO60;
  95.    }
  96.    baseVot=baseVot + baseChg*(temp_c - FREEPMTEMP);
  97.    dustVolt=dustVolt-baseVot;
  98.    if(dustVolt<0)
  99.    {
  100.      dustVolt=0;
  101.    }
  102.   }

  103.   dustVal = dustVolt * PMRATIO;
  104.   dustVal = dustVal + PMFIX;

  105.   // moving average
  106.   getMovingAverage(pm2_5,&dustVal);

  107.   lcd.setCursor(6, 0);
  108.   lcd.print("     ");
  109.   lcd.setCursor(6, 0);
  110.   lcd.print(dustVal,0);
  111. }

  112. void showTempHumiData() {
  113.   temp_c = sht1x.readTemperatureC();
  114.   humidity = sht1x.readHumidity();

  115.   lcd.setCursor(0, 1);
  116.   lcd.print("     ");
  117.   lcd.setCursor(0, 1);
  118.   lcd.print(temp_c,1);

  119.   lcd.setCursor(12, 1);
  120.   lcd.print("   ");
  121.   lcd.setCursor(12, 1);
  122.   lcd.print(humidity,0);
  123. }

  124. static float getAverage(double vals[])
  125. {
  126.   double sum=0.0;
  127.   uint8_t cout=0;
  128.   for(int i=0;i<movingaveragecout;i++)
  129.   {
  130.    if(vals[i] != NULLVALUE)
  131.    {
  132.      sum=sum+vals[i];
  133.      cout++;
  134.    }
  135.   }
  136.   if(cout>0)
  137.   {
  138.    return sum/cout;
  139.   }
  140.   else
  141.   {
  142.    return 0.0;
  143.   }
  144. }

  145. static void getMovingAverage(double pms[],double* pm)
  146. {
  147.   pms[arrNewPoint] = *pm;

  148.   arrNewPoint++;
  149.   if(arrNewPoint>=MOVINGAVERAGECOUT)
  150.   {
  151.    arrNewPoint=0;
  152.   }
  153.   *pm=getAverage(pms);
  154. }

复制代码

仪器未经标定,应用还需谨慎!
< /movingaveragecout;i++)
< /movingaveragecout;i++)
沙发
ID:111876发表于 2016-6-17 10:22|只看该作者
   这个代码无法用!
板凳
ID:119421发表于 2017-4-12 13:56|只看该作者
感谢分享,不知道有没有proteus的仿真

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网