Здоровья всем читателям Муськи!
Неоднократно делал для дома и аквариумов разные светильники на галогенках, ЛЛ и светодиодах. И в какой-то момент понял, что не помешало бы иметь хотя бы простейший приборчик для количественного сравнения светильников, ибо человеческий глаз ну очень не стабильный измеритель. Если светильники включать не одновременно, то глаз адаптируется и освещенность отличающаяся даже не в разы, а на порядки, кажется одинаковой. Но потом оказывается, что под этим светом не получается различить мелкие детали, цвета, а в аквариуме трава не растет.
Но тратиться на нормальный прибор для домашнего применения пару раз в год казалось излишеством. И тут как нельзя кстати оказались обзоры самодельных люксметров на дешевом датчике BH1750FVI (
datasheet), который выдает уровень освещенности прямо в люксах, да еще с приличной точностью. Замечательно — прибор делаем сами, заодно изучив новые технологии.
В обзоре помимо конструкции люксметра расскажу об отличиях двух модулей датчиков и будет некоторый ликбез по шине I2C.
Аналогичные люксметры на таком же датчике собирались вот в этих обзорах, которыми я и вдохновлялся:
Приборный корпус с ТАОБАО и самодельный люксметр в нем.
Люксометр за 80 рублей. Часть 1
Люксометр за 80 рублей. Часть 2. Сравнение с Extech 407026
Однако, по-моему, осталась некоторая недосказанность по вопросам:
— в продаже присутствуют почти одинаковые модули CY-30 и CY-302 на одном том же датчике BH1750FVI. Чем они отличаются и который лучше купить?
— датчик работает от 3.3В, микроконтроллер как правило от 5В, для их связи на модулях применены разные схемы преобразования уровней сигналов. В чем их отличия и какие могут быть проблемы?
Я купил оба модуля (благо стоят недорого) для изучения и возможности сравнить показания хотя бы между собой.
Модуль CY-302
Применялся в приведенных выше обзорах, габариты платы вдвое меньше у CY-30, деталей напаяно меньше.
Схема модуля
Входное напряжение 5В понижается линейным стабилизатором с маркировкой 662К (
datasheet) до 3.3В для питания датчика.
Линии данных SDA и SCL просто подтянуты к 3.3В резисторами 4.7К. Преобразователь уровня по сути отсутствует. Безопасно ли подключать к ним выводы 5В микроконтроллера рассмотрим ниже.
Модуль CY-30
Больше габаритами, больше радиодеталей.
Схема модуля
Все то же самое, плюс преобразование уровней сигналов SDA и SCL. Для линии SDA преобразование двунаправленное, на полевом транзисторе и двух резисторах, для линии SCL — однонаправленное, на диоде и резисторе. А нужен ли этот дополнительный обвес? Вон же работает у людей и без него!
Шина I2C
Про стандарт шины можно почитать:
robocraft.ru/blog/communication/780.html
easyelectronics.ru/interface-bus-iic-i2c.html
ru.wikipedia.org/wiki/I%C2%B2C
www.gaw.ru/html.cgi/txt/interface/iic/index.htm
Протокола обмена касаться не будем (для этого есть библиотеки), а рассмотрим более простой и важный для здоровья железок уровень физического подключения.
Основы:
— к шине подключаются устройства с выходом в режиме «с открытым коллектором» с образованием схемы «монтажное И», т.е. устройства могут:
— слушать шину в режиме входа с высоким входным сопротивлением,
— в режиме выхода притягивать шину к «земле», выдавая логический «0».
— в уровень логической «1» шина возвращается сама при помощи подтягивающих резисторов, когда ни одно устройство не выдает «0»;
— данные передаются в обе стороны по линии SDA;
— синхроимпульсы по линии SCL выдаются только Мастером, а Slave-устройства эту линию только слушают. Это стандартно, а реально некоторые устройства (пример — датчик влажности SHT21) и эту линию используют как двунаправленную, для информирования другой стороны о своем состоянии.
Отсюда следуют два важных следствия:
1. В схеме обязательно должны быть резисторы подтягивающие линии данных к "+" питания.
2. ЗАПРЕЩЕНА установка выхода в «1» (pinMode(OUTPUT), digitalWrite(HIGH) в Arduino; DDR=1, PORT=1 в AVR). Если другое устройство в это время «прижмет» линию к «земле», то будет КЗ и оба устройства выгорят!
В случае питания устройств от одного напряжения местоположение подтягивающих резисторов значения не имеет — могут быть например на плате Arduino, на модуле датчика, или вообще — встроенные в микроконтроллер подтягивающие резисторы порта.
А вот когда одно устройство питается от 5В, а другое от 3.3В, то без соответствующей развязки подтягивать шину к +5В уже нельзя — может выжечь ногу датчика, а то и 3.3В стабилизатор. Но если подтянуть шину на низкой стороне, к +3.3В, то запрет выдачи «1» идет нам на пользу — более высокое напряжение на нее уже никто не выдаст, а 3.3В даже 5В устройство воспримет как логическую «1» и все заработает и без преобразования уровней. Так сделано на «мелком» модуле CY-302.
Однако, дополнительные схемы преобразования уровней дают преимущества:
— повышается скорость и надежность передачи данных;
— некоторые схемы попутно защищают от последствий ошибок при монтаже и программировании: не пропускают высокое напряжение на низкую сторону. А ведь на некоторых платах Arduino напаяны резисторы подтяжки SDA и SCL к +5В, а в некоторых версиях библиотеки Wire.h включаются встроенные в МК подтяжки на те же +5В. Не проследили этот момент — и прощай датчик!
Про схемы преобразования уровней можно почитать:
we.easyelectronics.ru/Shematech/soglasovanie-logicheskih-urovney-5v-i-33v-ustroystv.html
playground.arduino.cc/Main/I2CBi-directionalLevelShifter
learn.sparkfun.com/tutorials/using-the-logic-level-converter
Таким образом, «мелкий» модуль CY-302 лучше применять в готовом устройстве, где гарантируется, что:
— нет резисторов подтяжки на +5В;
— в МК заранее загружена программа, в которой (а) не включаются встроенные подтяжки и (б) на выходы не подается «1».
«Крупный» модуль CY-30 лучше применять с ардуинкой и при отладке на макетке:
— в МК может запущена программа предыдущего проекта, где на эти выводы подключается подтяжка, а то и выдается логическая «1»;
— резисторы подтяжки на +5В могли остаться на макетной плате от другого проекта;
— разработчик (например ребенок) не в курсе, как устроена его плата Arduino и библиотека работы с I2C.
В этих случаях встроенные преобразователи уровня спасут датчик. И хотя преобразователь на одном полевике не способен защитить от КЗ, но и в этом случает выручит то, что датчик выставляет «0» и передает данные только получив свой адрес. А подключение с выводу со статическими +5В для этого модуля безопасно.
Люксметр
Разобравшись с матчастью, приступаем к конструированию устройства.
Требования к нему:
1. В качестве корпуса — небольшая распаечная коробка 75*75*20мм с «пеньком» самореза посередине.
2. Питание от литиевого аккумулятора BL-4C старого телефона Nokia.
3. Встроенная зарядка от micro-USB.
4. Кнопка включения и переключения режимов.
5. Отсутствие выключателя питания — коммутация питания транзисторами и использование Sleep режима микроконтроллера.
6. Два режима работы с разной настройкой датчика:
a) медленные замеры с высоким разрешением и отображение только освещенности;
б) замеры с максимальной частотой и расчет Min/Max/Avg значений и величины пульсации.
Ставить целый дисплей в устройство, отображающее только 1 число показалось излишним и решил применить лежащую в загашнике матрицу семисегментных индикаторов
FYQ-2541AS-11 (
datasheet) с красным свечением и общими катодами. Индикатор оказался странным (отдельный знак "-" оказался справа, да еще электрически соединен с точкой над ним, у старшего разряда нет десятичной точки, а точки наверху не светятся), но нам подойдет.
Выбираем микроконтроллер. У имеющихся ATtiny85 слишком мало ног, а добавлять отдельный драйвер для индикатора не хотелось. Arduino Pro Mini надо дорабатывать — удалить стабилизатор питания и светодиод, чтобы не разряжали аккумулятор при спящем МК. Отдельный чип ATmega328P — подходит идеально. Тактировать его будем на 1МГц от встроенной RC цепочки — высокая скорость не нужна (только лишний расход энергии), стабильность времени не важна.
Схема получается весьма простая:
Библиотечный элемент индикатора для Eagle нарисовал сам. Также сделал элемент для ATmega328P с ардуинскими обозначениями ног, вдруг решу в Arduino IDE программировать.
Схема (кроме датчика) питается напрямую от литиевого акумулятора. Стабилизировать напряжение нет никакой нужды, лишний расход деталей и энергии. В процессе разряда 4.2-3.0В только слегка меняется яркость индикатора. Можно было запитать всю схему от 3.3В, но стабилизатор на модуле датчика не потянет по току, а дополнительный нафиг не нужен.
Кстати, проводил эксперименты — ATmega328P стабильно работал и при 1.5В, светодиоды гасли, а МК молотил как ни в чем ни бывало.
Для зарядки аккумулятора взят «народный» модуль на TP4056.
Датчик подключается через двунаправленные преобразователи уровня на транзисторах Q6, Q7. Можно было не делать, но пусть будут — вдруг решу поменять датчик и они понадобятся. Для работы преобразователей нужно питание 3.3В, оно добыто на выводах резисторов 472 модуля (со стороны датчика) и проводом сквозь дырку Addr прокинуто на плату устройства.
Транзистор Q8 вырубает питание датчика.
Матрица анодами через токоограничивающие резисторы подключается к порту D микроконтроллера (D0-D7 ардуины). Сегменты A-G всех разрядов уже соединены внутри с расчетом на динамическую индикацию, к ним же подключаем точки, как пятый «разряд».
Общие катоды (разряды) через транзисторы Q1-Q5 замыкаются на землю по сигналу с порта B (D8-D12 ардуины). Подключать напрямую к МК (как делают некоторые ардуинщики) не рискнул — 175мА даже импульсного тока для одной ноги МК многовато.
Кнопка подключена также к порту D (D2 ардуины), поскольку это одна из двух ног, которая может генерировать прерывание и будить МК из спячки.
Ток и ограничивающие резисторы рассчитывал так:
Подходящая яркость на 4.2В достигается при 5мА с резистором 500 Ом. При динамической индикации на 5 разрядов (ШИМ 1:5) для сохранения той же яркости ток надо увеличить в 5 раз — значит резисторы 100 Ом. Однако, при импульсном питании свечение светодиодов кажется ярче, чем при постоянном и берем резисторы на 130 Ом.
Программирование производится через гребенку ICSP программатором USBasp (можно использовать Arduino как программатор).
Мучиться с макеткой и клубком проводков при удобстве ЛУТа неохота. Разводим в Eagle плату под размер корпуса. Используем выводные резисторы для возможности провести дороги между ног. Но из-за навороченного подключения индикатора сделать одностороннюю плату без десятка перемычек все равно не вышло.
Напаиваем детали. Датчик решил разместить под 90 градусов к основной плате, чтобы можно было его направлять на источник как фонарик и не засвечивать индикатор.
Программировать решил в AVR Studio 4.19. Во-первых, было лениво изучать чего ардуинщики наворочали в библиотеках, а во-вторых, тормозной ардуинский digitalWrite мало пригоден для организации быстрой динамической индикации.
Чтение кнопки и динамическая индикация на экране повешены на прерывания INT0 и 1мс таймера, чтение датчика и выбор чего показывать — в основном цикле.
Удивило, что в стандартных библиотеках AVR не оказалось либы для I2C (в МК есть аппаратная поддержка, но ее изучим в другой раз) и использовал первую попавшуюся, с софтовым ногодрыгом. Ну и пусть себе дрыгает и delay'ит, больше то в главном цикле ничего и не делается, все остальное работает на прерываниях.
Для общения с самим BH1750 с нужными 2 режимами никаких библиотек (а
они есть, и с поддержкой всех режимов датчика) решил не использовать, чего уж там — 2 функции по 3 строки.
Прошивка (исходники и hex):
yadi.sk/d/2pWcDk2VzNzGf
Фьюзы используются дефолтные для ATmega328P: 62 D9
В работе:
Короткое нажатие кнопки переключает режим (только освещенность или Max/Avg/Min/Pulse).
Что именно сейчас отображается говорят точки слева и точки/минус справа (похоже на %).
Если люксов больше 9999 — вместо младшего разряда отображается тоже точки/минус справа.
В основном режиме точность 1лк, время замера 120мс, период опроса 200мс.
В режиме Max/Avg/Min/Pulse точность 4лк, время замера 16мс, период опроса 20мс. Но режим достаточно бестолковый — пульсации с частотой выше 50Гц (а по науке даже 25Гц) датчик заметить не в состоянии. Рекомендуемые на замену TSL2561 (12мс) и MAX44009 (6,5мс) не сильно то ушли от BH1750FVI и смысла менять датчик не вижу.
Подсмотрел работу I2C шины:
Момент перехода на 20мс опрос + реально читает разные значения:
149.7310ms, I2C-0, [S] 47 Read 14 7E [P]
356.5130ms, I2C-0, [S] 47 Read 14 61 [P]
563.3060ms, I2C-0, [S] 47 Read 14 AE [P]
770.1460ms, I2C-0, [S] 47 Read 14 C7 [P]
976.9560ms, I2C-0, [S] 47 Read 14 EA [P]
1.1837920s, I2C-0, [S] 47 Read 15 1B [P]
1.3845370s, I2C-0, [S] 46 Write 13 [P]
1.4017910s, I2C-0, [S] 47 Read 14 E2 [P]
1.4209930s, I2C-0, [S] 47 Read 14 84 [P]
1.4403100s, I2C-0, [S] 47 Read 14 90 [P]
1.4595000s, I2C-0, [S] 47 Read 14 90 [P]
1.4788090s, I2C-0, [S] 47 Read 14 94 [P]
1.4980120s, I2C-0, [S] 47 Read 14 9C [P]
1.5173130s, I2C-0, [S] 47 Read 14 A0 [P]
При долгом (>3c) нажатие кнопки, разряде аккумулятора ниже 3В, после 5 минут работы устройство обесточивает датчик, гасит экран и засыпает. Перед засыпанием и в течение нескольких секунд после пробуждения отображает напряжение аккумулятора.
В состоянии сна МК мультиметр в режиме 2000мкА показывает потребление тока 0 мкА. За месяц напряжение на аккумуляторе не изменилось.
Второй имеющийся модуль, GY-30, подключил к ардуине и загрузил простейший скетч для BH1750FVI. Расположенные рядом датчики показывали различающиеся в пределах 5% значения.
Приборчиком доволен, теперь можно сравнивать лампочки.
ДОПОЛНЕНО 23.01.2017:
Задумал на досуге попроверять эффективность работы УЗ увлажнителя. Но гигрометра (кроме встроенного в сам увлажнитель) в хозяйстве не было. Поначалу хотел собрать на макетке из ардуинки и датчика DHT22, но взгляд упал на самодельный люксметр и решил сделать этот полезный показометр еще полезнее.
Для подключения датчика влажности и температуры DHT22 достаточно питания и одной свободной ноги МК — три проводка и датчик подключен:
Далее начинаем дорабатывать программу, и, как всегда, утыкаемся в ряд трудностей, про преодоление которых и хочу рассказать.
Было доработано:
1. В знакогенератор добавлены символы «h» и «t» для отображения режима, LEDScreenPrint() обучен выводить отрицательные значения.
2. Добавлена библиотека DHT.h работы с датчиком влажности.
3. Добавлен (третий) режим работы, в который попадаем коротким нажатием кнопки и в котором поочередно отображаются влажность и температура.
И если с п.1 и 3 никаких вопросов не возникло, то с библиотекой пришлось повозиться.
Главный момент — общение с датчиком DHT22 происходит всего по одному проводу, нет отдельной линии синхронизации, а значит надежность чтения данных сильно зависит от протокола обмена и способности МК отмерять необходимые интервалы времени. А у нас МК работает на 1МГц от внутреннего RC-генератора, а значит тактовая частота не точная, да еще заметно плавает.
Лезем в
даташит на датчик и видим, что минимальный интервал, который надо замерить — 26мкс, а перед каждым битовым импульсом всегда следует пауза в 50мкс. Сам протокол дает возможность перед приемом каждого бита «подстроить» часы по длине паузы и нестабильность тактовой частоты уже не опасна.
Накачал несколько разных библиотек, но ни одна не подходила по всем параметрам:
1) в одних МК отмеряет отрезки времени при помощи delay, а затем смотрит что там на входе — непригодно при нестабильной частоте и невозможно синхронизироваться по самому сигналу.
2) в других, например от Adafruit Industries, наоборот — МК непрерывно следит за входом засекая время между фронтами. Но автоподстройки по длительности паузы нет и здесь, а длина импульса сравнивается с некоторой предопределенной уставкой.
Потому было решено доработать наиболее подходящий вариант — от Adafruit, всего то пара строчек дополнительного кода (сравниваем длину битового импульса не с уставкой, а с длиной предыдущей паузы) и все заработает и при сильно нестабильной частоте МК.
Однако хватит ли вообще быстродействия в 1 МГц? Arduino то тактируется минимум на 8 МГц (3.3В версия). Для этого надо проанализировать код библиотеки. Замер интервала между фронтами и упаковка принятого бита занимают порядка 15 команд ассемблера, причем часть из них выполняются за 2-3 такта. А такт у нас 1мкс и значит замер 26мкс уже на пределе возможностей. Вывод — для надежной работы надо увеличивать частоту МК.
Но напаивать кварц и конденсаторы не придется. Благо даже у встроенного генератора можно увеличить частоту до 8 МГц простой перепрошивкой фьюзов (сбросив бит CKDIV8). Дополнительно надо поправить задание F_CPU=8000000UL в свойствах проекта и увеличить на 8 предделитель таймера, чтобы время не ускорилось.
В итоге, влажность и температура прочитались без проблем, освещенность читается как и раньше, а последствия разгона вылезли глюком там, где совсем не ожидал — перестало читаться напряжение питания, точнее стало выдавать в 2.5 раза меньше нормального.
Замер напряжения питания без лишних деталей и расхода выводов был сделан с использованием функции vccRead из вот
этой статьи. Вроде все просто, в Arduino с 16МГц кварцем — работает, с внутренним генератором на 1 МГц — работает, а на 8 МГц — работать перестало.
Лезем в даташит на ATmega328 и изучаем работу с АЦП в разделе тактирования. Там английским по белому написано, что максимальная рабочая частота АЦП (с разрешением 10 бит) — 200 КГц. В функции vccRead делитель тактовой частоты для АЦП не задается. В Arduino его видимо определял фреймворк, а я его задать забыл вообще, а по умолчанию он равен /2. Т.е. раньше у меня АЦП работал на 500 КГц, и однако успешно работал! И на 4 МГц продолжил работать, но уже не так успешно.
Для исправления добавляем в vccRead в инициализацию АЦП задание битов ADPS2, ADPS1, ADPS0 выставляющее предделитель /64, т.е. тактирование АЦП на 125 КГц и все заработало как надо.
Версия прошивки с поддержкой DHT22 (исходники и hex):
yadi.sk/d/zCT31Kn03AVEhB
Фьюзы: E2 D9
https://aliexpress.com/item/item/MAX44009-Ambient-Light-Sensor-Module-with-4P-Pin-Header/32761901963.html
По цене практически то же самое, а по характеристикам на голову превосходит B1705 и TSL2561
У него в первую очередь больше измеряемый диапазон как в меньшую сторону почти на два порядка, так и в большую
https://aliexpress.com/item/item/1pcs-lot-GY-302-BH1750-Chip-Light-Intensity-Light-Module/32673799136.html
хотя мне в моих поделках хватает датчика TEMT6000 вполне хорошо определяет освещённость в квартире в вечернее время
BH1750 диапазон измерения 1 — 65 535 lx а если реализовать в прошивке auto range то спокойно можно и 0.11 — 100 000 lx выжать.
для бытовых нужд вполне хватет 1 — 65 535 lx. Вобщем когда цена на MAX44009 опустится до $0.93 то можно переходить на него.
Свой труд в изготовлении платы лично я цегю намного дороже, поэтому экономить на самых ключевых деталях можно либо на коммерческих партиях, которые нужно слепить как можно дешевле, либо на коленках разово что-то померить.
А так дешевле фоторезистора ничего не найдете — тоже вполне мерит освещенность если есть чем откалибровать
про остальное с вами согласен. если есть деньги берите MAX44009, если нет, то BH1750 вполне еще неплохой вариант.
А менять BH1750FVI никакого смысла не вижу — измерять в темноте или на улице в солнечный день мало кому надо, а выше разрешение и частота 100Гц вместо 50 не принципиальны.
Вот если бы был встроенный режим замера пульсаций с приличной частотой…
В ардуину залил скетч, простенькая платка…
И вместо матриц можно поюзать LCD.
Хотя каждому ближе то, с чем он знаком: ардуина, пик, атмел…
Скачать инструкцию в интернете и по ней проводки соединить — знание физики вообще не нужны )))
хорошо на ней клепать конечные автоматы
И, кстати, у друзей дети-первоклашки в кружок ходят, так они там на ардуине роботов ваяют и сражения устраивают.
Подключение i2c устройства к шине одно из самых простых: два подтягивающих резистора на линии данных и питание с землей (4 провода).
Вот фонарик приближал для интереса
Туда же…
Порты защищают от перенапряжения диодами, рассчитанными на микроамперные токи. Ток от встроенной подтяжки 50КОм наверняка выдержит, а вот если подтяжка внешняя да на пару килоом? А если вместо нее открытый полевик?
Я вижу тут ~45ом
Для датчика подобного не нашел, но думаю, там будет больше.
Подтяжка от 5В — тоже не сделает дела.
P.S. Я знаю, что так делать нельзя и всячески не приветствую вещи типа «заявлено 3В, но у меня и от 4 работает». Но тут — «не сгорит»
Для меги максимальный ток 40мА, для датчика — SDA Sink Current Imax 7 mA.
И рассчитывать на выживание при КЗ благодаря тому «на проводах напряжение просядет» совсем не дело.
По поводу защитных от перенапряжения диодов не видел значений допустимого тока в документах, но везде упоминаются только микроамперы.
Оно конечно может повезти, железка окажется крепкая и волшебный дым не выйдет, но так делать — нельзя!
Нормально измерить частоту (но в ущерб точности) смогут быстрый фотодиод+быстрый АЦП, как здесь
radiokot.ru/konkursCatDay2014/47/
Или, проще всего, фотодиод+осциллограф.
50 герц — это 0.02 сек. Время измерения, на самом грубом режиме, у BH1750 равно 0.025 сек. Так что реально померять пульсации от 38 гц и ниже.
BH1750FVI. TSL2591, TSL2561, OPT3001. MAX44007, MAX44009, OPT300, TEMT6000
Помогите пожалуйста с выбором сенсора и примероом кода.
Собирала термометр нв базе NodeMCU v3 + DS18b20 передающий температуру на Народный Мониторинг. Хочу добавить в этот проект один из датчиков освещенности на I2C.
Кто то из соседей каждую ночь отключает свет над подъездом и странно в этот же день сливают бензин. Я хочу установить камеры, уже присмотрела, но пока денег нет на комплект. А вот датчик добавить к проекту очень просто.
Спасибо
с библиотекой от Adafruit была печаль, а вот с библиотекой SFE_TSL2561 все получилось, темноту видит хорошо — от 0lux
делал по инструкции:
learn.sparkfun.com/tutorials/tsl2561-luminosity-sensor-hookup-guide/all
сама библиотека:
github.com/sparkfun/TSL2561_Luminosity_Sensor_BOB
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.