Agkz.ru - игровой новостной портал
Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

  • Цена: $23.98
  • Сравним три популярных датчика пыли. Стоит ли переплачивать за более дорогой? Какие наиболее распространенные ошибки допускают при работе с бюджетными датчиками? Ответы под катом.

    Об устройстве чуть позже, сначала посмотрим внимательнее на датчики.

    SDS011

    Первый датчик лазерный, фирмы Nova Fitness. Он предназначен для определения количества пыли размером от 0,3 до 10 мкм в воздухе. Датчик разделяет пыль на две категории — размером от 0,3 до 2,5 мкм и от 2,5 до 10 мкм. Это общепринятая классификация, и наиболее опасна для здоровья пыль от 0,3 до 2,5 мкм.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Как и у многих современных датчиков, у этого два типа представления данных. Он способен передавать сведения в последовательный порт, а кроме того, имеет два выхода, скважность сигналов на которых пропорциональна концентрации пыли двух размеров.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Прочие сведения:

    диапазон измерений: 0 — 999 мкг/м3

    напряжение питания: 5 вольт

    потребляемый ток: 100 мА

    ток в режиме энергосбережения: 2 мА

    температура окружающей среды: -20-50°С

    время отклика: 1 сек

    частота отправки сообщений в компорт: 1 раз в секунду.

    минимальный определяемый размер частиц пыли: менее 0,3мкм.

    размеры: 71х70х23 мм

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Датчик снабжен центробежным микровентилятором.

    В комплект входит переходник с последовательного порта на usb.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Тут pdf на с подробной информацией по датчику: https://inovafitness.de/downloads/

    А тут описание протокола обмена по UART интерфейсу. https://nettigo.eu/attachments/415

    GP2Y1014AU0F

    Второй датчик производства фирмы Sharp. Он дешевле, компактнее и проще первого. Определяет пыль по принципу фотометрии. Краткие характеристики:

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    потребляемый ток: 20 мА

    напряжение питания: 5 вольт

    чувствительность: 0,5 вольт/100мкг/м3

    размеры: 46х30×17,6мм

    диапазон измерений: 0 — 500 мкг/м3

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Вентилятора у датчика нет, что с одной стороны является преимуществом, но с другой обещает не такую быструю реакцию датчика на изменение атмосферы.

    Вот описание датчика: http://www.sharp-world.com/products/device/lineup/data/pdf/datasheet/gp2y1010au_appl_e.pdf

    Samyoung DSM501a

    Третий датчик для определения пыли он использует тот же метод, что и Шарп, но в отличие от него, данные выдает по двум калибрам пыли — до 2,5мкм и от 2,5 и выше. Для связи передачи данных используется широтно-импульсная модуляция, что немного сложнее обработке, но намного надежнее с точки зрения помехозащищенности, чем аналоговый сигнал.

    Его краткая характеристика:

    напряжение питания: 4,5-5,5 вольт

    потребляемый ток: 90ма

    минимальный размер обнаруживаемой пыли: 1мкм

    диапазон измерений: 0-1400 мкг/м3

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    У этого датчика есть выход, который используется для регулировки чувствительности второго канала. Таким образом, мы можем менять границу разделения пыли на две фракции. Для улучшения циркуляции воздуха используется микро-печка из резистора, которая нагревает воздух и за счет конвекции он быстрее обновляется у сенсора.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Описание: http://www.platan.ru/pdf/datasheets/samyoung/DSM501.pdf

    Разумеется, фаворитом соревнований является лазерный датчик. Он и дороже и современнее своих конкурентов. Мне его прислали бесплатно, на обзор, и, как многие думают, я его должен хвалить уже из-за этого. Это не так, но сказать пару хороших слов можно сразу, едва вынув датчик из упаковки. Его легко подключить к компьютеру через прилагаемый переходник, скачать программу снятия данных и вуаля! График пыли строится на вашем экране.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Программа у меня провисела в фоне несколько дней, прежде чем я занялся сравнением датчиков, и уже в эти дни я понял, очень мало я знаю о пыли в своем доме.

    Теперь, когда с соперниками разобрались, кратко остановимся на тех деталях, которые будут использованы для изготовления стенда.

    Экран 128х160 с интерфейсом SPI, размером 1,8 дюйма.

    Часы реального времени DS3231, соединение по шине I2C

    «Черный ящик» OpenLog — будет висеть на компорте и записывать на флешку все, что контроллер отправляет в порт.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    И конечно же Arduino Pro Mini — мозг и память всего проекта.

    В качестве переходного звена, объединяющего все элементы, будет макетная платка. В основном на ней разъемы для подключения датчиков, но еще имеются резистор и электролитик — они требуются для нормального функционирования датчика Sharp.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Два резистора с джамперами — они служат для переключения порога чувствительности второго канала датчика DSM501, разъем микро-usb для питания в отсутствии компьютера и линейка резисторов для безопасного подключения экрана.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Вот что у меня получилось в результате.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Первым делом я решил протестировать датчик фирмы Sharp. Аналоговый выход обещал легкое подключение и обработку данных. Но все оказалось не совсем так. бОльшую часть времени датчик простаивает. Один раз в 10 мс на датчик нужно подать короткий импульс длительностью 320 мкс, который включит светодиод подсветки пыли. Потом, через 280 мкс, когда на выходе датчика окажется ответный сигнал, нужно успеть его снять и определить его амплитуду. Она-то и характеризует количество пыли в воздухе. Как только сигнал оцифрован, напряжение с подсветки снимается и все отключается до следующего импульса. Конечно, такой алгоритм снижает износ датчика и еще, как упомянуто в мануале, позволяет отличить пыль от дыма. Жаль, там не развивается эта мысль и остается только догадываться, как их отличить на практике.

    Простым вольтметром сигнал с датчика не померить и пришлось снимать осциллограмму.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Желтый график — управление светодиодом подсветки пыли. Отрицательный сигнал включает диод.

    Голубой — ответ датчика.

    Фиолетовый я ввел для наглядности, он включается непосредственно перед тем, как контроллер приступает к измерению напряжения сигнала и выключается после того, как напряжение измерено. Что интересно, мы видим, что сигнал от датчика начинает спадать не после отключения диода подсветки, а еще при его работе. Так что в измерениях важно не промахнуться по времени и все точно выполнять по инструкции.

    Второй важный момент — грамотно перевести полученные вольты в микрограммы на кубометр. Для этого надо вычесть из сигнала постоянную полку и по графику вычислить концентрацию пыли. Постоянная составляющая сигнала у каждого датчика своя. Все требует настройки.

    Программисту на заметку:
    В демонстрационных программах, которые можно найти на гитхабе, со временем промашка. Чтобы успеть все правильно измерить, нужно приступать уже через 200 мкс после включения диода, а не чрез 280, как там пишут.

    delayMicroseconds(200); // was 280, but real 320mks at 200 setting

    Итак. Что же мы имеем с гуся? А с гуся мы имеем почти ничего. Показания скачут вокруг нулевых значений. В принципе, это и не удивительно, я пылесошу каждый день. Но хотелось бы меньшего разброса показаний. Если поступить по-варварски и ввести в отверстие датчика какой-то предмет, то показания сразу взлетают на максимум, так что датчик рабочий. Просто для относительно чистой комнаты не очень чувствительный.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Второй датчик тоже заработал не сразу. Халява не прошла, и первый попавшийся в интернете код не заработал. Датчик показывал погоду на Марсе, и пришлось разбираться детально. Для начала я решил исключить плохое питание. Может оно и хорошее, но на всякий случай я припаял между + и — электролитик. Затем, в соответствии с мануалом, надо учитывать только импульсы от 10 до 90 мс. Да, импульсы у этого датчика следуют не с постоянной частотой и скважностью, а хаотично. И программно нужно их суммировать и вычислять процент присутствия импульсов относительно общего времени наблюдения. Так вот, в эту сумму не попадают импульсы менее 10 и более 90 мс. Третье: надо научиться пользоваться настройками датчика. При замыкании провода управления на землю через резистор 18,2КОм первый выход датчика становится столь же чувствительным, как и второй. Что не имеет практического смысла. При замыкании на землю через резистор 47 КОм первый выход начинает видеть пыль только крупнее 1,75 мкм. Таким образом, если в датчик залетит пылинка 1,5 мкм, то на втором выходе будет сигнал, а на первом — нет. При полном отключении управляющего провода от земли первый выход начинает замечать только пыль крупнее 2,5 мкм. Что нам и нужно. Мы снимаем показания со второго выхода, вычитаем их них показания с первого и получаем, таким образом, количество пыли в диапазоне от 1 до 2,5 мкм.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Но это еще не все. Остается перевести длительность присутствия сигнала на выходах датчика в количество пыли. А для этого в нашем распоряжении лишь график. График в программу не засунешь, я нашел онлайн сервис по оцифровке графиков и подбору полиномов для их более-менее точного моделирования. До меня это сделал какой-то парень из Штатов, но там у них свой стандарт, они меряют пыль в пылинках на одну сотую кубического фута. А у нас микрограммы на кубометр. Так что формула из готовых скриптов мне решительно не подходила.

    Программисту на заметку:
    Вот моя формула:

    y = -0.088496207228664*x^4 — 2.5505502324503*x^3 — 21.92053783603786*x^2 + 172.17128476610927*x — 90.1119605706346

    Где

    х — процент времени, когда присутствует сигнал от датчика, 0-100%

    y — концентрация пыли, мкг/м3

    Формула очень хорошо коррелирует с графиком из датшита, но совсем не коррелирует с действительностью, увы.

    После всех этих плясок с бубном ничего сильно хорошего не получилось: датчик показывал то чистейший горный воздух, то тяжелую атмосферу шлифовального цеха.

    Удивительно, но если вернуться к старой формуле из примеров использования датчика, той, с штуками пылинок на сотую кубофута, то выдаваемые датчиком значения численно более-менее правдоподобны, для чистой комнаты. Но как только поднимается пыль, они начинают отставать.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    А вот лазерный датчик хлопот не доставил. Байты из порта прочитались сразу. Сигнал с ШИМ — выходов тоже равномерный и красивый.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Показания очень хорошо соотносятся с происходящими вокруг датчика событиями. Это было заметно еще по первому включению, с выводом графика на десктоп. Пики в левой части графика — пайка. Датчик лежал на столе, где я паял стенд. По ощущениям, дыма особого не было, но график решительно полз вверх каждый раз, когда я включал паяльник. Короткий всплеск справа — расстилание кровати. Оказывается, даже чистая постель — источник огромного количества пыли.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Еще один неочевидный вывод — хороший пылесос совсем не гоняет пыль по комнате, а действительно ее всасывает. Включение пылесоса совершенно не отражалось на графике. А вот строительный пылесос — совсем другое дело. Мне нужно было просверлить пару небольших отверстий в ванной комнате. Там вытяжка, там маленькие отверстия, но все-таки я подогнал строительный пылесос, чтобы пылью от сверления не портить эксперимент с датчиками пыли. Эффект получился совсем не такой, как я ожидал.

    Датчик пыли SDS011. Ставим три разных датчика в одно устройство.

    Концентрация пыли мгновенно выросла в 20 раз и спадала потом еще полчаса. Кстати, проветривание резко снижает количество пыли в воздухе. Наверное, не во всех областях это так, но мне вот повезло.

    Код скрипта
    
    
    /////////////////// © Tykhon, 2019 ////////////////////////////////////
    #include "Wire.h"
    #include <SoftwareSerial.h>
    #include <TFT.h>
    /////////////////// for DSM501 sensor ////////////////////////////////////
    int pinV2 = 6;
    int pinV1 = 5;
    unsigned long durationV1;
    unsigned long durationV2;
    unsigned long starttimeV1;
    unsigned long starttimeV2;
    unsigned long lowpulseoccupancyV1 = 0;
    unsigned long lowpulseoccupancyV2 = 0;
    float one_to_two_point_five;
    float ratioV1 = 0;
    float ratioV2 = 0;
    boolean flagV1 = true;
    boolean flagV2 = true;
    boolean V1 = false;
    boolean V2 = false;
    float concentrationV1 = 0;
    float concentrationV2 = 0;
    int allV1, allV2, goodV1, goodV2;

    /////////////////// for Sharp sensor ////////////////////////////////////
    unsigned long LastCheckSharp;
    const int sharpLEDPin = 4; // Arduino digital pin 2 connect to sensor LED.
    const int sharpVoPin = A6; // Arduino analog pin A6 connect to sensor Vo.
    static unsigned long VoRawTotal = 0;
    int VoRawCount = 0;
    static float Voc = 0.45;
    float dustDensity = 0.0;
    float Vo = 0.0;
    float Dust = 0.0;

    /////////////////// for general purposes ////////////////////////////////
    unsigned long starttime;
    unsigned long endtime;
    unsigned long sampletime_ms = 30000;
    unsigned long now;
    unsigned long loops;
    #define DS1307_ADDR 0x68 // RTC address

    /////////////////// for LCD ////////////////////////////////////////////

    #define TFT_CS 10
    #define TFT_RST 9
    #define TFT_DC 8
    int line_25[85] = {};
    int line_10[85] = {};
    byte lineIndex;
    TFT TFTscreen = TFT(TFT_CS, TFT_DC, TFT_RST);
    char one_to_two_point_fivec[5], Dustc[5], Pm25fc[5], Pm10fc[5];

    ////////////////// for SDS 011 sensor //////////////////////////////////
    int rxPin = 3;
    int txPin = 2;
    SoftwareSerial mySerial(3, 2); //RX, TX
    unsigned int Pm25 = 0;
    unsigned int Pm10 = 0;
    float Pm25f = 0.0;
    float Pm10f = 0.0;
    int sdspoll = 0;
    unsigned int Pm25sum = 0;
    unsigned int Pm10sum = 0;
    unsigned long lastsds;
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void setup()
    {
    Serial.begin(9600);
    mySerial.begin(9600);
    pinMode(pinV1,INPUT);
    pinMode(pinV2,INPUT);
    pinMode(sharpLEDPin, OUTPUT);
    starttime = millis();
    Wire.begin();
    TFTscreen.begin();
    TFTscreen.setRotation(2);
    TFTscreen.background(20,0,0);
    TFTscreen.stroke(200,200,200);
    TFTscreen.setTextSize(2);
    TFTscreen.text("DSM", 2, 5);
    TFTscreen.text("Sharp", 2, 35);
    TFTscreen.stroke(0,250,250);
    TFTscreen.text("Pm10", 2, 65);
    TFTscreen.stroke(180,10,250);
    TFTscreen.text("Pm2.5", 2, 95);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    /////////////////// for date and time //////////////////////////////////
    byte bcdToDec(byte val) {
    return ( (val/16*10) + (val%16) );
    }
    /////////////////// returns date and time //////////////////////////////////
    String getdate(){
    Wire.beginTransmission(DS1307_ADDR);
    byte zero = 0x00;
    Wire.write(zero);
    Wire.endTransmission();
    Wire.requestFrom(DS1307_ADDR, 7);
    int secondint = bcdToDec(Wire.read());
    int minuteint = bcdToDec(Wire.read());
    int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
    int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
    int monthDay = bcdToDec(Wire.read());
    int month = bcdToDec(Wire.read());
    int year = bcdToDec(Wire.read());
    String second = String(secondint); if (secondint < 10) {second ="0"+second;};
    String minute = String(minuteint); if (minuteint < 10) {minute ="0"+minute;};
    return String(hour)+":"+minute+":"+second+" "+String(monthDay)+"/"+String(month)+"/"+String(year); ///
    }
    //////////////////// draws graph ////////////////////////////////////////
    void tft_graph(){
    byte k = 30;
    TFTscreen.stroke(20,0,0);
    TFTscreen.fill(20,0,0);
    TFTscreen.rect(0, TFTscreen.height()-45, TFTscreen.width(), 45);
    TFTscreen.stroke(250,180,10);

    TFTscreen.line(5, 90+k, 5, 121+k);
    TFTscreen.line(5, 121+k, 90, 121+k);
    int maxvalue = 0;
    for (int i = 0; i < (sizeof(line_10)/sizeof(int)); i++){
    maxvalue = max(maxvalue, line_10[i]);
    maxvalue = max(maxvalue, line_25[i]);
    };
    int g = 5+(sizeof(line_10)/sizeof(int));
    for (int i = lineIndex-1; i >= 0; i--){
    int x1 = g;
    g--;
    int y1 = map(line_10[i],maxvalue,0,90+k,120+k);
    int y2 = map(line_25[i],maxvalue,0,90+k,120+k);

    TFTscreen.stroke(10,180,250);
    TFTscreen.point(x1, y1);
    TFTscreen.stroke(180,10,250);
    TFTscreen.point(x1, y2);
    };
    for (int i = (sizeof(line_10)/sizeof(int))-1; i >= lineIndex; i--){
    int x1 = g;
    g--;
    int y1 = map(line_10[i],maxvalue,0,90+k,120+k);
    int y2 = map(line_25[i],maxvalue,0,90+k,120+k);
    TFTscreen.stroke(10,180,250);
    TFTscreen.point(x1, y1);
    TFTscreen.stroke(180,10,250);
    TFTscreen.point(x1, y2);
    };
    }
    ///////////////////// prints data on screen ///////////////////////////
    void tft_output(){
    TFTscreen.stroke(20,0,0);
    TFTscreen.text(one_to_two_point_fivec, 70, 5);
    TFTscreen.text(Dustc, 70, 35);
    TFTscreen.text(Pm10fc, 70, 65);
    TFTscreen.text(Pm25fc, 70, 95);
    String one_to_two_point_fives = String(one_to_two_point_five);
    String Dusts = String(Dust);
    String Pm10fs = String(Pm10f);
    String Pm25fs = String(Pm25f);
    one_to_two_point_fives.toCharArray(one_to_two_point_fivec,5);
    Dusts.toCharArray(Dustc,5);
    Pm10fs.toCharArray(Pm10fc,5);
    Pm25fs.toCharArray(Pm25fc,5);
    TFTscreen.stroke(255,255,255);
    TFTscreen.text(one_to_two_point_fivec, 70, 5);
    TFTscreen.text(Dustc, 70, 35);
    TFTscreen.text(Pm10fc, 70, 65);
    TFTscreen.text(Pm25fc, 70, 95);
    }

    ////////////////// reads serial port and decodes data //////////////////////

    void ProcessSerialData()
    {
    uint8_t mData = 0;
    uint8_t i = 0;
    uint8_t mPkt[10] = {0};
    uint8_t mCheck = 0;
    while (mySerial.available() > 0)
    {
    // from www.inovafitness.com
    // packet format: AA C0 PM25_Low PM25_High PM10_Low PM10_High 0 0 CRC AB
    mData = mySerial.read(); delay(2);//wait until packet is received
    if (mData == 0xAA) //head1 ok
    {
    mPkt[0] = mData;
    mData = mySerial.read();
    if (mData == 0xc0) //head2 ok
    {
    mPkt[1] = mData;
    mCheck = 0;
    for (i = 0; i < 6; i++) //data recv and crc calc
    {
    mPkt[i + 2] = mySerial.read();
    delay(2);
    mCheck += mPkt[i + 2];
    }
    mPkt[8] = mySerial.read();
    delay(1);
    mPkt[9] = mySerial.read();
    if (mCheck == mPkt[8]) //crc ok
    {
    mySerial.flush();
    Pm25 = (uint16_t)mPkt[2] | (uint16_t)(mPkt[3] << 8);
    Pm10 = (uint16_t)mPkt[4] | (uint16_t)(mPkt[5] << 8);
    if (Pm25 > 9999)
    Pm25 = 9999;
    if (Pm10 > 9999)
    Pm10 = 9999;
    return;
    }
    }
    }
    }
    }

    ////////////////// sends SLEEP command to SDS011 //////////////////////
    void SDS011sleep()
    {
    while (mySerial.available() > 0)
    {
    uint8_t sleep_command[] = {0xAA, 0xB4, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB};
    for (uint8_t i = 0; i < 19; i++) {
    mySerial.write(sleep_command[i]);
    }
    mySerial.flush();
    }
    }
    ////////////////// sends WAKEUP command to SDS011 //////////////////////
    void SDS011wakeup()
    {
    while (mySerial.available() > 0)
    {
    uint8_t wakeup_command[] = {0xAA, 0xB4, 0x06, 0x01, 0x01, 0xC5};
    for (uint8_t i = 0; i < 6; i++) {
    mySerial.write(wakeup_command[i]);
    }
    }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void loop()
    {
    loops +=1;
    now = millis();
    ////////////// Sharp ////////////////////////

    if ((now - LastCheckSharp) >= 10) {
    LastCheckSharp = now;
    digitalWrite(sharpLEDPin, LOW);
    delayMicroseconds(200); // was 280, but real 320mks at 200 setting
    int VoRaw = analogRead(sharpVoPin);
    digitalWrite(sharpLEDPin, HIGH);
    VoRawTotal += VoRaw;
    VoRawCount++;
    };
    //////////// DSM 501 ////////////////////////
    V1 = digitalRead(pinV1);
    if ((flagV1)&&!(V1)) { // start period of low V1
    starttimeV1 = millis();
    flagV1 = false;
    };
    if (!(flagV1)&&(V1)) { // stop period of low V1
    durationV1 = millis() - starttimeV1;
    flagV1 = true;
    allV1+=1;

    if ((durationV1 <= 90)&&(durationV1 >= 10)) {
    lowpulseoccupancyV1 += durationV1;
    goodV1+=1;
    };
    };
    V2 = digitalRead(pinV2);
    if ((flagV2)&&!(V2)) { // start period of low V2
    starttimeV2 = millis();
    flagV2 = false;
    };
    if (!(flagV2)&&(V2)) { // stop period of low V2
    durationV2 = millis() - starttimeV2;
    flagV2 = true;
    allV2+=1;

    if ((durationV2 <= 90)&&(durationV2 >= 10)) {
    lowpulseoccupancyV2 += durationV2;
    goodV2+=1;
    };
    };
    //////////// SDS 011 ////////////////////////
    if ((now - lastsds)> 1000) {
    lastsds = now;
    sdspoll ++;
    ProcessSerialData();
    Pm25sum += Pm25;
    Pm10sum += Pm10;
    };
    //////////// output ///////////////////////////////

    endtime = millis();
    if ((endtime-starttime) > sampletime_ms)
    {
    Serial.print(getdate());
    //////////////////////////
    Vo = 1.0 * VoRawTotal / VoRawCount;
    Vo = Vo / 1024.0 * 5.0;
    float dV = Vo - Voc;
    if (dV < 0 ) {dV = 0; Voc = Vo;};
    Dust = 172.0*dV;
    Serial.print(" Sharp: ");
    Serial.print(Dust);
    VoRawCount = 0;
    VoRawTotal = 0;
    //////////////////////////

    ratioV1 = (lowpulseoccupancyV1*100.0)/(endtime-starttime); // Integer percentage 0=>100
    ratioV2 = (lowpulseoccupancyV2*100.0)/(endtime-starttime); // Integer percentage 0=>100
    // concentrationV1 = 1.1*pow(ratioV1,3)-3.8*pow(ratioV1,2)+520*ratioV1+0.62; // using spec sheet curve in pcs in 1/100 ft3
    // concentrationV2 = 1.1*pow(ratioV2,3)-3.8*pow(ratioV2,2)+520*ratioV2+0.62; // using spec sheet curve in pcs in 1/100 ft3
    concentrationV1 = -0.0885*pow(ratioV1,4) - 2.55055*pow(ratioV1,3)- 21.920538*pow(ratioV1,2) + 172.171285*ratioV1 - 90.112;
    concentrationV2 = -0.0885*pow(ratioV2,4) - 2.55055*pow(ratioV2,3)- 21.920538*pow(ratioV2,2) + 172.171285*ratioV2 - 90.112;
    if (concentrationV1 < 0) {concentrationV1 = 0.0;};
    if (concentrationV2 < 0) {concentrationV2 = 0.0;};
    one_to_two_point_five = concentrationV2 - concentrationV1;
    if (one_to_two_point_five < 0) {one_to_two_point_five = 0;};
    Serial.print(" DSM501_>2.5: ");
    Serial.print(concentrationV1);
    Serial.print(" DSM501_>1.0: ");
    Serial.print(concentrationV2);

    Serial.print(" DSM501_1-2.5: ");
    Serial.print(one_to_two_point_five);

    lowpulseoccupancyV1 = 0;
    lowpulseoccupancyV2 = 0;
    loops = 0;
    allV1 = 0;
    goodV1 = 0;
    allV2 = 0;
    goodV2 = 0;

    ///////////// SDS011 /////////////////
    Pm25f = Pm25sum/(sdspoll*10.0);
    Pm10f = Pm10sum/(sdspoll*10.0);
    Serial.print(" Pm2.5 ");
    Serial.print(Pm25f,2);
    Serial.print(" Pm10 ");
    Serial.print(Pm10f,2);
    sdspoll = 0;
    Pm25sum = 0;
    Pm10sum = 0;
    line_25[lineIndex] = int(Pm25f*100.0);
    line_10[lineIndex] = int(Pm10f*100.0);
    lineIndex++;
    if (lineIndex >= 85) {lineIndex = 0;};

    //////////// finish ///////////////

    tft_output();
    Serial.println();
    tft_graph();
    starttime = millis();
    } // if 30 sec passed

    } // loop

    Выводы

    Я пару дней гонял стенд с тремя датчиками в разных условиях. В области малых концентраций пыли для измерений годится только лазерный датчик. Он же и самый быстрый на отклик. У меня нет возможностей проверить показания этого датчика. Но мне достаточно того, что в его измерениях отражались все события в комнате, которые так или иначе должны были влиять на пыль. Расстилание кровати, проветривание, пайка, работа пылесоса, ремонтные работы — все это тут же сказывалось на графике. Что до шума от вентилятора, то он не очень большой. И у датчика есть режим энергосбережения, при котором вентилятор не работает. Два других датчика скорее подойдут для контроля относительно грязной атмосферы. Если выбирать из них, то Samyoung DSM 501 выглядит предпочтительнее. Его преимущества — разделение пыли по фракциям, лучшая помехозащищенность, большой диапазон и улучшенная циркуляция воздуха.

    Плюсы датчика SDS011

    + высокая корреляция показаний прибора и обстановки с пылью вокруг

    + стабильность показаний

    + скорость реакции

    + невысокая (для лазерных датчиков) стоимость.

    Минусы датчика SDS011

    — шум от вентилятора

    — относительно высокое энергопотребление

    Товар предоставлен для написания обзора магазином. Обзор опубликован в соответствии с п.18 Правил сайта.