Многие люди испытывают дерматологические проблемы и не могут находиться долго на открытом солнце. Данный проект поможет создать своими руками на основе Ардуино Нано и УФ-датчика измеритель ултрафиолетового излучения. Автор проекта назвал данное устройство UltraV.
Оно создано на основе Arduino Nano rev3, УФ-датчика, DC/DC-преобразователя для повышения напряжения питания выше 3В и небольшого OLED-дисплея. Главная цель заключалась в том, чтобы сделать устройство портативным для измерения УФ-индекса в любой момент и в любом месте.
Шаг 1: Детали и компоненты
Нам понадобятся достаточное количество деталей и компонентов для проекта УФ-измерителя на Ардуино:
- Микроконтроллер Arduino Nano rev.3
- Ультрафиолетовый датчик ML8511
- 128×64 OLED дисплей (SSD1306)
- Преобразователь MT3608 DC-DC
- Аккумулятор CR2
- Держатель батареи CR2
- Переключатель
- Корпус
Шаг 2: Датчик
ML8511 - это УФ-датчик, который подходит для получения УФ-интенсивности в помещении или на открытом воздухе. ML8511 оснащен внутренним усилителем, который преобразует фото-ток в напряжение в зависимости от интенсивности УФ-излучения. Эта уникальная функция предлагает простой интерфейс для внешних схем, таких как АЦП. В режиме отключения питания типичный ток в режиме ожидания составляет 0,1 мкА, что позволяет увеличить срок службы батареи.
Особенности:
- Фотодиод чувствителен к УФ-А и УФ-В
- Встроенный операционный усилитель
- Аналоговый выход напряжения
- Низкий ток питания (300 мкА) и низкий ток в режиме ожидания (0,1 мкА).
- Малый и тонкий комплект для поверхностного монтажа (4,0 мм х 3,7 мм х 0,73 мм, 12-контактный керамический QFN)
К сожалению, не было возможности найти какой-либо УФ-прозрачный материал для защиты датчика. Любая прозрачная крышка, которую тестировали (пластик, стекло и т.д.), ослабляла УФ-измерение. Лучший выбор - стекло из плавленого кварца, но тяжело найти такое по разумной цене, поэтому было принято решение оставить датчик вне корпуса под открытым небом.
Шаг 3: Как работает датчик
Просто включите устройство и наведите его на солнце в течение нескольких секунд, удерживая его в соответствии с направлением солнечных лучей. Затем смотрите на дисплей: индекс слева всегда показывает мгновенное значение (каждые 200 мс), в то время как показания справа являются максимальным показанием, сделанным во время этого сеанса: это то, что вам нужно.
В нижней левой части дисплея сообщается также эквивалентная номенклатура Всемирной организации здравоохранения, ВОЗ, как на фото выше (LOW, MODERATE, HIGH, VERY HIGH, EXTREME) для измеренного УФ-индекса - Низкий, Умеренный, Высокий, Очень высокий, Экстремальный.
Шаг 4: Напряжение и аккумулятор
Был выбран аккумулятор CR2 из-за размера и емкости (800 мАч). Устройство использовалось в течение всего лета и аккумулятор все еще 2.8В, поэтому все вполне довольны выбором. Когда устройство работает, цепь выдает около 100 мА, но измерение показаний занимает не более нескольких секунд. Поскольку номинальное напряжение батареи составляет 3 В, добвлен преобразователь постоянного тока DC-DC, чтобы довести напряжение до 9 вольт и подключить его к выходу Vin.
Чтобы иметь индикацию напряжения батареи на дисплее, использован аналоговый вход (A2). Аналоговые входы Arduino могут использоваться для измерения постоянного напряжения от 0 до 5 В, но для этого метода требуется калибровка. Для выполнения калибровки понадобится мультиметр. Сначала включите цепь с вашей последней батареей (CR2) и не используйте питание USB от компьютера; измерять 5V на Arduino от регулятора (находится на выводе Ардуина 5V): это напряжение используется для опорного напряжения АЦП Ардуино по умолчанию. Теперь поместите измеренное значение в код следующим образом (предположим, что вы прочитали 5.023):
voltage = ((long)sum / (long)NUM_SAMPLES * 5023) / 1024.0;
В эскизе взято среднее значение из 10 измерений.
Шаг 5: Схема и соединения
Принципиальная схема Ультрафиолетового измерителя Ардуино выглядит таким образом:
Шаг 6: Программное обеспечение
Для дисплея была использована U8g2lib, которая является очень гибкой и мощной для подобных OLED-дисплеев, широкий выбор шрифтов и хорошие функции позиционирования.
Что касается показания напряжения от ML8511, был использован опорный контакт 3,3 В Arduino (с точностью до 1%) в качестве основы для преобразователя АЦП. Таким образом, делая аналого-цифровое преобразование на выводе 3.3V (подключая его к A1), а затем сравнивая это показание с показанием датчика, мы можем экстраполировать истинное значение, независимо от того, что на VIN (пока оно выше 3.4В).
int uvLevel = averageAnalogRead(UVOUT); int refLevel = averageAnalogRead(REF_3V3); float outputVoltage = 3.3 / refLevel * uvLevel;
Скачайте или скопируйте код ниже:
#include <Arduino.h> #include <U8g2lib.h> #include <Wire.h> U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display #define FIRST_ROW_Y 16 #define FIRST_ROW_X 16 #define BOX_H 38 //Hardware pin definitions const int UVOUT = A0; //Output from the sensor const int REF_3V3 = A1; //3.3V power on the Arduino board const int VBATT = A2; //Battery voltage float maxUV = 0; //Max UV index read void setup() { pinMode(UVOUT, INPUT); pinMode(REF_3V3, INPUT); pinMode(VBATT, INPUT); u8g2.begin(); } void loop() { u8g2.firstPage(); do { int uvLevel = averageAnalogRead(UVOUT); int refLevel = averageAnalogRead(REF_3V3); //Use the 3.3V power pin as a reference to get a very accurate output value from sensor float outputVoltage = 3.3 / refLevel * uvLevel; float uvIntensity = mapfloat(outputVoltage, 0.99, 2.6, 0.0, 15.0); //Convert the voltage to a UV intensity level readBattery(); if (maxUV < uvIntensity) { maxUV = uvIntensity; } u8g2.drawFrame(0,FIRST_ROW_Y+1,128,BOX_H); u8g2.setFont(u8g2_font_logisoso18_tf); //Instant UV u8g2.setCursor(10,40); u8g2.print(uvIntensity); //UV Max u8g2.setCursor(70,40); u8g2.print(maxUV); u8g2.setFont(u8g2_font_u8glib_4_tf); u8g2.setCursor(10,52); u8g2.print(F("INSTANT")); u8g2.setCursor(75,52); u8g2.print(F("MAXIMUM")); showUVCategory(); u8g2.setCursor(88,64); u8g2.print(F("F.Marzocca")); } while ( u8g2.nextPage() ); delay(200); } // Reads maxUV and prints the UV category void showUVCategory() { char strCat[12]; byte categ = (byte)(maxUV+0.5); //round up if ((categ >= 0) && (categ < 3)) { strcpy(strCat, "LOW"); } else if ((categ >= 3) && (categ < 6)) { strcpy(strCat, "MODERATE"); } else if ((categ >= 6) && (categ < 8)) { strcpy(strCat, "HIGH !"); } else if ((categ >= 8) && (categ < 10)) { strcpy(strCat, "VERY HIGH!"); } else if (categ >= 11) { strcpy(strCat, "EXTREME!"); } u8g2.setCursor(0,64); u8g2.print(strCat); } //Takes an average of readings on a given pin //Returns the average int averageAnalogRead(int pinToRead) { byte numberOfReadings = 16; unsigned int runningValue = 0; for(int x = 0 ; x < numberOfReadings ; x++) runningValue += analogRead(pinToRead); runningValue /= numberOfReadings; return(runningValue); } //The Arduino Map function but for floats //From: http://forum.arduino.cc/index.php?topic=3922.0 float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } void readBattery() { long battery = readBattVcc(); long VccMin = 2300; //Battery minimum voltage read on Vcc byte batteryBar; //Battery progress bar int barStep = 140; //step for battery progress bar (235) batteryBar = (battery - VccMin)/barStep; //battery icon u8g2.setFont(u8g2_font_open_iconic_embedded_2x_t); u8g2.drawGlyph(1, FIRST_ROW_Y, 73 ); // battery status cursor u8g2.setFont(u8g2_font_open_iconic_play_1x_t); for (byte i=1; i<=batteryBar; i++) { u8g2.drawGlyph( 128-9*i,FIRST_ROW_Y-4,75); } // battery voltage u8g2.setFont(u8g2_font_freedoomr10_tu); u8g2.setCursor(25, FIRST_ROW_Y); u8g2.print(float(battery)/1000, 3); } long readBattVcc() { int sum=0; int sample_count=0; long voltage= 0; #define NUM_SAMPLES 10 // take a number of analog samples and add them up while (sample_count < NUM_SAMPLES) { sum += analogRead(VBATT); sample_count++; delay(2); } // calculate the voltage // use 5000 for a 5.0V ADC reference voltage // 5020V is the calibrated reference voltage (in millivolts) for my project voltage = ((long)sum / (long)NUM_SAMPLES * 5020) / 1024.0; return voltage; //Vbattery in millivolts }
Шаг 7: Корпус и сборка
После нескольких (плохих) тестов при ручной резки прямоугольного окна дисплея в купленной пластиковой коробке было принято решение создать собственный корпус. Таким образом, с помощью приложения САПР была разработана коробка, а чтобы она была как можно меньше, батарею CR2 смонтировали снаружи на задней стороне (с держателем батареи, наклеенным на корпус).
Вы можете скачать файл STL для корпуса ниже:
Шаг 8: Итоговый результат
На этом наш измеритель ультрафиолетового излучения на Ардуино готов.