BH1750: подключение к Arduino, адреса и люксметр своими руками
Фоторезистор честно отвечает на вопрос «светло или темно», но вопрос «сколько именно света» на нём буксует: отсчёты на A1 плывут с питанием, температурой и партией резистора, а после каждой пересборки макетки порог подбирается заново. Выход один — прибор с единицами измерения. Фабричный люксметр стоит заметных денег, а модуль на чипе BH1750 от Rohm решает ту же задачу на макетке: внутри корпуса фотодиод со спектральной чувствительностью, близкой к человеческому глазу, и шестнадцатибитный преобразователь. По I2C датчик отдаёт готовое число сразу в люксах — без делителей, логарифмических кривых и калибровочных коэффициентов; шаг от 0,5 лк, потолок около 54600 лк при заводских настройках.
Ниже — подключение модуля GY-302 четырьмя проводами, скетч на библиотеке BH1750, который получает первый люкс тремя строками, и пара датчиков на адресах 0x23 и 0x5C для сравнения света на полке и у окна. Таблица режимов покажет цену каждого шага: поллюксовая точность стоит половины диапазона, низкое разрешение экономит шину. Первый инструмент, если модуль молчит, — сканер I2C-адресов, а не угадывание по форумам.
Зачем люксы, когда есть фоторезистор
Аналоговый датчик отвечает относительностью: 0-1023 отсчёта зависят от напряжения питания, номинала делителя и конкретного экземпляра резистора. Один и тот же подоконник утром даст 400 отсчётов на одном макете и 620 на другом, а переводной таблицы «отсчёт — люкс» не существует в принципе. BH1750 переворачивает картину: чип меряет свет сам и отдаёт по шине абсолютные единицы. Двести пятьдесят люкс — это двести пятьдесят люкс и вчера, и на другой плате, и в журнале данных через месяц; цифры можно сравнивать между собой, логировать и сверять с нормой досветки растения из справочника.
| Параметр | Фоторезистор | BH1750 |
|---|---|---|
| Единицы | отсчёты 0-1023, у каждого макета свои | люксы, готовые абсолютные значения |
| Повторяемость | порог калибруется заново после пересборки | 250 лк сегодня и завтра — одно и то же число |
| Шаг показаний | зависит от кривой конкретного резистора | 0,5 / 1 / 4 лк — выбирается режимом |
| Время отсчёта | миллисекунды | 16-180 мс в зависимости от режима |
| Интерфейс | одна аналоговая ножка | I2C: два провода плюс общий адрес |
| Обвязка | делитель из двух резисторов | не нужна, адресный вход ADDR для второго датчика |
Плата за приборность — интерфейс и темп. Фоторезистор отвечает мгновенно и занимает один вход; BH1750 едет по шине и на самом быстром режиме даёт свежий отсчёт каждые 16 мс, на точном — каждые 120. Для авточника, досветки и логов этого хватает с избытком, а повторяемость перевешивает всё. Но у простого пана есть законная территория: если задача кончается словами «включить реле в темноте», фоторезисторный ночник дешевле и проще. Когда нужны именно единицы — журнал, сравнение мест, досветка по паспортной норме — начинается BH1750; механику обмена байт за байтом без единой библиотеки разобрал урок про датчик на голом Wire.
Схема подключения GY-302 и первые люксы
На модуле пять выводов: VCC на 5 В, GND на землю, SDA на A4, SCL на A5 — стандартный расклад шины, механика которого разложена в уроке про два провода I2C. Пятая ножка ADDR на готовых платах прижата к земле заводской подтяжкой, поэтому чип почти всегда отвечает на 0x23 — и только осознанный перенос её на питание даёт второй адрес. Голому чипу нужны 2,4-3,6 В, но модули GY-30 и GY-302 несут на борту стабилизатор, так что и 5-вольтовая Uno, и 3,3-вольтовые платы кормят его напрямую. Первую сборку заканчивайте проверкой сканером: 0x23 в выводе — можно двигаться дальше.
#include <Wire.h>#include <BH1750.h> // VCC->5V, GND->GND, SDA->A4, SCL->A5. ADDR не подключена -> 0x23BH1750 luxometr; void setup() { Serial.begin(9600); Wire.begin(); if (!luxometr.begin()) { // адрес 0x23, непрерывно, шаг 1 лк Serial.println("BH1750 ne otvechaet: provoda, adres, podtyazhki"); while (true) {} }} void loop() { float lux = luxometr.readLightLevel(); // пауза на замер внутри Serial.print("Osveshchennost: "); Serial.print(lux, 1); Serial.println(" lk"); delay(500);}Библиотека ищется в менеджере по имени BH1750 — автор Christopher Laws, ставится одной кнопкой. Она сама шлёт опкод старта, выдерживает паузу на замер и пересчитывает сырые отсчёты в люксы, поэтому readLightLevel() возвращает готовый float. Адрес и режим передаются там же, в begin(): begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x5C) — для датчика с ADDR на питании. Возврат false означает, что шина не нашла чип на указанном адресе: подозреваемые на редкость стабильны — перепутанные SDA и SCL, питание, подтяжки.
Режимы измерения: цена каждого шага
Непрерывных режимов четыре, разовых три, и разница между ними — в цене деления, времени и потолке. По умолчанию логично жить в 0x10: шаг 1 люкс, свежий отсчёт каждые 120-180 мс, диапазон до 54600 лк. Поллюксовый 0x11 нужен там, где график должен плавно ползти в сумерках, — но те же 16 бит, размазанные по вдвое мелким ступеням, означают потолок вдвое ниже. Низкоразрешающий 0x13 отдаёт вердикт «светло или темно» за 16 мс с шагом 4 лк — его выбирают циклы, где шину делят экран и часы. Разовые 0x20, 0x21 и 0x23 повторяют те же шаги, но после отсчёта чип засыпает до следующей команды.
| Режим | Опкод | Шаг | Время отсчёта | Потолок |
|---|---|---|---|---|
| непрерывно, высокое разрешение | 0x10 | 1 лк | 120 мс, до 180 | ~54600 лк |
| непрерывно, высокое разрешение 2 | 0x11 | 0,5 лк | 120 мс, до 180 | ~27300 лк |
| непрерывно, низкое разрешение | 0x13 | 4 лк | 16 мс, до 24 | ~54600 лк |
| разовое измерение | 0x20 | 1 лк | 120 мс, потом чип спит | ~54600 лк |
Два датчика на одной шине: 0x23 и 0x5C
Адрес выбирается одной ножкой, поэтому вторая «ложка света» встаёт на шину без мультиплексоров: первый датчик с ADDR на земле отвечает на 0x23, второй с ADDR на питании — на 0x5C. Классика жанра — сравнить условия: у окна и на полке с растениями, в комнате и в шкафу, до шторы и после. Конфликта не будет, пока адреса различаются; что происходит, когда два одинаковых модуля претендуют на один адрес, показал урок про коллизии адресов. Когда датчиков нужно больше двух, в игру вступает мультиплексор TCA9548A, разруливающий восемь отдельных шин.
#include <Wire.h>#include <BH1750.h> // ADDR первого прижата к земле -> 0x23, ADDR второго на питании -> 0x5CBH1750 polka;BH1750 okno; void setup() { Serial.begin(9600); Wire.begin(); if (!polka.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23)) { Serial.println("0x23 molchit: provoda ili podtyazhki"); while (true) {} } if (!okno.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x5C)) { Serial.println("0x5C molchit: ADDR ne na pitanii?"); while (true) {} }} void loop() { float naPolke = polka.readLightLevel(); float naOkne = okno.readLightLevel(); Serial.print("polka: "); Serial.print(naPolke, 0); Serial.print(" lk okno: "); Serial.print(naOkne, 0); Serial.println(" lk"); delay(1000);}Люксметр своими руками: от макетки до прибора
Честный люксметр отличается от строчки в Serial двумя вещами: сглаженными числами и понятной шкалой. Отдельные отсчёты будут плавать всегда — облако прошло, свет моргнул; лечится бегущим средним за пять-десять значений, и колонка в мониторе сразу становится пригодной для чтения. Арифметика усреднения — та же, что у показаний АЦП, для неё есть отдельный урок из списка ниже. Ориентиры для калибровки глаза: 250-450 лк под потолком комнаты, 2000-5000 у окна в пасмурный день, прямое солнце упирается в потолок шкалы. Если макетка молчит, начните со сканера из лендинга про поиск устройств на шине — он покажет, видит ли шина датчик, до всяких догадок про код. И про браузер без обмана: в симуляторе самоучителя BH1750 не эмулируется — движок отвечает на любой I2C-адрес заглушкой; зато аналоговые входы и логику порогов, ту самую вилку «включить/выключить», можно пощупать прямо на странице симулятора.
- ADDR прижата к земле — жду 0x23 в сканере; перебросил на питание — жду 0x5C
- первый отсчёт не раньше 180 мс после команды старта: раньше приходит ноль или прошлое значение
- при обмене без библиотеки деление на 1,2 — только дробное: raw / 1.2 в переменной float
- датчик под солнцем — помню про потолок 54600 лк и рычаг MTreg