RSS блога
Подписка
TOF050C + OLED = дальномер
Не так давно на Aliexpress появились модули лазерных дальномеров, основанные на датчиках VL6180X (или подобных) от фирмы STM. Причем их стоимость на удивление низкая. Например, модуль TOF050C за 2.1 USD, не считая пересылки. Измерять расстояния особой потребности нет, но на работе понадобился источник коротких световых импульсов для проверки фотоприемников, для чего данный датчик идеально подошел. Чтобы он не светил зря, я решил задействовать и его основную функцию – измерение расстояния. Просто в ознакомительных целях.
По меркам человека из прошлого века, такой датчик – это просто фантастика. Внутри маленькой микросхемы расположен лазер, фотоприемник, а также схема измерения микроскопических интервалов времени, за которые свет успевает дойти до препятствия и вернуться обратно. Датчик способен измерять даже такое малое расстояние, как 10 мм, которое свет проходит туда-обратно за время примерно 67 пикосекунд!
Данная технология измерения расстояния называется FlightSense, более подробно о ней можно почитать на сайте STM.
В качестве излучателя в датчике используется VCSEL-лазер. Расшифровывается как «Vertical-Cavity Surface-Emitting Laser», или «поверхностно-излучающий лазер с вертикальным резонатором». Произносится как «Vixel». В отличие от обычных полупроводниковых лазеров, где излучает торец кристалла, тут излучение происходит в направлении, перпендикулярном поверхности кристалла. VCSEL-лазеры имеют целый ряд полезных свойств, в частности, у них очень низкий порог генерации по току. Что позволяет их использовать в датчиках мобильных устройств, где вопрос экономии энергии стоит очень остро.
Лазер датчика работает в ИК-диапазоне, длина волны 850 nm. Лазер излучает очень короткие импульсы. Длительность импульса примерно 3.3 нс, период повторения импульсов – 10 нс.
В качестве приемника излучения в датчике используется массив SPAD-фотодиодов. Это «Single Photon Avalanche Diode», или «однофотонные лавинные фотодиоды». Они способны регистрировать одиночные фотоны, выдавая на выходе электрический импульс. Для питания таких фотодиодов требуется довольно высокое напряжение. В описании датчика говорится про 14 В, для чего внутри имеется умножитель напряжения.
Дополнительно VL6180X имеет датчик окружающего света (ALS, Ambient Light Sensor). Он может быть использован для измерения освещенности в широком диапазоне, в том числе, при очень низкой освещенности (порядка 1 lux). Максимум спектральной чувствительности датчика лежит на длине волны 550 nm. На рисунке из datasheet показаны диаграммы направленности излучателя, приемника и датчика ALS.
Чтобы сделать из датчика полноценный дальномер, нужен процессор, который будет считывать показания датчика, и нужен дисплей, куда процессор будет выводить результат. В качестве процессора я выбрал ATmega88, так как макетная плата с ним лежала ближе всего. В качестве дисплея сначала планировал применить LCD, но захотелось чего-то более компактного, поэтому выбрал OLED-дисплей с разрешением 128 х 32 точки и диагональю 0.91 дюйма. Дисплей был куплен на Aliexpress (старая ссылка уже не работает, но аналогичные дисплеи есть по другим ссылкам), обошелся примерно 1.6$ вместе с доставкой.
Занятие электроникой в настоящее время довольно сильно изменило свою форму. Сейчас редко приходится проектировать схемы целиком из «элементарных» компонентов, таких как резисторы, конденсаторы, транзисторы, диоды. Сначала появились микросхемы и заменили собой значительные фрагменты схем, а теперь получили распространение готовые модули, которые просто надо соединить между собой. Получается некое подобие детского конструктора из кубиков.
Как правило, сейчас каждый модуль имеет цифровой интерфейс и подключается к микроконтроллеру. Появляется дополнительная задача программной поддержки модулей. Но и тут действует тот же принцип строительства из кубиков – существует большое количество готовых библиотек. В чем сильно помогла платформа «Arduino». Ее многие ругают, но совершенно напрасно. Она резко снизила планку вхождения в электронику и программирование, приобщив к этому занятию множество людей. А с претензиями по поводу надежности можно поспорить. Схемы и платы там вполне обычные, сделаны хорошо. А программное обеспечение – это еще вопрос, что надежнее, самодельная программа, написанная и протестированная одним человеком, или библиотека, которой пользуются тысячи людей, каждый из которых жадно ищет ошибку, чтобы первому о ней объявить. Сам я эту платформу не использую, но лишь потому, что вошел в мир электроники и микроконтроллеров намного раньше, чем она появилась.
Конечно, не вся электроника выглядит именно так, иногда приходится копаться и в мелочах. Но это в тех случаях, когда речь идет о чем-то особенном, для чего еще не сделан свой «кубик».
Даже собирая систему из кубиков, не всё так просто и гладко. Хоть задача сводится в основном к организации питания кубиков и согласования их между собой, тут тоже хватает подводных камней. В данном случае требуется соединить микроконтроллер с дисплеем и датчиком, а также запитать всё это.
Выбранный OLED-дисплей построен на базе контроллера SSD1306. Кристалл этой микросхемы имеет огромное количество выводов (целых 281) и расположен на стекле дисплея. Основная часть выводов соединена с матрицей светодиодов. У контроллера 128 выводов предназначено для управления столбцами, и 64 вывода для управления строками (из которых тут задействована только половина, так как разрешение дисплея 128 х 32 точек).
Внутри контроллера имеется видеопамять, каждой бит которой соответствует точке на экране. Чтобы зажечь точку, надо записать единичку в нужный бит по нужному адресу. Общий объем видеопамяти – 1024 байта (8192 бит).
Кроме видеопамяти внутри контроллера имеются регистры конфигурации. Они позволяют управлять его работой. Чтобы дисплей заработал, после включения питания надо провести инициализацию – записать в нужные регистры нужные коды.
Контроллер поддерживает 5 видов последовательных и параллельных интерфейсов, мой вариант дисплея имеет последовательный интерфейс SPI. Существует еще вариант с управлением по шине I2C. Вариант с SPI позволяет быстрее передавать данные, но требует для подключение большего количества проводов (и выводов микроконтроллера). Для данного проекта скорость обновления экрана не особо важна, можно было применить любой вариант. Выбрал тот, который был под рукой.
Когда контроллер использует последовательный интерфейс, то возможна только запись информации в видеопамять, а чтение из нее невозможно. Это очень плохо, но об этом ниже.
На плате дисплея расположена вся необходимая «обвязка» контроллера SSD1306. Это блокировочные конденсаторы, «летающие» конденсаторы для встроенного умножителя напряжения, опорный резистор для задания тока через светодиоды пикселей. Принципиальная схема нашлась на страничке продавца.
Контроллер SSD1306 питается напряжением 3.3 В, для этого на плате установлен отдельный стабилизатор XC6206P-33 (маркировка 662K). На контакт VCC разъема платы можно подавать 5 В. Но сигналы цифрового интерфейса идут напрямую на контроллер, соответственно, имеют логические уровни 3.3 В.
Поскольку здесь возможна только запись данных, то все логические сигналы являются входными. Иногда логические микросхемы могут иметь логические входы, «толерантные» к напряжению, превышающему напряжение питания самой микросхемы. Примером могут служить некоторые входы микроконтроллеров STM32 или входы логики серии 74LVC. Для SSD1306 это не так, входы имеют обычные защитные диоды, подключенные к питанию. Если на логический вход подать сигнал с уровнем 5 В, то микросхема начинает питаться от этого сигнала через защитный диод. На выводе питания появляется напряжение, которое ниже входного примерно на 0.65 В, что является типичным прямым падением на кремниевом диоде. Поэтому подавать на дисплей логические сигналы с уровнями 5 В нельзя. Как тогда быть в системах с напряжением питания 5 В? Можно применить резисторные делители. Но надо учитывать, что они могут ограничить максимальную скорость передачи данных из-за паразитных емкостей. Для устройств с жесткими требованиями к потребляемому току делители тоже могут не подойти – при высоком логическом уровне они постоянно потребляют ток. Еще один вариант – использовать выходы с открытым стоком. Но в микроконтроллерах AVR нет возможности реализовать выходы с открытым стоком для аппаратного SPI. Самое надежное решение – применить преобразователи уровней на МОП-транзисторах или в виде интегральной микросхемы.
А что же с питанием датчика TOF050C? Микросхема датчика питается напряжением 2.8 В, для чего на плате модуля установлен стабилизатор напряжения. В результате модуль можно питать напряжением 5 В или 3.3 В, этого будет достаточно для работы LDO-стабилизатора на 2.8 В. На плате модуля есть и другая «обвязка», принципиальная схема нашлась на страничке продавца.
Модуль имеет интерфейс I2C, линии SDA и SCL со стороны микросхемы датчика подтянуты резисторами к питанию 2.8 В. Затем эти линии проходят через преобразователи уровня, выполненные на сборке полевых транзисторов 2N7002DW (маркировка K72), и только потом поступают на разъем модуля. Со стороны разъема они подтянуты резисторами к входному питанию. Таким образом, уровень логической единицы этих сигналов будет равен напряжению питания модуля и может быть как 3.3 В, так и 5 В.
Кроме сигналов SDA и SCL микросхема датчика имеет еще два логических сигнала: INT и SHUT. Они поступают на выводы модуля прямо с выводов микросхемы и преобразователей уровней не имеют. Для этих сигналов уровень логической единицы равен напряжению питания микросхемы, т.е. 2.8 В. На плате модуля они подтянуты резисторами к этому напряжению. Сигнал INT формирует микросхема при окончании цикла измерения. Сигнал SHUT по умолчанию работает как вход сброса. Уровень сигнала INT (2.8 В) с трудом вписывается в допустимый диапазон для логической единицы на входе микроконтроллера с напряжением питания 5 В. Поэтому здесь требуется преобразователь уровня. Входом сброса, в принципе, можно управлять с помощью выхода с открытым стоком, подтягивающий резистор уже есть на плате модуля.
Как видим, при питании микроконтроллера напряжением 5 В возникает масса проблем. Это заставило пересмотреть выбор напряжения питания. У дисплея в сумме 5 сигналов (SCK, SDA, RES, DC, CS), это требует 10 резисторов делителей, что довольно громоздко. Еще нужен преобразователь уровня для сигнала INT датчика расстояния. От всего этого можно отказаться, если перевести питание микроконтроллера на 3.3 В. Правда, при этом потребуется небольшая переделка дисплея: нужно выпаять микросхему стабилизатора 3.3 В и установить вместо нее перемычку. Это несложно, но «из коробки» использовать модули, как ни странно, не получается.
Первым делом решил разобраться с дисплеем. В Интернете можно найти библиотеки для работы с ним. Если бы мне нужно было побыстрее сделать проект, взял бы все готовое. Но это неинтересно, хочется написать код самостоятельно, лишь иногда подсматривая в чужие исходники. В готовых библиотеках всегда что-то не так, как хотелось бы, да и при использовании готового сложно получить представление о всех возможностях железа.
Самой таинственной операцией является процесс инициализации дисплея. Он выглядит как какое-то заклинание – по определенным адресам записываются определенные коды. Разобраться в этих кодах не так просто. Казалось бы, достаточно прочитать datasheet на контроллер дисплея. Но там не будет конкретики, касающейся именно этого дисплея. Потому что контроллер универсальный, и он может быть использован по-разному. Существуют datasheet на дисплеи с этим котроллером (например, вот), но не факт, что они в полной мере соответствуют имеющемуся дисплею от непонятного производителя. Самое смешное, что даже в datasheet нет толкования отдельных загружаемых в регистры значений – всё те же магические числа, взявшиеся неизвестно откуда.
В принципе, можно просто скопировать значения с одного из документов или готовой библиотеки, обычно разночтений не случается. Есть только несколько регистров, значения в которых могут отличаться от рекомендованных и на которые надо обратить внимание.
Во-первых, код инициализации будет зависеть от размеров дисплея. Обычно он отличается кодом в двух регистрах:
Set Multiplex Ratio (A8h) = 1Fh для 128 х 32, 3Fh для 128 х 64
Set COM Pins Hardware Configuration (DAh) = 02h для 128 х 32, 12h для 128 х 64
Механически плата дисплея не является симметричной. При использовании в конкретном устройстве, ее удобней располагать вполне определенным образом. Например, в моем случае выводы платы должны быть снизу. Здесь имеется полная свобода, так как есть регистры, позволяющие зеркалить изображение по горизонтали и вертикали:
Set Segment Re-map (A0h/A1h) – зеркалит/не реркалит по горизонтали
Set COM Output Scan Direction (C0h/C8h) – зеркалит/не зеркалит по вертикали
Еще можно менять значение контраста изображения, хотя чаще всего обходятся значением по умолчанию.
Есть два регистра, значения в которых зависят от выбранного способа питания OLED-матрицы: внешнее, или с использованием встроенного преобразователя. В данном модуле дисплея используется встроенный преобразователь.
Set Pre-charge Period (D9h) = 22h – внешнее питание, F1h – внутренний преобразователь
Charge Pump Setting (8Dh) = 10h – внешнее питание, 14h – внутренний преобразователь
Встречал в Интернете обсуждение минимизации помех индикатора с помощью регистра Set Pre-charge Period. Но пришли к выводу, что на уровень помех он не влияет. По моим наблюдениям – тоже. Надо отметить, что потребляемый OLED-дисплеем ток носит импульсный характер и зависит от выводимой картинки. Помех получается больше, чем от LCD-дисплеев, в некоторых применениях это может быть критично. Максимальный потребляемый ток этого дисплея составил 24 мА.
Самый загадочный регистр – это Set VCOMH Deselect Level (DBh). Его значения могут быть 00h, 10h, 20h, 30h, 40h, 50h, 60h, 70h. Он управляет напряжением V_COMH, которое выведено наружу (на плате модуля установлен блокировочный конденсатор), и которое можно измерить. В datasheet приведены 3 варианта кодов, но в библиотеках обычно туда загружают другой код (40h). Попробовал менять это значение – при коде 40h напряжение V_COMH максимально, дальнейшее увеличение кода ни на что не влияет.
В документе AN001 «OLED Driver Basic Register Setup» от фирмы Osram есть интересная табличка, где описаны симптомы неправильного программирования регистров контроллера OLED. Про напряжение V_COMH сказано, что при слишком низком могут быть артефакты взаимного влияния пикселей (cross-talk), а при слишком высоком может пострадать надежность дисплея.
Когда дисплей подключен и инициализирован, на него можно выводить желаемую информацию. Для этого я написал небольшой набор функций и адаптировал несколько шрифтов, которые ранее использовал для LCD. Дисплей оказался настолько маленьким, что для отладки функций вывода пришлось использовать микроскоп. Чаще всего возникают «краевые» ошибки, когда не хватает одного пикселя или появляется один лишний. Рассмотреть отдельный пиксель здесь довольно затруднительно.
При написании функций вывода на дисплей всплыла очень неприятная особенность контроллера. Дело в том, что при использовании последовательного интерфейса контроллер не позволяет читать данные из видеопамяти. Поэтому невозможно делать обновление изображения по принципу «чтение-модификация-запись». Контроллер поддерживает разные режимы адресации видеопамяти, которые можно задавать при инициализации дисплея. Но всегда адресация по вертикали делается с точностью до байта (здесь это называется Page). Если выводим что-то на дисплей, что по высоте занимает меньше байта, то перезаписывается весь байт. Например, если выводим строчку текста, которая затрагивает по вертикали только часть байта, оставшуюся часть нельзя использовать для вывода следующей строчки – будет стерта нижняя часть предыдущей. Приходится распределять экран таким образом, чтобы отдельные объекты размещались в отдельных байтах. Это накладывает существенные ограничения на дизайн интерфейса.
Конечно, такую проблему легко решить – в памяти микроконтроллера надо выделить буфер, равный по размеру видеопамяти. Сначала рисовать там, а потом копировать буфер в память дисплея (весь, или только изменившиеся байты). Но для младших микроконтроллеров это не всегда возможно из-за недостатка ОЗУ. Для ATmega88 и дисплея 128 х 32 буфер использовать можно, но уже для дисплея 128 х 64 это станет невозможным, так как буфер займет всё ОЗУ микроконтроллера.
Обидно, что данную проблему можно было очень легко обойти на этапе проектирования ASIC контроллера дисплея. Достаточно было для адресации по вертикали использовать не байты (Page), а строки. Т.е. границы блока, подлежащего обновлению, задавать с точностью до пикселя. Передаваться будут целые байты, как обычно, но те биты, которые лежат за границей блока, будут маскироваться и не будут записываться в видеопамять. В итоге видеопамять за пределами блока никогда не будет испорчена, даже если границы блока проходят внутри байта. Но, увы, здесь этого нет.
Для данного проекта, когда надо выводить фактически только одну строку, такой изъян адресации помешал не сильно. Но если потребуется выводить что-то более сложное, надо либо брать процессор с ОЗУ побольше, либо придумывать какие-то хитрости с обновлением дисплея.
В целом OLED-дисплей понравился, он дает контрастную картинку с очень хорошими углами обзора. Дисплей с диагональю побольше выглядит еще лучше, надо будет в будущем сделать на нем какой-нибудь проект. Единственный вопрос – это срок службы таких дисплеев. Но и тут всё не так плохо, если судить по имеющимся тестам. Да и не все устройства должны работать круглосуточно.
Подключение датчика TOF050C при питании процессора 3.3 В не вызывает проблем. Логический уровень выхода INT согласуется непосредственно. Вход SHUT тоже можно подключить к процессору напрямую – превышение 3.3 В над 2.8 В недостаточно для открывания защитных диодов. Но я решил на всякий случай использовать выход с открытым стоком – так правильней.
Инициализация микросхемы VL6180X – это вообще сущий ад. Ради единичного и не слишком важного проекта изучать 87-страничный datasheet не совсем уместно. Кроме datasheet, есть еще User manual UM1983 «VL6180X proximity, gesture and ambient light sensing (ALS) module », DT0035, DT0037 и другие документы. А еще есть Application note AN4545 «VL6180X basic ranging application note» где приведена готовая таблица магических заклинаний, которые надо по I2C передать внутрь микросхемы, чтобы она ожила. К счастью, магия сработала, подробно разбираться с вопросом не пришлось. Это ведь не OLED-дисплей, который может быть полезен и для других проектов. Датчик расстояния вряд ли придется еще когда-либо использовать, глубокие знания тут скорее окажутся бесполезными. Как бы то ни было, макет с датчиком и дисплеем ожил и начал показывать расстояние.
Некоторые странности при работе датчика все-таки были обнаружены. При отладке питал конструкцию от лабораторного БП. Когда ее подключал к включенному заранее БП, все работало нормально. Но когда сначала подключал, а потом включал БП, то из датчика постоянно стал считываться код FFh. Чтобы разобраться, в чем дело, считал значение регистра STATUS. При ошибке считался код 11h (17), что означает ошибку «VCSEL Continuity Test». В норме STATUS читается как 03h. Вероятно, из-за медленного нарастания напряжения питания перестал срабатывать внутренний сброс микросхемы VL6180X. Пришлось задействовать сигнал SHUT, который по умолчанию выполняет функцию сброса микросхемы. Чего в начале я делать не хотел, думал вообще обойтись подключением только двух сигналов – SDA и SCL.
Шина I2C на скорости 400 кГц нормально не заработала, при чтении возникали ошибки. Но на скорости 200 кГц все работало нормально, так и оставил.
При переходе из однократного режима в циклический изредка были зависания датчика, тогда показания замирали. Похоже, по какой-то причине переставал приходить сигнал прерывания. Для защиты от такой ситуации добавил таймер на 100 мс: если прерывание за это время не поступило, вызывается инициализация модуля. Больше зависаний не видел.
Для калибровки показаний датчика служит значение Offset. Процедура калибровки описана в datasheet. Заводское значение Offset записано в энергонезависимой памяти (NVM) и считывается после включения питания. Если я делаю свою калибровку, то, по идее, я могу перезаписать значение в NVM своим значением. Можно ли это сделать, и как – я так и не понял. Плюнул и сохраняю Offset в EEPROM микроконтроллера.
После устранения найденных шероховатостей, можно рисовать окончательную принципиальную схему. У меня она получилась такой:
Питание устройства задумывалось от внешнего БП через разъем. Можно было, конечно, поставить аккумулятор, но мне автономность не нужна. Показания дальномера планировалось не только выводить на дисплей, но и считывать на компьютер через разъем USB. А раз так, то желательно предусмотреть питание и от него. На моей схеме питание от двух источников суммируется через сдвоенный диод VD1. При питании от USB диод шунтируется транзистором VT1 для уменьшения падения напряжения. Эта мера не сильно нужна при питании 3.3 В, для стабилизатора хватит входного напряжения и с учетом падения на диоде. Но данное решение осталось от первоначальной задумки питать процессор напряжением 5 В, решил транзистор оставить.
Теперь надо выбрать корпус и разработать конструктив. В качестве корпуса взял давно купленный на Aliexpress алюминиевый профиль. Плата задвигается в него на салазках, никакого крепления не требуется. Размеры платы получились 57 х 40.5 мм. Плату изготовил с помощью ЛУТ. Плата получилась почти односторонней, вторая сторона залита земляным полигоном, и на ней есть лишь две дорожки питания и одна дорожка для подключения кнопки.
Датчик крепится к передней панели винтами и подключается к плате через разъем. В плату датчика впаяны прямые штырьки PLS. Ответная часть – разъем PBS, который размещается в вырезе платы и припаивается к площадкам на SMD-манер. На фотографии платы в районе этого разъема видны перемычки. Дело в том, что первоначально вырез в плате не планировался, а разъем должен был лежать на поверхности платы. При этом датчик должен был установлен немного выше середины передней панели. Но чувство прекрасного взяло верх, датчик был врезан точно в центр передней панели, а разъем пришлось опустить, сделав вырез. При этом дорожки, которые проходили снизу платы на месте выреза, пришлось восстановить перемычками. Но это внутри, а снаружи все красиво и симметрично.
На задней панели расположен разъем питания, разъем USB и одна кнопка. Для кнопки придумал функцию – переключение абсолютных и относительных измерений. При включении относительных на экране загорается надпись «REL».
Дисплей вставляется в разъем сверху, дополнительно он опирается на две пластиковые стойки с резьбой М2. При разработке платы надо учитывать тот факт, что физический центр активной области дисплея не совпадает с центром платы модуля.
Собранная плата сразу заработала, ведь прошивка была заранее отлажена на макете. Датчик нормально показывает расстояния до 170 – 180 мм, хоть в datasheet гарантируют только до 100 мм. Расстояние представлено однобайтным числом, т.е. может быть от 0 до 255 мм с дискретностью 1 мм. В документе User manual UM1876 «Getting started with VL6180X proximity, gesture, ambient light sensor software expansion for STM32Cube» описана возможность увеличения шкалы расстояний датчика ценой уменьшения разрешающей способности, чего нет в datasheet. Можно включить масштабирование шкалы в заданное число раз: 1, 2 или 3. Но за ненадобностью эту возможность я не проверял.
Для компьютера написал простейшее приложение, которое позволяет выводить показания датчика, а также проводить его калибровку. Калибровка сохраняется в EEPROM микроконтроллера и используется в дальнейшей автономной работе.
Откалибровал датчик по методике, изложенной в datasheet. Там требуется на расстоянии 50 мм расположить поверхность с коэффициентом отражения 88%. На практике коэффициент отражения поверхности влияет слабо, это требование можно не соблюдать. Если показания находятся в пределах ±3 мм, то считается, что калибровка не требуется. В других случаях надо обнулить Offset, провести 10 измерений расстояния, найти среднее значение, и по нему вычислить новое значение Offset.
Осталось вырезать окно для индикатора в профиле и изготовить стекло. Но сначала надо это стекло выбрать. Цвет свечения индикатора – холодный белый, сильно отдающий синевой. Хочется иметь более приятный цвет свечения, чего можно добиться с помощью светофильтра. Больше всего понравилось красное оргстекло, оно дает янтарный цвет свечения, который называется красивым словом Amber. Но это стекло слишком прозрачное, пришлось взять более темное стекло.
Вот так выглядит устройство в сборе:
Что можно сказать в качестве вывода? Модуль дальномера TOF050C работает, и работает неплохо. Но какого-то практического применения для него я не вижу. Как уже было сказано выше, это устройство делалось просто как источник коротких световых импульсов для проверки фотоприемников на работе. Измерение расстояния – это всего лишь приятный бонус.
Лично для меня в этом проекте гораздо интереснее OLED-дисплей. Он мне понравился, надо в будущем применить подобный в каком-нибудь другом проекте. Для этого куплены OLED-модули разных цветов и размеров.
Надо сказать, что проектировать интерфейс на графическом дисплее крайне трудоемко и неудобно. Если делать это сразу на микроконтроллере, то требуется большое количество перепрошивок при отладке, чтобы увидеть, как будет смотреться тот или иной вариант экрана. Для упрощения разработки надо на компьютере написать эмулятор такого дисплея, чтобы с комфортом разрабатывать интерфейс, а потом просто перенести весть текст на Си, вместе с массивами картинок и шрифтами в микроконтроллер. Но это тоже кусок работы, требующий времени. На что именно надо в первую очередь тратить свое время – это тоже вопрос, и на его решение тоже уходит время.
По меркам человека из прошлого века, такой датчик – это просто фантастика. Внутри маленькой микросхемы расположен лазер, фотоприемник, а также схема измерения микроскопических интервалов времени, за которые свет успевает дойти до препятствия и вернуться обратно. Датчик способен измерять даже такое малое расстояние, как 10 мм, которое свет проходит туда-обратно за время примерно 67 пикосекунд!
Данная технология измерения расстояния называется FlightSense, более подробно о ней можно почитать на сайте STM.
В качестве излучателя в датчике используется VCSEL-лазер. Расшифровывается как «Vertical-Cavity Surface-Emitting Laser», или «поверхностно-излучающий лазер с вертикальным резонатором». Произносится как «Vixel». В отличие от обычных полупроводниковых лазеров, где излучает торец кристалла, тут излучение происходит в направлении, перпендикулярном поверхности кристалла. VCSEL-лазеры имеют целый ряд полезных свойств, в частности, у них очень низкий порог генерации по току. Что позволяет их использовать в датчиках мобильных устройств, где вопрос экономии энергии стоит очень остро.
Лазер датчика работает в ИК-диапазоне, длина волны 850 nm. Лазер излучает очень короткие импульсы. Длительность импульса примерно 3.3 нс, период повторения импульсов – 10 нс.
В качестве приемника излучения в датчике используется массив SPAD-фотодиодов. Это «Single Photon Avalanche Diode», или «однофотонные лавинные фотодиоды». Они способны регистрировать одиночные фотоны, выдавая на выходе электрический импульс. Для питания таких фотодиодов требуется довольно высокое напряжение. В описании датчика говорится про 14 В, для чего внутри имеется умножитель напряжения.
Дополнительно VL6180X имеет датчик окружающего света (ALS, Ambient Light Sensor). Он может быть использован для измерения освещенности в широком диапазоне, в том числе, при очень низкой освещенности (порядка 1 lux). Максимум спектральной чувствительности датчика лежит на длине волны 550 nm. На рисунке из datasheet показаны диаграммы направленности излучателя, приемника и датчика ALS.
Чтобы сделать из датчика полноценный дальномер, нужен процессор, который будет считывать показания датчика, и нужен дисплей, куда процессор будет выводить результат. В качестве процессора я выбрал ATmega88, так как макетная плата с ним лежала ближе всего. В качестве дисплея сначала планировал применить LCD, но захотелось чего-то более компактного, поэтому выбрал OLED-дисплей с разрешением 128 х 32 точки и диагональю 0.91 дюйма. Дисплей был куплен на Aliexpress (старая ссылка уже не работает, но аналогичные дисплеи есть по другим ссылкам), обошелся примерно 1.6$ вместе с доставкой.
Занятие электроникой в настоящее время довольно сильно изменило свою форму. Сейчас редко приходится проектировать схемы целиком из «элементарных» компонентов, таких как резисторы, конденсаторы, транзисторы, диоды. Сначала появились микросхемы и заменили собой значительные фрагменты схем, а теперь получили распространение готовые модули, которые просто надо соединить между собой. Получается некое подобие детского конструктора из кубиков.
Как правило, сейчас каждый модуль имеет цифровой интерфейс и подключается к микроконтроллеру. Появляется дополнительная задача программной поддержки модулей. Но и тут действует тот же принцип строительства из кубиков – существует большое количество готовых библиотек. В чем сильно помогла платформа «Arduino». Ее многие ругают, но совершенно напрасно. Она резко снизила планку вхождения в электронику и программирование, приобщив к этому занятию множество людей. А с претензиями по поводу надежности можно поспорить. Схемы и платы там вполне обычные, сделаны хорошо. А программное обеспечение – это еще вопрос, что надежнее, самодельная программа, написанная и протестированная одним человеком, или библиотека, которой пользуются тысячи людей, каждый из которых жадно ищет ошибку, чтобы первому о ней объявить. Сам я эту платформу не использую, но лишь потому, что вошел в мир электроники и микроконтроллеров намного раньше, чем она появилась.
Конечно, не вся электроника выглядит именно так, иногда приходится копаться и в мелочах. Но это в тех случаях, когда речь идет о чем-то особенном, для чего еще не сделан свой «кубик».
Даже собирая систему из кубиков, не всё так просто и гладко. Хоть задача сводится в основном к организации питания кубиков и согласования их между собой, тут тоже хватает подводных камней. В данном случае требуется соединить микроконтроллер с дисплеем и датчиком, а также запитать всё это.
Выбранный OLED-дисплей построен на базе контроллера SSD1306. Кристалл этой микросхемы имеет огромное количество выводов (целых 281) и расположен на стекле дисплея. Основная часть выводов соединена с матрицей светодиодов. У контроллера 128 выводов предназначено для управления столбцами, и 64 вывода для управления строками (из которых тут задействована только половина, так как разрешение дисплея 128 х 32 точек).
Внутри контроллера имеется видеопамять, каждой бит которой соответствует точке на экране. Чтобы зажечь точку, надо записать единичку в нужный бит по нужному адресу. Общий объем видеопамяти – 1024 байта (8192 бит).
Кроме видеопамяти внутри контроллера имеются регистры конфигурации. Они позволяют управлять его работой. Чтобы дисплей заработал, после включения питания надо провести инициализацию – записать в нужные регистры нужные коды.
Контроллер поддерживает 5 видов последовательных и параллельных интерфейсов, мой вариант дисплея имеет последовательный интерфейс SPI. Существует еще вариант с управлением по шине I2C. Вариант с SPI позволяет быстрее передавать данные, но требует для подключение большего количества проводов (и выводов микроконтроллера). Для данного проекта скорость обновления экрана не особо важна, можно было применить любой вариант. Выбрал тот, который был под рукой.
Когда контроллер использует последовательный интерфейс, то возможна только запись информации в видеопамять, а чтение из нее невозможно. Это очень плохо, но об этом ниже.
На плате дисплея расположена вся необходимая «обвязка» контроллера SSD1306. Это блокировочные конденсаторы, «летающие» конденсаторы для встроенного умножителя напряжения, опорный резистор для задания тока через светодиоды пикселей. Принципиальная схема нашлась на страничке продавца.
Контроллер SSD1306 питается напряжением 3.3 В, для этого на плате установлен отдельный стабилизатор XC6206P-33 (маркировка 662K). На контакт VCC разъема платы можно подавать 5 В. Но сигналы цифрового интерфейса идут напрямую на контроллер, соответственно, имеют логические уровни 3.3 В.
Поскольку здесь возможна только запись данных, то все логические сигналы являются входными. Иногда логические микросхемы могут иметь логические входы, «толерантные» к напряжению, превышающему напряжение питания самой микросхемы. Примером могут служить некоторые входы микроконтроллеров STM32 или входы логики серии 74LVC. Для SSD1306 это не так, входы имеют обычные защитные диоды, подключенные к питанию. Если на логический вход подать сигнал с уровнем 5 В, то микросхема начинает питаться от этого сигнала через защитный диод. На выводе питания появляется напряжение, которое ниже входного примерно на 0.65 В, что является типичным прямым падением на кремниевом диоде. Поэтому подавать на дисплей логические сигналы с уровнями 5 В нельзя. Как тогда быть в системах с напряжением питания 5 В? Можно применить резисторные делители. Но надо учитывать, что они могут ограничить максимальную скорость передачи данных из-за паразитных емкостей. Для устройств с жесткими требованиями к потребляемому току делители тоже могут не подойти – при высоком логическом уровне они постоянно потребляют ток. Еще один вариант – использовать выходы с открытым стоком. Но в микроконтроллерах AVR нет возможности реализовать выходы с открытым стоком для аппаратного SPI. Самое надежное решение – применить преобразователи уровней на МОП-транзисторах или в виде интегральной микросхемы.
А что же с питанием датчика TOF050C? Микросхема датчика питается напряжением 2.8 В, для чего на плате модуля установлен стабилизатор напряжения. В результате модуль можно питать напряжением 5 В или 3.3 В, этого будет достаточно для работы LDO-стабилизатора на 2.8 В. На плате модуля есть и другая «обвязка», принципиальная схема нашлась на страничке продавца.
Модуль имеет интерфейс I2C, линии SDA и SCL со стороны микросхемы датчика подтянуты резисторами к питанию 2.8 В. Затем эти линии проходят через преобразователи уровня, выполненные на сборке полевых транзисторов 2N7002DW (маркировка K72), и только потом поступают на разъем модуля. Со стороны разъема они подтянуты резисторами к входному питанию. Таким образом, уровень логической единицы этих сигналов будет равен напряжению питания модуля и может быть как 3.3 В, так и 5 В.
Кроме сигналов SDA и SCL микросхема датчика имеет еще два логических сигнала: INT и SHUT. Они поступают на выводы модуля прямо с выводов микросхемы и преобразователей уровней не имеют. Для этих сигналов уровень логической единицы равен напряжению питания микросхемы, т.е. 2.8 В. На плате модуля они подтянуты резисторами к этому напряжению. Сигнал INT формирует микросхема при окончании цикла измерения. Сигнал SHUT по умолчанию работает как вход сброса. Уровень сигнала INT (2.8 В) с трудом вписывается в допустимый диапазон для логической единицы на входе микроконтроллера с напряжением питания 5 В. Поэтому здесь требуется преобразователь уровня. Входом сброса, в принципе, можно управлять с помощью выхода с открытым стоком, подтягивающий резистор уже есть на плате модуля.
Как видим, при питании микроконтроллера напряжением 5 В возникает масса проблем. Это заставило пересмотреть выбор напряжения питания. У дисплея в сумме 5 сигналов (SCK, SDA, RES, DC, CS), это требует 10 резисторов делителей, что довольно громоздко. Еще нужен преобразователь уровня для сигнала INT датчика расстояния. От всего этого можно отказаться, если перевести питание микроконтроллера на 3.3 В. Правда, при этом потребуется небольшая переделка дисплея: нужно выпаять микросхему стабилизатора 3.3 В и установить вместо нее перемычку. Это несложно, но «из коробки» использовать модули, как ни странно, не получается.
Первым делом решил разобраться с дисплеем. В Интернете можно найти библиотеки для работы с ним. Если бы мне нужно было побыстрее сделать проект, взял бы все готовое. Но это неинтересно, хочется написать код самостоятельно, лишь иногда подсматривая в чужие исходники. В готовых библиотеках всегда что-то не так, как хотелось бы, да и при использовании готового сложно получить представление о всех возможностях железа.
Самой таинственной операцией является процесс инициализации дисплея. Он выглядит как какое-то заклинание – по определенным адресам записываются определенные коды. Разобраться в этих кодах не так просто. Казалось бы, достаточно прочитать datasheet на контроллер дисплея. Но там не будет конкретики, касающейся именно этого дисплея. Потому что контроллер универсальный, и он может быть использован по-разному. Существуют datasheet на дисплеи с этим котроллером (например, вот), но не факт, что они в полной мере соответствуют имеющемуся дисплею от непонятного производителя. Самое смешное, что даже в datasheet нет толкования отдельных загружаемых в регистры значений – всё те же магические числа, взявшиеся неизвестно откуда.
В принципе, можно просто скопировать значения с одного из документов или готовой библиотеки, обычно разночтений не случается. Есть только несколько регистров, значения в которых могут отличаться от рекомендованных и на которые надо обратить внимание.
Во-первых, код инициализации будет зависеть от размеров дисплея. Обычно он отличается кодом в двух регистрах:
Set Multiplex Ratio (A8h) = 1Fh для 128 х 32, 3Fh для 128 х 64
Set COM Pins Hardware Configuration (DAh) = 02h для 128 х 32, 12h для 128 х 64
Механически плата дисплея не является симметричной. При использовании в конкретном устройстве, ее удобней располагать вполне определенным образом. Например, в моем случае выводы платы должны быть снизу. Здесь имеется полная свобода, так как есть регистры, позволяющие зеркалить изображение по горизонтали и вертикали:
Set Segment Re-map (A0h/A1h) – зеркалит/не реркалит по горизонтали
Set COM Output Scan Direction (C0h/C8h) – зеркалит/не зеркалит по вертикали
Еще можно менять значение контраста изображения, хотя чаще всего обходятся значением по умолчанию.
Есть два регистра, значения в которых зависят от выбранного способа питания OLED-матрицы: внешнее, или с использованием встроенного преобразователя. В данном модуле дисплея используется встроенный преобразователь.
Set Pre-charge Period (D9h) = 22h – внешнее питание, F1h – внутренний преобразователь
Charge Pump Setting (8Dh) = 10h – внешнее питание, 14h – внутренний преобразователь
Встречал в Интернете обсуждение минимизации помех индикатора с помощью регистра Set Pre-charge Period. Но пришли к выводу, что на уровень помех он не влияет. По моим наблюдениям – тоже. Надо отметить, что потребляемый OLED-дисплеем ток носит импульсный характер и зависит от выводимой картинки. Помех получается больше, чем от LCD-дисплеев, в некоторых применениях это может быть критично. Максимальный потребляемый ток этого дисплея составил 24 мА.
Самый загадочный регистр – это Set VCOMH Deselect Level (DBh). Его значения могут быть 00h, 10h, 20h, 30h, 40h, 50h, 60h, 70h. Он управляет напряжением V_COMH, которое выведено наружу (на плате модуля установлен блокировочный конденсатор), и которое можно измерить. В datasheet приведены 3 варианта кодов, но в библиотеках обычно туда загружают другой код (40h). Попробовал менять это значение – при коде 40h напряжение V_COMH максимально, дальнейшее увеличение кода ни на что не влияет.
В документе AN001 «OLED Driver Basic Register Setup» от фирмы Osram есть интересная табличка, где описаны симптомы неправильного программирования регистров контроллера OLED. Про напряжение V_COMH сказано, что при слишком низком могут быть артефакты взаимного влияния пикселей (cross-talk), а при слишком высоком может пострадать надежность дисплея.
Когда дисплей подключен и инициализирован, на него можно выводить желаемую информацию. Для этого я написал небольшой набор функций и адаптировал несколько шрифтов, которые ранее использовал для LCD. Дисплей оказался настолько маленьким, что для отладки функций вывода пришлось использовать микроскоп. Чаще всего возникают «краевые» ошибки, когда не хватает одного пикселя или появляется один лишний. Рассмотреть отдельный пиксель здесь довольно затруднительно.
При написании функций вывода на дисплей всплыла очень неприятная особенность контроллера. Дело в том, что при использовании последовательного интерфейса контроллер не позволяет читать данные из видеопамяти. Поэтому невозможно делать обновление изображения по принципу «чтение-модификация-запись». Контроллер поддерживает разные режимы адресации видеопамяти, которые можно задавать при инициализации дисплея. Но всегда адресация по вертикали делается с точностью до байта (здесь это называется Page). Если выводим что-то на дисплей, что по высоте занимает меньше байта, то перезаписывается весь байт. Например, если выводим строчку текста, которая затрагивает по вертикали только часть байта, оставшуюся часть нельзя использовать для вывода следующей строчки – будет стерта нижняя часть предыдущей. Приходится распределять экран таким образом, чтобы отдельные объекты размещались в отдельных байтах. Это накладывает существенные ограничения на дизайн интерфейса.
Конечно, такую проблему легко решить – в памяти микроконтроллера надо выделить буфер, равный по размеру видеопамяти. Сначала рисовать там, а потом копировать буфер в память дисплея (весь, или только изменившиеся байты). Но для младших микроконтроллеров это не всегда возможно из-за недостатка ОЗУ. Для ATmega88 и дисплея 128 х 32 буфер использовать можно, но уже для дисплея 128 х 64 это станет невозможным, так как буфер займет всё ОЗУ микроконтроллера.
Обидно, что данную проблему можно было очень легко обойти на этапе проектирования ASIC контроллера дисплея. Достаточно было для адресации по вертикали использовать не байты (Page), а строки. Т.е. границы блока, подлежащего обновлению, задавать с точностью до пикселя. Передаваться будут целые байты, как обычно, но те биты, которые лежат за границей блока, будут маскироваться и не будут записываться в видеопамять. В итоге видеопамять за пределами блока никогда не будет испорчена, даже если границы блока проходят внутри байта. Но, увы, здесь этого нет.
Для данного проекта, когда надо выводить фактически только одну строку, такой изъян адресации помешал не сильно. Но если потребуется выводить что-то более сложное, надо либо брать процессор с ОЗУ побольше, либо придумывать какие-то хитрости с обновлением дисплея.
В целом OLED-дисплей понравился, он дает контрастную картинку с очень хорошими углами обзора. Дисплей с диагональю побольше выглядит еще лучше, надо будет в будущем сделать на нем какой-нибудь проект. Единственный вопрос – это срок службы таких дисплеев. Но и тут всё не так плохо, если судить по имеющимся тестам. Да и не все устройства должны работать круглосуточно.
Подключение датчика TOF050C при питании процессора 3.3 В не вызывает проблем. Логический уровень выхода INT согласуется непосредственно. Вход SHUT тоже можно подключить к процессору напрямую – превышение 3.3 В над 2.8 В недостаточно для открывания защитных диодов. Но я решил на всякий случай использовать выход с открытым стоком – так правильней.
Инициализация микросхемы VL6180X – это вообще сущий ад. Ради единичного и не слишком важного проекта изучать 87-страничный datasheet не совсем уместно. Кроме datasheet, есть еще User manual UM1983 «VL6180X proximity, gesture and ambient light sensing (ALS) module », DT0035, DT0037 и другие документы. А еще есть Application note AN4545 «VL6180X basic ranging application note» где приведена готовая таблица магических заклинаний, которые надо по I2C передать внутрь микросхемы, чтобы она ожила. К счастью, магия сработала, подробно разбираться с вопросом не пришлось. Это ведь не OLED-дисплей, который может быть полезен и для других проектов. Датчик расстояния вряд ли придется еще когда-либо использовать, глубокие знания тут скорее окажутся бесполезными. Как бы то ни было, макет с датчиком и дисплеем ожил и начал показывать расстояние.
Некоторые странности при работе датчика все-таки были обнаружены. При отладке питал конструкцию от лабораторного БП. Когда ее подключал к включенному заранее БП, все работало нормально. Но когда сначала подключал, а потом включал БП, то из датчика постоянно стал считываться код FFh. Чтобы разобраться, в чем дело, считал значение регистра STATUS. При ошибке считался код 11h (17), что означает ошибку «VCSEL Continuity Test». В норме STATUS читается как 03h. Вероятно, из-за медленного нарастания напряжения питания перестал срабатывать внутренний сброс микросхемы VL6180X. Пришлось задействовать сигнал SHUT, который по умолчанию выполняет функцию сброса микросхемы. Чего в начале я делать не хотел, думал вообще обойтись подключением только двух сигналов – SDA и SCL.
Шина I2C на скорости 400 кГц нормально не заработала, при чтении возникали ошибки. Но на скорости 200 кГц все работало нормально, так и оставил.
При переходе из однократного режима в циклический изредка были зависания датчика, тогда показания замирали. Похоже, по какой-то причине переставал приходить сигнал прерывания. Для защиты от такой ситуации добавил таймер на 100 мс: если прерывание за это время не поступило, вызывается инициализация модуля. Больше зависаний не видел.
Для калибровки показаний датчика служит значение Offset. Процедура калибровки описана в datasheet. Заводское значение Offset записано в энергонезависимой памяти (NVM) и считывается после включения питания. Если я делаю свою калибровку, то, по идее, я могу перезаписать значение в NVM своим значением. Можно ли это сделать, и как – я так и не понял. Плюнул и сохраняю Offset в EEPROM микроконтроллера.
После устранения найденных шероховатостей, можно рисовать окончательную принципиальную схему. У меня она получилась такой:
Питание устройства задумывалось от внешнего БП через разъем. Можно было, конечно, поставить аккумулятор, но мне автономность не нужна. Показания дальномера планировалось не только выводить на дисплей, но и считывать на компьютер через разъем USB. А раз так, то желательно предусмотреть питание и от него. На моей схеме питание от двух источников суммируется через сдвоенный диод VD1. При питании от USB диод шунтируется транзистором VT1 для уменьшения падения напряжения. Эта мера не сильно нужна при питании 3.3 В, для стабилизатора хватит входного напряжения и с учетом падения на диоде. Но данное решение осталось от первоначальной задумки питать процессор напряжением 5 В, решил транзистор оставить.
Теперь надо выбрать корпус и разработать конструктив. В качестве корпуса взял давно купленный на Aliexpress алюминиевый профиль. Плата задвигается в него на салазках, никакого крепления не требуется. Размеры платы получились 57 х 40.5 мм. Плату изготовил с помощью ЛУТ. Плата получилась почти односторонней, вторая сторона залита земляным полигоном, и на ней есть лишь две дорожки питания и одна дорожка для подключения кнопки.
Датчик крепится к передней панели винтами и подключается к плате через разъем. В плату датчика впаяны прямые штырьки PLS. Ответная часть – разъем PBS, который размещается в вырезе платы и припаивается к площадкам на SMD-манер. На фотографии платы в районе этого разъема видны перемычки. Дело в том, что первоначально вырез в плате не планировался, а разъем должен был лежать на поверхности платы. При этом датчик должен был установлен немного выше середины передней панели. Но чувство прекрасного взяло верх, датчик был врезан точно в центр передней панели, а разъем пришлось опустить, сделав вырез. При этом дорожки, которые проходили снизу платы на месте выреза, пришлось восстановить перемычками. Но это внутри, а снаружи все красиво и симметрично.
На задней панели расположен разъем питания, разъем USB и одна кнопка. Для кнопки придумал функцию – переключение абсолютных и относительных измерений. При включении относительных на экране загорается надпись «REL».
Дисплей вставляется в разъем сверху, дополнительно он опирается на две пластиковые стойки с резьбой М2. При разработке платы надо учитывать тот факт, что физический центр активной области дисплея не совпадает с центром платы модуля.
Собранная плата сразу заработала, ведь прошивка была заранее отлажена на макете. Датчик нормально показывает расстояния до 170 – 180 мм, хоть в datasheet гарантируют только до 100 мм. Расстояние представлено однобайтным числом, т.е. может быть от 0 до 255 мм с дискретностью 1 мм. В документе User manual UM1876 «Getting started with VL6180X proximity, gesture, ambient light sensor software expansion for STM32Cube» описана возможность увеличения шкалы расстояний датчика ценой уменьшения разрешающей способности, чего нет в datasheet. Можно включить масштабирование шкалы в заданное число раз: 1, 2 или 3. Но за ненадобностью эту возможность я не проверял.
Для компьютера написал простейшее приложение, которое позволяет выводить показания датчика, а также проводить его калибровку. Калибровка сохраняется в EEPROM микроконтроллера и используется в дальнейшей автономной работе.
Откалибровал датчик по методике, изложенной в datasheet. Там требуется на расстоянии 50 мм расположить поверхность с коэффициентом отражения 88%. На практике коэффициент отражения поверхности влияет слабо, это требование можно не соблюдать. Если показания находятся в пределах ±3 мм, то считается, что калибровка не требуется. В других случаях надо обнулить Offset, провести 10 измерений расстояния, найти среднее значение, и по нему вычислить новое значение Offset.
Осталось вырезать окно для индикатора в профиле и изготовить стекло. Но сначала надо это стекло выбрать. Цвет свечения индикатора – холодный белый, сильно отдающий синевой. Хочется иметь более приятный цвет свечения, чего можно добиться с помощью светофильтра. Больше всего понравилось красное оргстекло, оно дает янтарный цвет свечения, который называется красивым словом Amber. Но это стекло слишком прозрачное, пришлось взять более темное стекло.
Вот так выглядит устройство в сборе:
Что можно сказать в качестве вывода? Модуль дальномера TOF050C работает, и работает неплохо. Но какого-то практического применения для него я не вижу. Как уже было сказано выше, это устройство делалось просто как источник коротких световых импульсов для проверки фотоприемников на работе. Измерение расстояния – это всего лишь приятный бонус.
Лично для меня в этом проекте гораздо интереснее OLED-дисплей. Он мне понравился, надо в будущем применить подобный в каком-нибудь другом проекте. Для этого куплены OLED-модули разных цветов и размеров.
Надо сказать, что проектировать интерфейс на графическом дисплее крайне трудоемко и неудобно. Если делать это сразу на микроконтроллере, то требуется большое количество перепрошивок при отладке, чтобы увидеть, как будет смотреться тот или иной вариант экрана. Для упрощения разработки надо на компьютере написать эмулятор такого дисплея, чтобы с комфортом разрабатывать интерфейс, а потом просто перенести весть текст на Си, вместе с массивами картинок и шрифтами в микроконтроллер. Но это тоже кусок работы, требующий времени. На что именно надо в первую очередь тратить свое время – это тоже вопрос, и на его решение тоже уходит время.
Самые обсуждаемые обзоры
+67 |
3125
131
|
+49 |
3368
64
|
+28 |
2308
41
|
+32 |
2533
30
|
+52 |
1947
37
|
Как забавно. Как раз заказал себе такой датчик (и ещё VL53L0X за компанию) буквально пару дней назад, а тут муська уже всё об этом знает. Я на них вышел через VCNL4200, который не нашёл по доступной мне цене в варианте с платой.
Если кто знает похожие датчики с сенсором окружающего освещения и измерения расстояния до 2 метров по i2c, то буду признателен.
Кстати, по поводу «проектировать интерфейс на графическом дисплее крайне трудоемко и неудобно», то есть LVGL. Но, справедливости ради, там и МК нужен потолще. Зато можно на PC смотреть результат.
Не оставляет вопрос, а зачем в датчик расстояния встроили датчик освещенности? Какая связь?
По поводу LVGL — это что-то слишком сложное. Моя врожденная особенность — работать с самыми простыми микроконтроллерами. Пытался работать с STM32, но за 10 лет так и не смог к ним привыкнуть — не помещаются в мозг.
У меня с проектом так получилось, что мне для реализации надо как раз оба датчика и было бы приятно обойтись одним модулем. Но я уже сдался и буду запихивать два модуля. Недавно сделал заказ и жду по почте.
LVGL для начала мне показалась немного громоздкой, но потом распробовал. Но я вообще халявщик и мне в этом плане повезло — у меня ESP32, RP2040, Cortex M7.
Вот и сделали такой комбайн под них. Модули для диайвай лишь побочное следствие дешевизны массового продукта.
Была бы возможность упихивать в тот же корпус mems-динамик — может быть впихнули бы и его.
2 метра. I2c.
Подключается за 5 минут без бубнов.
В еспхоум две строчки описание. Внутрь лезть нет никакой необходимости.
Разве что лоу левел нужно, ассемблер там, место там сэкономить… но это уже узкая специализация.
да и зачем оно нужно, если применяешь по назначению и именно этот вариант задокументирован.
более того, вся внутренняя кухня регистров и всего прочего скорее всего изначально не должна торчать наружу и может произвольным образом меняться в следующих ревизиях микросхем (или в зависимости от производителя).
а вот интерфейс общий, им и надо пользоваться.
Тут ключевое — хотеть то, что заведомо поддерживается нижележащим уровнем, а если не выходит — тупо менять этот самый уровень, а не пытаться выжать всё. И смотреть на стоимость не в тиках процессора и байтах памяти, а в долларах и часах разработки.
По моему мнению — всё равно все там будем, сложность-то растёт.
Потому что я сейчас как раз захожу в разработку с позиции джуна на пару с ИИ.
И этот ИИ для меня пока что лучший ментор
ИИ как ментор — э… не знаю, может быть и работает. Но вообще я не очень представляю, как это. Задача ментора — объяснить, почему выбрана такая-то архитектура кода, как ещё можно сделать и тому подобное. Неужто уже и это умудрились на ИИ перетащить?
На уровне джуна он вроде норм, а на уровне мидла и выше начинает проседать. Ну это пока. И у ИИ есть правила конфиденциальности — тот же copilot используют многие и норм.
Второе насколько он еще вырастет.
Потому что даже сейчас — я бэк, и на данном уровне ИИ позволяет мне писать фронт к моему бэку и фронт даже худо-бедно работает и я даже чуть понимаю что к чему.
То есть может на мобилке он работает криво, но на компе нормально.
При этом он будет развиваться.
1. Расстояние.
2. Ээээээ да больше нафиг ничего не нужно
В используете аттини с 128 байтами памяти? Нет?
Теперь вопрос. Зачем апи ассемблер коды и прочая фигня если оно за минимальное время показывает вам расстояние?
Зы. Если что я старпер и писал на все ассемблерах начиная с 4040 8080 ес эвм и заканчивая 586 всему свое предназначение.
Мне ардуино нравится за множество библиотек. Можно взять требуемый кусок (например, инициализации дисплея) себе в проект без необходимости детально разбираться с даташитом. Но код там, в большинстве своем, к сожалению, ужасен.
Что касается контроллеров дисплея, так сделаны многие — без оптимизации на слабые микроконтроллеры. Хотя, казалось бы, чуть-чуть еще доработать и стало бы лучше. В этом плане подключение через 8-битный интерфейс удобней (и быстрей), но требует много проводов и свободный порт МК.
Кстати, при питании 3.3 В у AVR максимальная частота ниже.
Это, прямо, оверкил. Сейчас тоже занимаюсь устройством с графическим дисплеем, и для себя пришел к выводу, что самый простой способ проектирования UI — рисование на ПК картинок в фотошопе. Можно подобрать нужные шрифты, использовать слои, графические фигуры, битмапы, и т.д., и, в результате, получается набор объектов с точными пиксельными координатами, которые уже легко перенести в код.
Вы пишете, что используете ЛУТ для двухсторонних плат. Я так понимаю, это в домашних условиях делается? А как совмещаете рисунок дорожек? И производите ли какую-либо металлизацию отверстий? Например, у вас «мама» для дисплея запаяна со стороны дорожек. Без металлизации это сделать достаточно сложно.
Картинки я, конечно, тоже рисую. Но чаще в векторном редакторе, так мне удобней. Допустим, экран, что на последнем фото, был разработан именно таким образом.
Но хочется пойти дальше — не только рисовать статические картинки, но и моделировать рисование в real-time каких-то графических объектов, навигацию в меню, вывод сообщений и прочее. Причем код можно полностью переносить на микроконтроллер. На компьютере будет только дополнительная «прослойка», заменяющая собой микросхему контроллера дисплея. Мысль написать такой эмелятор возникла давно, и я обязательно это сделаю, работы там не так много. Забавно, но на днях, когда искал информацию по OLED, на Github прочитал точно такую же мысль — человек хочет написать такой же эмулятор. Так что мое желание не такое уж безумное.
По платам — да, двухсторонние делаю сам. Печатаю обе стороны на журнальных страницах, затем на просвет совмещаю и скрепляю степлером. В получившийся конвертик вкладываю плату и утюжу. Переходные металлизирую с помощью заклепок из медного провода. Но если надо сверху впаять разъем, тогда сложнее — приходится в отверстия впаивать тоненькие проволочки. Но таких мест на платах как правило мало. Про изготовление плат (и прочего) я когда-то полдробно писал в ЖЖ, можно поискать по тегу lut или по другим тегам.
wokwi.com/
Эмулятор дуин, еспшек и стмок. Экраны вроде как тоже эмулирует(по крайней мере в примерах есть)
Если не смущает пиратский флаг, то на торрентс ру был 21 года.
Это, кстати, учит сразу писать более качественный код и проводить часть отладки непосредственно «в голове», рассматривая исходник.
Ну и юниттесты — это самый минимум, все реальные нюансы выплывают в интеграции. Ну да на МК свои проблемы, начиная как раз с того, что абстракции не догоняют сложность проектов.
Моя практика показала, что это не нужно. Если мы не делаем какую-то супер-графическую систему, где на экране много анимации, то картинка почти всегда стабильна. Значит, достаточно отрисовать несколько статических макетов — главный экран, меню, настройки и т.д. Можно пойти чуть дальше, отрисовать макеты в фигме и сделать даже небольшую навигацию между ними, но мне оказалось это тоже не нужно, т.к. макеты прекрасно позволили осуществить компоновку экранов, а большего и не нужно.
Я не освоил домашнюю технологию двухсторонних плат. С ЛУТом у меня как-то сразу не заладилось (выход годного был очень низкий), возможно, имеющийся принтер для него не подходит. В итоге, перешел на фоторезист. Для экспозиции использую фотополимерный 3д-принтер (разрешение 50 мкм/пиксель), платы получаются точными и весьма качественными, но вот хорошо совместить две стороны — та еще проблема. Поэтому пока что от двухсторонних отказался — делаю перемычками.
Ваш вариант со степлером и конвертиком — интересный, надо будет попробовать. Только с утюгом у меня тоже плохо получалось :) С ламинатором намного лучше, надо будет подумать, как заменить степлер скотчем, чтобы можно было прогонять через ламинатор.
Когда графика задается в виде картинок — то да. Но иногда для экономии памяти лучше нарисовать графический объект в real-time с помощью примитивов. Вот такие функции рисования можно полностью отлаживать на компьютере.
Да и вообще, не о чем тут спорить. Написать все это на компьютере не сложнее, чем написать библиотеку для дисплея на МК. Сделаю, пусть будет.
Очень сильно влияет тонер. Если бы у меня вдруг не оказалось фирменного картриджа для HP LJ-1200, то ЛУТ мог бы пройти стороной. То, чем обычно картриджи перезаправляют, не годится категорически (хотя, возможно, просто не везло). Когда закончился фирменный, мне заправляли порошком, ссыпанным в виде остатков из фирменных картриджей. Когда закончилось и это, случилась остановка в ЛУТ, никак не мог подобрать тонер. Но оказалось, что прекрасно подходит китайский картридж (взял Cactus). Не отличается от фирменного, но сильно отличается от перезаправленного.
Еще влияет бумага. Если делать односторонние платы, то идеально переносит рисунок термотрансферная. Но сложить из нее конвертик не получается, тонер не держится. Пришлось вернуться к страницам журнала «Stereo & Video». Вот бы найти бумагу — нечто среднее между мелованной и термотрансферной!
Я именно так и делаю. У меня атмега на 32 КБ ПЗУ и экран на 112.5 КБ, я не могу позволить себе хранить в памяти графику такого разрешения, поэтому все рисуется примитивами. И это очень удобно макетировать в графическом редакторе — я там рисую такие же примитивы, после чего снимаю их пиксельные координаты и переношу в код. Реализация и отладка UI занимает меньше времени, чем само макетирование :) Но я ни разу не дизайнер.
Кстати, по поводу отладки — самым трудоемким процессом было написать ассемблерный код вывода символа из шрифта так, чтобы он подавал новый байт в регистр SPI ровно через 18 тактов.
Сделайте, конечно, если хочется. Удовольствие от занятия любимым делом намного важнее практического смысла.
Да, пришел к точно такому же выводу! Правда, у меня и на односторонних платах бывало, что осыпался :)
Я пробовал много разной — от обычной А4, до тетрадной, газетной и даже фотобумаги для струйников. Последнюю несколько стремно совать в принтер, т.к. есть полимерные, которые от температуры плавятся и могут принтер испортить. Однажды попался мне листик такой, что была практически идеальной — печаталось всё нормально, а потом в воде за 10 минут размокала как втулка от туалетной бумаги Zewa в хорошие времена. И просто пальцем стиралась. Но потом не смог найти её — покупал в магазине аналогичную, но она уже была «по новой технологии» на каком-то полимере. А дальше попробовал фоторезист, понравилось, на нем и остановился.
Читал об этом. Но у меня китайский принтер pantum, скорее всего, он вообще плохо подходит для ЛУТ, т.к. печатает весьма тонко, для ЛУТ надо жирнее. Надо было brother покупать, вроде там честная настройка плотности в драйверах, которая влияет на напряжение. Мне кажется, у меня это лишь программная опция. Но сейчас платы делаю настолько редко, что не повод менять.
Ну или, допустим, хотим подправить шрифт. Как быстро посмотреть, что получилось? Рисовать попиксельно в графическом редакторе символы — то еще занятие.
Глянцевая фотобумага для струйников — почти идеал. Лучше всего подошла Epson, но она страшно дорогая. С более дешевыми есть проблема — глянец плохо отмывается из мелких зазоров между дорожками. И еще одна проблема — тот картридж, который использовал с бумагой для струйника, очень скоро стал плохо печататать.
Да, хочется полностью уйти от этой грязной работы. И дело шло к тому некоторое время назад.
Меня в заказе готовых плат всегда смущало время. Если я нарисовал схему и плату, то хочу получить её в руках максимально быстро, а не ждать пару недель. Но качество готовых несравнимо с домашним, это очевидно.
«Датчик способен измерять даже такое малое расстояние, как 10 мм, которое свет проходит туда-обратно за время примерно 67 пикосекунд!»
Вот точно фантастика. Интересно, какие фронты у импульса лазера?
Дисплеи реально классные в плане удобства чтения, количества выводов и потребления
На всякий случай — готовых дальномеров с кучей фий и алюм корпусом и низкой ценой полно на али.
Что касается дисплеев — да, они выглядят классно. Единственное, что меня смущает — это уровень помех. Например, для большого дисплея, что на последнем фото, на питании наблюдаю пульсации 300 мВ. Боюсь, что избавиться от помех будет очень трудно, как в случае динамической индикации на обычных LED. Есть отрицательный опыт, избавиться не удалось никак (речь идет о микровольтовых уровнях). Боюсь, чтобы не пришлось переходить на LCD, там с этим намного лучше (подсветка, естественно, не должна питаться импульсно).
По дальномеру — у меня же написано, для чего он делался. Как дальномер его никто не собирается использовать.
VCOMH отвечает за контраст, емнип, и точно также редко на что-то влияет в контексте данных экранчиков — у них для него обычно четко определенное значение и все.
А для чего вам так глубоко с этим разбираться? Возьмите код из наиболее авторитетного примера, скорее всего, там будет подходящее значение.
Если накопаете что-то инетерсное про это — поделитесь пож.
Мое предположение, что VCOMH — это вот это:
— habr.com/ru/articles/741164/
— microsin.net/adminstuff/hardware/ssd1306-oled-controller.html
Но вот это:
— полностью поддерживаю!
Ну, и, скорее всего, изначально под «экранной клавиатурой» подразумевалась клавиатура, нарисованная на экране, позволяющая вводить текст. Вот такой на маленьком экране будет очень тесно.
Вот и я не думаю, что автор изначального поста имел в виду под экранной клавиатурой то, что озвучили вы, ведь это еще потребует подключение и настройку тачскрина. Не уверен, что такие маленькие дисплеи идут с ним по умолчанию.
kdekaluga, и он ничего не говорил о том, будет ли оно стоять всю жизнь на месте.
Вам я ничего предлагать не стал бы — слишком разные понятия о правильном и прекрасном.
Поэтому, исходя из задачи устройства, все настройки, которые имеет смысл менять, должны меняться без подключения к компьютеру или телефону (подключение к компьютеру я вообще не планирую, хоть пины последовательного порта МК на всякий случай и оставил свободными).
И тут остается лишь понять, какие именно настройки вообще надо менять, а какие можно просто «захардкодить», т.к. их изменение может лишь навредить функциональности.
А если уж говорить про способ удаленного управления, то самый удобный — это WiFi и настройка через браузер. Не надо ничего физически подключать, не надо ничего устанавливать на телефон. Но это надо было планировать с самого начала, т.к. нужен другой контроллер, с которым есть свои (другие) сложности.
По поводу Wi-Fi — у меня нет ни одного устройства с ним (в компьютере его нет), поэтому себе такое управление никогда не делаю. Что касается утилиты на компьютере, я, честно говоря, не понял, что советовалось взамен. По-моему, чтобы с компьютера делать нстройки, надо иметь на компьютере какую-то программу. С GUI или через команджную строку или файл — это другой вопрос. Удобнее всего с GUI. На работе есть много фирменных приборов, всегда для настройки идет утилита под Windows. Я по-другому и не мыслю. Еще идет в комплекте DLL, через которую можно управлять приборами из Матлаб. Я тоже такие DLL к своим приборам делаю.
Тогда устройство можно будет настроить без ПО на компьютере, отправляя нужные команды вручную. Это проще в реализации, чем эмуляция хранилища с файлом настроек.
Это некий стереотип, заложившийся во времена, когда windows была, по сути, единственной альтернативой. Как и «толстые» десктопные приложения.
Сейчас происходит сдвиг на «облачность», «тонкие клиенты». Хорошо это или плохо, вопрос отдельный, который можно обсуждать бесконечно. Но факт остается фактом — для рядового пользователя гораздо проще открыть браузер и настроить устройство через смартфон, чем искать винду и ставить приложение. И еще проще, если эта настройка доступна через интернет, а не только в локальной сети. Но это уже совсем другой уровень.
Мне не доводилось касаться того мира, где кто-то настраивает какие-то приборы через смартфон или через интернет. Что я вижу вокруг — у всех компьютер, у всех Windows.
А он есть :) Удаленное управление через телеграм-бота сейчас вообще сильно популярно, т.к. позволяет управлять из любой точки мира, но не требует сервера с белым IP :)
При подключении устройство эмулирует флешку на 2 кб, допустим, на которой лежит текстовый файл с настройками. Соответственно, открываем блокноте или аналоге, правим, сохраняем обратно.
Однозначно годится не для всех случаев, зато там, где годится — не требует никакого специального софта, даже терминала, плюс заодно даёт возможность бэкапить/восстанавливать настройки. Никак не могу вспомнить, где такое встречал, а вот прошивку, реализованную таким макаром, видел не раз. В любом случае реализаций этой штуки полно, и они достаточно мелкие, чтобы даже жить в бутлоадере.
Поэтому, если уж есть подключение к USB и очень хочется сделать настройку через комп — лучше это осуществлять в терминале текстовыми командами. И SCPI вам приветливо машет ручкой. Это, кстати, не отменяет возможности написать и утилиту, которая может подавать в порт точно такие же команды. Вин-вин.
Вы можете возразить, что вам удобней иначе — несомненно. Но вы же часто потом выкладываете ваши разработки в свободный доступ, значит, надо подумать и о тех, кто их будет повторять.
Ну, а вернувшись к вопросу — моя позиция здесь такова, что если в устройстве есть настройки, которые надо менять, надо дать возможность делать это напрямую с устройства. Без компьютера, телефона или отдельного блока управления. Это, в любом случае, практичней.
Просто, чтобы понимать, о каких масштабах мы говорим — допустим, у вас есть пара числовых 16-битных параметров, пара 8-ми битных, штук 5 битовых флагов. Сколько времени займет создание самого интерфейса на ПК, передача этого через последовательный порт и код обработки на МК?
Для БП, конечно, одного энкодера мало, но двух — уже достаточно. Плюс еще кнопка вкл/выкл выхода. Но для других устройств и одного вполне. Например, паяльник Т12.
Эти датчики могут больше.
www.youtube.com/shorts/b18ghRCWawo
www.youtube.com/shorts/_ZjAZ7eieNM
www.youtube.com/shorts/mBebfzSqTqA
Ну или поискать станочные тиски похожего плана на барахолках.
Брал вроде бы тут
У них кстати цены как будто чуток попроще алика
Самые дешёвые, питание снимаю с бортовой сети вместо батареек, отлично работают. И да, по вертикальной оси перемещение передаёт тупо печатная деталь. Жёсткости вполне хватает
Тогда бы и платы ЛУТом делать не пришлось бы
Делать платы фрезеровкой по-моему хуже, чем ЛУТ. Долго, шумно, пыльно.
впрочем, WCH это не касается, т.к. его уже в pio затянули.
В целом, получается неплохо, я сейчас свой проект именно на pio делаю. Ложку дегтя добавляет только вот это, невольно задумываешься, как бы какой закладки не оказалось.
Если серьёзно — это не особо стыкуется с тем, что у них написано (а там заявлено, что это, прежде всего, универсальная тулза, которая умеет не только тулчейны ставить, но и прочие зависимости тащить, и подключается к разным IDE.
Ну, по сути, да. То есть, может фреймворк ардуино, например, выкачать, может что-то еще. Но я для avr использую «голый» компилятор, поэтому для меня основное — тулчейн.
Вплоть до того, что то, что собиралось в нём же год назад, сегодня собираться не захочет.
Лично я такой софт считаю кривым.
Но есть фанаты, как есть и такие, которые торопятся ставить любое обновление.
Работает — не трогай. Но это точно не про PlatformIO
Чисто программными методами убить контроллер? Серьезно? То есть, завтра может пройти глюк по питанию или сильная помеха, контроллер даст сбой, перейдет в невалидное состояние и убьет себя? Лично я на таком железе на данный момент делать ничего не хочу.
От этого сообщество моментально не появится, и проблемы решаться не станут.
Журнал, фотобумага, подводка от самоклейки?
Возник такой вопрос: можно ли данный датчик использовать для измерения скоростей небольших предметов на расстояниях от 0 до 2 м? Не просто измерить начальное положение и конечное и получить серднюю скорость на 2м, а именно снять массив временных меток + расстояния измереннные датчиком? Какого времени между двумя измерениями можно достичь?