cometsky 发表于 2014-11-6 23:44:14

基于夏普DN7C3JA001的PM2.5检测仪

本帖最后由 cometsky 于 2014-11-7 13:56 编辑

先露个脸


在那群密密麻麻的线后面还藏着一个LM35的温度传感器,主要用来计算DN7C3的温度补偿。
线路图就不画了,连线很简单,和前代GP2Y1010是完全一样的,这货基本上就一外壳包着GP2Y1010外加风扇,价格可是x4了。

测试的串口屏幕

左边的一列是analogRead()后的换算电压(还取了1000次平均),那叫一个飘。中间是减掉基准参考电压后,第三列是PM2.5

PDF附上:

说说经验:
1 这东西几乎完全是模拟器件,至少接口是,Vo电压差不多有10mV左右的漂移,上图中最后一列是PM2.5读数(单位手误了),前半部分是走到楼梯间测的,后半部分是室内测的(有空气净化器)。
2 打开风扇会让读数稳定些,应该是大灰尘都按惯性走了旁边的通道,没有进入传感器,为了防止电机对电源的干扰,电机的供电单独设置。
3 外壳上QRCode里面的参考电压就是一个摆设,我在较洁净的室内实测电压低于参考电压将近130mV,应该是LED串联的电阻阻值略高(153欧),并且加上面包板上各个插针的接触电阻导致LED亮度不够,另外所有器件的电源都从Arduino板上取,会稍微的拉低电压。
4 温度漂移要考虑,参考电压是在25度下的读数,每摄氏度有6mV的漂移。相当于3.6ug的颗粒物。
5 模拟口不同针脚连续读取好像有干扰(不确定),反正代码里读DN7C3和LM35分开了200us。
6 analogRead()函数执行大概需要100us多一点,但是采样的延时应该没有那么多(有一种说法是可以设置ADCH连续采样,间隔是26us),前后的时间应该是开关ADC的耗时,我感觉应该在60-80us后是读数时点。所以arduino的delayMicroseconds我取值220。
7 除非能有校准的手段,否则这东西就是一准玩具。我准备去美帝使馆附近校准。
8 脉冲必须按时发出,无论你读取与否,间断的脉冲会导致错误读数。
9 通过USB传进来的电压必须准确,我用山寨充电宝当电源,结果Arduino的5v针脚就变成5.2v了。

上代码:(大概10s之后才有读数,这是稳定期,每秒的读数是和前10秒的平均值,否则跳跃太大)
// My QRcode: 1491800B82 1.23 **** 24.9
// 14918 is produce at 2014-09-18 (WTF!)
// 1.23 is reference voltage
// 24.9 is temperature of reference voltage

#include <LiquidCrystal.h>

//LCD_VSS pin to ground
//LCD_VDD pin to 5V
//LCD_VOpin to ground with 10K resistor
int LCD_RS = 6;
//LCD_RW pin to ground
int LCD_E= 7;
int LCD_D4 = 8;
int LCD_D5 = 9;
int LCD_D6 = 10;
int LCD_D7 = 11;
//LCD_A   pin to 5V
//LCD_K   pin to ground
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

int count = 0;
float valueP = 0; // reading of DN7C3
float valueT = 0; // reading of LM35
float averageP = 0;
float averageT = 0;
float historyP = 0;
unsigned long timer = 0;

unsigned long A = 0;
unsigned long B = 0;

void setup() {
    pinMode(A5, INPUT); // DN7C3 Vo Pin
    pinMode(A2, INPUT); // LM35 input
    pinMode(4, OUTPUT);
    digitalWrite(4, HIGH);
   
    lcd.begin(16, 2);
    lcd.print("Sharp DN7C3");
   
    Serial.begin(115200);
    Serial.println("Sharp DN7C3 PM2.5 Sensor");
   
    for(int i = 0; i < 1000; i++) {
      delayMicroseconds(9680);
      digitalWrite(4, LOW);
      delayMicroseconds(320);
      digitalWrite(4, HIGH);
    }
    timer = micros();
}

void loop() {
    if ((micros() - timer) >= 10000) {// per 10ms
      timer = micros();
      
      digitalWrite(4, LOW);    // turn on led
      A = micros();            // measure pulse begin time
      delayMicroseconds(230);// Arduino ADC need about 100us
      valueP = analogRead(A5); // PM2.5 reading
      B = micros();            // measure pulse end time
      digitalWrite(4, HIGH);   // turn off led
      
      delayMicroseconds(200);// wait to read Temperature
      valueT = analogRead(A2); // Temperature reading
      
      count++;
      averageP = (averageP * (count - 1) + valueP * (5000.0 / 1024.0)) / count;
      averageT = (averageT * (count - 1) + valueT * (5000.0 / 1024.0)) / count;
      
      if (count >= 100) { // 100 times average, 1 second
            float temp = averageT / 10; // get Temperature
            float diffrent = averageP - (1100 + (temp-24.9)*6); // 1100 is ture reference voltage base on my circuits
            float pm25ug = diffrent * 0.6;
            
            if (historyP == 0) {
                historyP = pm25ug;
            }
            else {
                historyP = (historyP * 9 + pm25ug) / 10;
            }
            
            // post to Serial
            Serial.print("T: ");
            Serial.print(temp, 2);
            Serial.print(" C\tV: ");
            Serial.print(averageP, 2);
            Serial.print(" mV\t P: ");
            Serial.print(pm25ug, 2);
            Serial.print(" ug/m3\t avgP: ");
            Serial.print(historyP, 2);
            Serial.print(" ug/m3\t Pulse: ");
            Serial.println(B - A);
            
            // show on 1602
            lcd.clear();
            lcd.setCursor(0,0);
            lcd.print("PM25: ");
            lcd.print(historyP); // averaged
            lcd.setCursor(14,0);
            lcd.print("ug");
            lcd.setCursor(0,1);
            lcd.print("Temp: ");
            lcd.print(temp);
            lcd.setCursor(15,1);
            lcd.print("C");
            
            // clear for next time
            count = 0;
            valueP = 0;
            valueT = 0;
            averageP = 0;
            averageT = 0;
      }
    }
}


cometsky 发表于 2014-11-6 23:49:28

关于Arduino的ADC连续采样,有兴趣的可以看看这里:http://www.instructables.com/id/Arduino-Audio-Input/step6/Sampling-rate-of-40kHz/

tcgwpct 发表于 2014-11-8 08:00:25

非常感谢呀:)

Kenobi 发表于 2014-12-4 11:06:22

cometsky 发表于 2014-11-6 23:49 static/image/common/back.gif
关于Arduino的ADC连续采样,有兴趣的可以看看这里:http://www.instructables.com/id/Arduino-Audio-Input/ ...

嗨, 你好.
我對夏普這PM2.5檢測儀有興趣. 從Google搜尋找到這裡. 真是謝謝你的這些資料. 想請問你, 如果我要用 Raspberry Pi 而不是 Arduino是否可行?

先謝謝

cometsky 发表于 2014-12-5 22:23:08

Kenobi 发表于 2014-12-4 11:06 static/image/common/back.gif
嗨, 你好.
我對夏普這PM2.5檢測儀有興趣. 從Google搜尋找到這裡. 真是謝謝你的這些資料. 想請問你, 如果 ...

树莓派没有内置的A/D转换,你需要另外接一个,其他的就是那个0.28ms的时间控制了,因为有外置A/D电路所以需要在程序中仔细计算延迟,另外Linux不是实时系统,延时可能会不准

超姸131411 发表于 2016-5-23 20:53:35

如果我把这个与无人机相连 ,那与stm32相连的程序怎么写啊

hellryuz 发表于 2017-2-6 09:58:43

版主可以提供電路圖嗎,對於DN7C3電阻始終有接線的疑慮!感激不盡~
页: [1]
查看完整版本: 基于夏普DN7C3JA001的PM2.5检测仪