В комментариях к той статье мне справедливо указали по поводу конструкции датчиков, что ось подобного устройства должна иметь твердое острие и опираться на столь же твердое основание (вспомним наручные часы «на стольких-то камнях»). Я это, конечно, знал, но тогда не смог придумать способ обеспечить легкую ось с острием достаточной твердости, поэтому, наоборот, пошел по пути минимизации трения, погрузив латунное (для флюгера) или дюралевое (для датчика скорости) острие в мягкий фторопласт (см. чертежик в указанной статье). В полном понимании, что это решение временное и недолговечное и в недалеком времени придется придумывать что-то поосновательней.
Результат прошедших двух сезонов эксплуатации показал тем не менее, что такое решение вполне годится для флюгера, который, конечно, пропилил латунной осью фторопластовое основание до металла, но ему это ничуть не повредило — минимальное трение там и не требуется, даже отчасти наоборот. Хуже было с датчиком скорости, в котором пропилился не только фторопласт в основании, но и само острие из мягкого дюраля стерлось миллиметра на два по длине. В результате прежде всего недопустимо возрос порог трогания и датчик пришлось модернизировать. Модернизации подвергся и сам анемометр, так как лазерный компакт-диск, на основе которого он был выполнен, от солнца расслоился и приобрел неопрятный внешний вид (надо же, я и не знал ранее, что компакт-диски состоят из двух слоев).
Подробнее о новом датчике я надеюсь рассказать позднее, после того, как он хоть немного побудет в эксплуатации и можно будет убедиться, что в нем сразу ничего не придется дорабатывать (то есть не ранее начала лета). А сейчас только некоторые подробности об изменениях в измерительной схеме, так как они имеют отношение к основной теме этой статьи.
Об измерительной схеме датчика
В связи со снижением порога трогания встал вопрос о значительном времени, которое занимает измерение малых частот, поступающих с датчика скорости (подробности см. в этой публикации о способах измерения малых частот). Чтобы не ограничивать порог трогания искусственно, в данном случае следовало бы измерять частоты, начиная от 1-2 герц: учитывая, что в датчике 16 отверстий по окружности (см. фото датчика в первоначальной статье), это соответствует примерно одному обороту за 8-16 секунд, что заведомо ниже любого порога трогания. То есть таймаут на ожидание прихода следующего импульса частоты должен быть не менее 1 с (см. указанную статью о способах измерения), что обессмысливает историю с энергосбережением: чтобы получить приемлемое время обновления и вместе с тем успевать осреднять данные во избежание дребезга показаний на дисплее, мы вынуждены будить контроллер каждые две секунды. И если половину из них будет занимать время ожидания импульсов, то никакого энергосбережения не получится — учитывая еще, что все это время работает излучающий светодиод датчика, потребляя около 20 мА.
Можно нагородить сложное управление пробуждением контроллера от двух источников: нормально от внешнего прерывания с датчика скорости (то есть во время ожидания импульсов с датчика контроллер также уходит в режим энергосбережения), а при отсутствии ветра — принудительное от Watchdog. Это имело бы смысл только при изменении принципа съема показаний датчика скорости с оптического на менее энергозатратные схемы (которые еще надо поискать — датчик Холла, например, потребляет 5-10 мА, что непринципиально меньше оптической конструкции). Но все упростилось из-за того, что датчик у меня теперь питается от солнечной батареи, что позволило просто отказаться от режима энергобережения.
Для тактирования съема показаний я не стал возиться с таймерами или отсчитывать ардуиновские millis(), а просто поставил примитивный внешний генератор частоты с периодом около 1,5 секунд на таймере 555:
Как мы помним, в схеме датчика используется «голый» контроллер Atmega328 в DIP-корпусе, запрограммированный через Uno и установленный на панельку, собственно Arduino используется только для макетирования. Выход генератора был заведен на вывод прерывания INT0, вывод 4 микросхемы (вывод D2 платы Uno). Прерывание по положительному перепаду (RISING) устанавливает некий флаг, по которому в основном цикле и происходит снятие очередных показаний. Частота с датчика при этом измеряется также методом прерывания (выход датчика заведен на вход прерывания INT1, вывод 4 (D3), см. последний метод в той самой статье), потому максимальное общее время ожидания вдвое превышает период измеряемой частоты. При таймауте в 1 сек, таким образом, минимальная измеряемая частота равна 2 Гц (один оборот анемометра за 8 сек). В каждом четвертом цикле происходит осреднение и готовые данные посылаются в основной модуль, то есть обновление показаний происходит примерно раз в 6 секунд.
Всю эту историю с обновленным датчиком придется калибровать и периодически проверять, не возросло ли трение, сравнивания показания с ручным анемометром. Потому очень неудобно, когда показания отображаются в одном месте (в доме), а внешний датчик установлен совсем в другом — на садовой беседке. Встал вопрос об установке контрольного ЖК-дисплея в корпус датчика. Так как красот тут не требуется, то информационные требования к нему минимальны: однострочного 10-символьного дисплея вполне достаточно. Зато геометрические требования довольно жесткие: дисплей должен умещаться в существующий корпус по ширине, которая составляет 70 мм. Надо сказать, что в силу моей органической нелюбви к ЖК-дисплеям (тусклые, малоконтрастные, с мелкими буковками, отвратительного качества подсветкой, и к тому же много потребляют, о чем далее), я почти не в курсе имеющегося в рознице ассортимента. И потому сразу выяснилось, что нужных мне дисплеев надо еще очень сильно поискать в продаже: стандартный ЖК-дисплей 16х2, кои в магазинах доминируют, имеет плату длиной 80 мм и в мой датчик не умещаются, а все остальные типы еще больших габаритов, причем независимо от фирмы. В природе, конечно, существуют и разновидности меньших размеров, но то в природе, а не в отечественной рознице.
Решение: о, МЭЛТ!
В конце концов я обнаружил сразу два МЭЛТ’а, которые чудесно соответствуют моей задаче. Первый из них — однострочный 10-символьный MT-10S1 с контроллером, который, как уверяют производители, «аналогичен HD44780 фирмы HITACHI и KS0066 фирмы SAMSUNG». У него достаточно крупные знаки: более 8 мм в высоту, что вообще-то характерно для китайских дисплеев куда больших размеров. Ширина платы 66 мм, габариты выступающего экрана (внешние) — 62х19,5. Потребление меня в данном случае волнует не очень (ибо внешний датчик питается от солнечной батареи заведомо большей мощности, чем необходимо), но по привычке взглянув на строку в даташите, я выяснил, что оно тоже меньше обычного — 0,7 мА (все обычные ЖК-дисплеи на аналогах HD44780 потребляют от 1,2 мА и выше). До кучи есть еще подсветка, как обычно у всех таких типов — довольно убогая и при этом потребляющая массу энергии.
Второй дисплей MT-10T7 еще восхитительнее: ровно в тех же габаритах уместилось 10 семисегментных цифр высотой аж 13 мм. Некоторые подозрения вызвал нестандартный, и, судя по всему, самопальный интерфейс (для которого в даташите даже приведен пример программирования в словесном псевдокоде). Дисплей не содержит настоящего контроллера: там набор статических триггеров-защелок, управляющихся комбинационной логикой. Но благодаря такой простоте вся эта конструкция потребляет всего 30 мкА, то есть она реально годится для приборов, которые круглосуточно работают на батарейном питании (потребление 1,4 мА у обычных дисплеев и даже 0,7 мА у МТ-10S1 сильно превышают допустимые для такого применения величины — посчитайте сами, сколько проработает такой дисплей, даже без учета остальных узлов прибора, например, от батареек ААА емкостью порядка 1500 мА-ч).
Короче, дайте два!
MT-10T7
Попытка самостоятельно воспроизвести алгоритм для MT-10T7, описанный в даташите (и на Arduino, и на чистом ассемблере), к успеху не привела. Что было сделано не так, я разбираться не стал, потому что наткнулся на вот эту публикацию, где автор (eshkinkot) привел весьма грамотно написанный и обстоятельно оформленный пример обращения с MT-10T7, после чего все сразу заработало. Если кому интересно, то вот тут лежит модифицированный пример eshkinkot’а, дополненный всеми допустимыми на семигментных индикаторах осмысленными символами, в том числе буквами, не совпадающими с цифрами:
На этих картинках контраст экрана немного подрихтован установкой делителя по выводу Vo — 18 кОм (к питанию): 10 кОм (к земле), хотя и без него контраст «по умолчанию» вполне приемлемый.
Я затем дописал к указанному примеру функцию, которая воспроизводит на дисплее произвольное число в пределах трех-четырех десятичных разрядов — положительное или отрицательное, целое или с плавающей точкой, то есть общее число знаков может достигать пяти: «-12,7», например. Так как точка в семисегментном коде не занимает отдельного знакоместа, то максимальное число выводимых разрядов равно 4. Входными параметрами для этой функции служат: а) массив (char buf[5]), содержащий ACSII-представление числа, б) реальное количество символов в нем (ii от 1 до 5) и в) позиция (pos от 0 до 9), куда помещать первый (слева) знак числа (используемые по ходу дела функции и обозначения см. в означенной публикации eshkinkot’а или в примере по ссылке):
void writeASCIIdig_serial(char buf[5], byte ii, byte pos)
//отображает на дисплее число из буфера
{
boolean dot; //признак присутствия точки в массиве
//выравнивание числа вправо, начиная от pos:
pos=pos+(4-ii);
//если есть точка, то на символ меньше:
for (byte i=0; i <= ii; i++) if (buf[i]=='.') pos++;
//выводим поразрядно:
for (byte i=0; i <= ii; i++){
//если след. символ точка, то выводим с точкой:
if (buf[i+1]=='.') dot=true; else dot=false;
switch (buf[i]) { //decoder ASCII -> 7-сегментный код
case '0':
writeSymbol(pos, DIGIT_ZERO, dot);
break;
case '1':
writeSymbol(pos, DIGIT_ONE, dot);
break;
case '2':
writeSymbol(pos, DIGIT_TWO, dot);
break;
case '3':
writeSymbol(pos, DIGIT_THREE, dot);
break;
case '4':
writeSymbol(pos, DIGIT_FOUR, dot);
break;
case '5':
writeSymbol(pos, DIGIT_FIVE, dot);
break;
case '6':
writeSymbol(pos, DIGIT_SIX, dot);
break;
case '7':
writeSymbol(pos, DIGIT_SEVEN, dot);
break;
case '8':
writeSymbol(pos, DIGIT_EIGHT, dot);
break;
case '9':
writeSymbol(pos, DIGIT_NINE, dot);
break;
case '-':
writeSymbol(pos, SYMBOL_MINUS, dot);
break;
} //end decoder
if (buf[i]!='.') pos++; //если не точка, то +1 позиция
}//end for i
}
Модуль MT-10T7 для контрольного вывода числовых значений удобнее, чем обычные строчно-матричные дисплеи: у него цифры большого размера, а десятичная точка не занимает отдельного знакоместа и, следовательно, в тех же позициях можно уместить на один знак больше. Но для моих целей удобнее, если есть возможность вывода букв (иначе направление придется выводить в компасных градусах, что несколько непривычно). Потому я для данного случая обратил свой взор на идентичный по размерам однострочный матричный MT-10S1, который, несмотря на ряд недостатков, и перекочевал в законченную конструкцию. Заодно у него уже есть подсветка, которой лишен MT-10T7 (для этого нужно было сразу покупать MT-10T8), и я решил, что в данном случае ее наличие не помешает.
MT-10S1
У дисплея MT-10S1 буковки-цифирки в полтора раза поменьше, но тоже вполне достойного размера. Кроме того у него экран экономно упакован в общие габариты: 10-значных импортных аналогов нет, но в винстаровском WH1601L (где символы даже чуть меньше по высоте) от общей длины платы и экрана на один знак приходится на целый миллиметр больше. Ну и уменьшенное почти вдвое потребление контроллера (в сравнении с тем же WH1601L). Собственно, на этом преимущества заканчиваются, дальше начинаются «особенности».
Модуль хвастается тем, что, как уже говорилось, имеет контроллер, совместимый с HD44780 фирмы HITACHI. То есть он без лишних напрягов должен работать с любимой Liquid Crystal. Мало того, «умолчательная» страница кодировки совпадает с англо-кириллической страницей HD44780 и его многочисленных аналогов, то есть MT-10S1 без проблем должен работать с Liquid Crystal Rus, никаких кодовых страниц для этого переключать не требуется. И он действительно все это делает, но с нюансами.
Первый нюанс — в однострочном варианте разработчики, видимо, экономят на регистрах, и в памяти на один регистр приходится только 8 символов строки (адреса 00h – 07h), а оставшиеся два символа относятся уже к другому регистру (40h-41h). То есть дисплей де-факто двухстрочный, просто обе строки физически расположены в одну линию. При ближайшем рассмотрении оказалось, что то же самое характерно и для WH1601 (только там второй регистр занимает полные восемь разрядов). Почему так неудобно сделано — совершено неясно, в обычных дисплеях 16х2 регистры шестнадцатибитные, и едва ли такое усечение удешевляет продукт, скорее наоборот из-за необходимости производить разные версии контроллера (если они разные, в чем я вовсе не уверен). Я подумал было, что с этим связано меньшее, чем обычно, потребление MT-10S1, но такой же WH1601 потребляет 1,2-1,4 мА, то есть ничем не отличается от своих продвинутых собратьев.
Ну, казалось бы, и ладно — в Liquid Crystal Rus обнаружилась функция setDRAMModel() и соответствующая константа LCD_DRAM_WH1601. Для такого режима в библиотеке прописано очевидное преобразование адресов:
if (ac>7 && ac<0x14) command(LCD_SETDDRAMADDR | (0x40+ac-8));
Но не знаю, как это функционирует на других однострочных дисплеях, а MT-10S1 в таком режиме работать напрочь отказывается — экран остается просто пустым. Так как речь идет об адресации, то простой самописной функцией поверх библиотеки это не исправишь, а ковыряться в библиотеке и выяснять, в чем дело, я не стал — у меня и без того подправленных вариантов Liquid Crystal уже больше полудюжины, не хочется их плодить и далее.
Дисплей MT-10S1 нужно объявлять, как двухстрочный: lcd.begin(16, 2); (вместо 16 можно подставить 10 или 12, ничего не изменится, так как реальное число символов в одной строке все равно 8). Попытка инициализировать его, как однострочный (цифирка 1 во второй позиции) приведет к сбою — фон окрасится темным. А выводить многоразрядные числа можно только в пределах 8 знаков, у более длинных строк крайние символы сверх 8 просто пропадут. Поэтому 9 и 10 знаки либо фактически годятся только для вывода вспомогательных величин (единиц измерения, например), либо нужно разбивать строку-число на отдельные разряды, и при переходе за 8-й символ менять позицию курсора на первый символ второй строки.
Для страждущих вот здесь можно скачать пробный скетч для этого дисплея (подключение выводов — в тексте скетча или на схеме ниже). Кстати, контраст (о котором в заводском даташите ни слова, и вывод Vo обозначен, как NC) здесь регулируется обычным образом, но этого действительно делать не надо: в отсутствие подсветки фон кажется несколько темноватым, но при попытке его осветлить подключением делителя к выводу Vo заметно теряется контраст при включении подсветки.
Интерфейс с контроллером
После проверки того, что все работает, как надо, встал в полный рост вопрос о том, как все это стыковать с контроллером датчика. Чтобы обеспечить управление от него непосредственно, свободных выводов у контроллера датчика, конечно, не хватало, а городить городеж с контроллерами больших размеров совсем не хотелось — удобнее, когда построение системы модульное, и вывод на дисплей не мешает работе основного алгоритма, уже отлаженного ранее. Оставалось задействовать какой-либо из последовательных интерфейсов.
Здесь напрашивается I2C-решение на основе PCF8574 (или ее многочисленных аналогов), тем более, что сама по себе эта микросхема — просто навороченный сдвиговый регистр, и потому потребляет несколько десятков мкА при работе и менее 10 мкА в покое. В совокупности с MT-10T7 они образуют отличную пару для создания малопотребляющих устройств с индикацией, и у МЭЛТ даже запасен готовый вариант на такой случай: MT-10T11 с общим потреблением в 30 мкА.
А вот для MT-10S1 такого удобного решения нет — почему-то дополнением в виде аналога PCF8574 среди строчных дисплеев МЭЛТ снабжаются только версии с конфигурацией 20х4 (UPD: в комментах подсказали, что есть еще МТ-16S2H конфигурации 16х2 с таким же интерфейсом, правда, у него размеры выходят за нужные мне габариты). Готовый модуль типа, описанного в этой статье, в данном случае применять неудобно, так как вторая неприятная особенность дисплея MT-10S1 — нестандартная разводка выводов. Выводы все те же самые (HD44780 все-таки, точнее его отечественный аналог КБ1013ВГ6), но расположены совершенно в нестандартном порядке. Проверил ради интереса и импортные 16х1, и МЭЛТ’овские двухстрочные/четырехстрочные — у всех у них стандартный порядок выводов, а MT-10S1 на этом фоне почему-то выделяется. Так что придется городить самопальное решение.
В результате я банально приставил к дисплею все тот же контроллер ATmega328, программируемый по той же схеме — через UNO, а затем вставляемый в панельку на отдельной плате, снабженной только необходимыми для запуска аксессуарами: кварцем с кондерами, емкостью по питанию и RC-цепочкой по выводу Reset (см. схему датчика в первоначальной статье, где контроллер подключен по аналогичной схеме).
А два одинаковых AVR-контроллера сам бог велел стыковать по обычному Serial-интерфейсу, который все равно, кроме процесса программирования, нигде больше в этом проекте не применяется, и для использования которого уже все есть под рукой. Такое решение, кстати, по цене компонентов не отличается от решения на основе PCF8574 и вполне может конкурировать с ним по части энергосбережения в варианте с MT-10T7 — на тот случай, если под рукой не окажется упомянутого выше MT-10T11.
Итого схема модуля MT-10S1 с контроллером выглядит следующим образом (на схеме обозначение выводов ATmega328 дано в скобках после выводов платы Arduino):
В контроллере я применил режим энергосбережения (ну да, оно здесь не очень требуется, но зачем держать микросхему включенной всю дорогу без нужды?). Причем пробуждение происходит по сигналу с того же генератора меандра на микросхеме 555, что и тактирование основного контроллера, только на этот раз по падающему фронту (FALLING), чтобы немного разделить функции измерения и пересылки данных.
Прерывание по низкому уровню очень неудобное в применении, так как один раз произойдя, при наличии этого самого низкого уровня на выводе оно будет происходить снова и снова, и надо принимать специальные меры, чтобы избавляться от лишних срабатываний. Так вот, ковыряясь на форумах в поисках различных решений этой задачи, я вдруг пару раз наткнулся на примеры кода, в которых для выхода из сна явным образом используется INT0 типа RISING или FALLING. Разумеется, я отнес это на счет безграмотности авторов. Но когда вот здесь споткнулся о фразу: «Хотя можно использовать и любой другой тип прерываний (RISING, FALLING, CHANGE) — все они выведут процессор из состояния сна», то решил, назло врагам, провести живой эксперимент — благо для этого все было под рукой.
И, к моему изумлению, все отлично заработало. Режим энергосбережения — SLEEP_MODE_PWR_DOWN; в силу ненадобности здесь я не принимал меры для дополнительного снижения потребления с отключением всяких других функций, но все равно тактовый генератор заведомо отключен. И тем не менее контроллер исправно просыпается по falling edge, запрашивает данные, отображает их на дисплее и засыпает снова. Для чистоты эксперимента я извлек МК из платы UNO и вставил в свою панельку с подключенным кварцем, и все равно всё продолжало работать. Это видно по потреблению: почти 17 мА в обычном режиме и 0,9-1 мА при включенном энергосбережении (из них 0,7 мА следует отнести на счет дисплея).
Не выходя из изумленного состояния, я перечитал даташиты от Atmel, заглянул в книжку Евстифеева (с их переводом), даже просмотрел старинное Atmel’овское пособие по семейству Classic, потом затратил полдня на поиски хоть какого-то объяснения происходящего (и по-русски и по-английски) в двух известных всем поисковиках, но нигде не нашел даже намека. Разве что в Atmel’овские Application Notes не полез, потому что сомнительно, чтобы там публиковалось что-то противоречащее даташитам. Буду счастлив, если кто-нибудь знающий объяснит мне, чего я здесь недопонимаю.
Пересылка данных из контроллера датчика в контроллер дисплея через UART организована в форме диалога. Просыпаясь, каждое 4-е прерывание контроллер дисплея запрашивает данные по очереди:
. . . . .
if (flag==1) { //флаг устанавливается каждое 4-е прерывание ~6 с
Serial.print('T'); //посылаем запрос данных
while(!Serial.available()); //ждем градусов T
iit = Serial.readBytes(buft,5); // считать 5 байт максимум,
// в ii реально прочитаное количество
Serial.print('H'); //посылаем запрос данных
while(!Serial.available()); //ждем влажности
iihh=Serial.readBytes(bufhh,5); // считать 5 байт максимум,
// в ii реально прочитаное количество
Serial.print('S'); //посылаем запрос данных
while(!Serial.available()); //ждем скорости
iiss=Serial.readBytes(bufss,5); // считать 5 байт максимум,
// в ii реально прочитаное количество
Serial.print('D'); //посылаем запрос данных
while(!Serial.available()); //ждем направления
iid=Serial.readBytes(bufd,5); // считать 5 байт максимум,
// в ii реально прочитаное количество
flag=0; //сброс флага запроса
}
. . . . .
Здесь buft, bufhh, bufss и bufd — массивы (не строки!) из пяти байт, которые содержат данные о температуре, влажности, скорости и направлении в виде ASCII-разложения соответствующих чисел. Для того, чтобы не принять лишнего, в setup'e указан сокращенный таймаут на прием:
. . . . .
Serial.begin(9600);
Serial.setTimeout(10); // лимит времени 10 миллисекунд
. . . . .
Так удобнее выводить на дисплей: во-первых, вы сразу имеете и длину принятого числа, во-вторых функция Serial.print() со стороны контроллера датчика все равно посылает ASCII-строку, с установленными паузами как раз в те самые 10 мс между посылками:
. . . . .
//посылка данных на дисплей по запросу:
if (Serial.available()>0) //ждем запроса
{ char ch=Serial.read();
if (ch=='T') {
Serial.print(temperature,1);
delay(10);}
if (ch=='H') {
Serial.print(humidity,0);
delay(10);}
if (ch=='S') {
float wFrq=(3+0.8*f)/10; //из герц в м/с
if (wFrq>0.3) Serial.print(wFrq,1);
else Serial.print(0.0,1);
delay(10);}
if (ch=='D') {
// Serial.println(wind_G);
Serial.println(wind_Avr);
delay(10);
}//end ch
}//end serial
. . . . .
Расчет скорости в м/с здесь идентичен тому, который производится в основном модуле станции (порог трогания установлен наугад равным 0,3 м/с) и его придется также менять по результатам калибровки.
Если попытаться принять данные обычным Serial.read(), а затем результат приема вывести на дисплей функцией вроде lcd.print(t,1), где t — температура в градусах, равная, например, 12.7, то MT-10S1 в ответ на такую команду выведет «49.5». Догадались, или подсказать? Это первые три знака в последовательности «49 50 46 55», то есть в ASCII-разложении числа «12.7». Потому проще сразу принять массив символов и непосредственно вывести на дисплей столько знаков, сколько было послано (count — счетчик, который увеличивается на единицу каждое прерывание):
. . . .
if (count%8==0){ //каждые 8 прерываний выводим
lcd.clear();
if (buft[0]!='-') lcd.print("+");
for (byte i = 0; i < iit; i++)
lcd.print(buft[i]); //вывели температуру
lcd.setCursor(6, 0);
for (byte i = 0; i < iihh; i++)
lcd.print(bufhh[i]); //вывели влажность
lcd.setCursor(0, 1);
lcd.print("%");
}
if ((count+4)%8==0){ //еще через 4 прерывания
lcd.clear();
lcd.setCursor(0, 0);
for (byte i = 0; i < iiss; i++)
lcd.print(bufss[i]); //вывели скорость
lcd.setCursor(5, 0);
dir_dd(bufd); //выводим направление
}
. . . . .
Последняя строка нуждается в расшифровке. Дело в том, что данные о направлении посылаются в коде 0-15 (в который они все равно переводятся из кода Грея при реализации векторного осреднения). В случае семисегментного дисплея MT-10T7 они переводились в компасные градусы:
. . . . .
dd=atoi(bufd); //преобразуем в число
dd=dd*22.5; //пересчитываем в градусы
itoa(dd,bufd,10); //преобразуем обратно в строку
. . . . .
А здесь мы можем писать прямо русскими буквами, так же, как и в основном модуле метеостанции (из-за чего этот дисплей, собственно, и был выбран):
. . . . .
void dir_dd(char dd[])
{switch(atoi(dd)) {
case 0:
{lcd.print("С"); break;}
case 1:
{lcd.print("CСЗ"); break;}
case 2:
{lcd.print("CЗ"); break;}
case 3:
{lcd.print("ЗCЗ"); break;}
case 4:
{lcd.print("З"); break;}
case 5:
{lcd.print("ЗЮЗ"); break;}
case 6:
{lcd.print("ЮЗ"); break;}
case 7:
{lcd.print("ЮЮЗ"); break;}
case 8:
{lcd.print("Ю"); break;}
case 9:
{lcd.print("ЮЮВ"); break;}
case 10:
{lcd.print("ЮВ"); break;}
case 11:
{lcd.print("ВЮВ"); break;}
case 12:
{lcd.print("В"); break;}
case 13:
{lcd.print("ВCВ"); break;}
case 14:
{lcd.print("CВ"); break;}
case 15:
{lcd.print("CСВ"); break;}
}//end switch
}//end dir
. . . . .
Внешний вид
На фото представлен внешний вид дисплея с подключенным контроллером в рабочем состоянии:
Вот так выглядит модуль доработанного датчика в сборе:
Параметры подсветки — те, что указаны на схеме выше. Так как падение напряжения на подсветке в модулях МЭЛТ составляет 4,5 В, то при питании 12 В ток подсветки составляет 50 мА (при максимальном для данного модуля 60 мА).
Корпус максимально уплотнен, чтобы избежать попадания влажного воздуха внутрь (черное обрамление экрана дисплея — из резиновой оболочки тонкого кабеля). Белая пластина справа — ограждение датчика влажности-температуры SHT-75, вынесенного за пределы корпуса (сам датчик находится за ней). Желтый провод выше — антенна передатчика 433 МГц. Слева — разъемы, куда подключены датчики скорости и направления.
А так выглядят показания на дисплее главного модуля метеостанции (черный модуль с белой антенной справа — приемник 433 МГц):
Комментарии (18)
geher
23.11.2018 15:26почему-то дополнением в виде аналога PCF8574 среди строчных дисплеев МЭЛТ снабжаются только версии с конфигурацией 20х4.
По крайней мере еще есть МТ-16S2H-I, который 16х2
но расположены совершенно в нестандартном порядке. Проверил ради интереса и импортные 16х1, и МЭЛТ’овские двухстрочные/четырехстрочные — у всех у них стандартный порядок выводов, а MT-10S1 на этом фоне почему-то выделяется. Так что придется городить самопальное решение.
С порядком выводов у МЭЛТ всегда были интересные решения.
У МТ 16S2H сначала идут 15 и 16, а потом с 1 по 14.
У его варианта с I2C, который МТ 16S2H-I, слева добавлены еще 18 и 17.
У дисплеев 20х4, с которыми имел дело, порядок обычный, с первого и далее до конца без перестаноаок.YRevich Автор
24.11.2018 05:47По крайней мере еще есть МТ-16S2H-I, который 16х2
Спасибо, почему-то не заметил. А что у них там справа буквами А и К помечено? В pdf об этом вроде ничего не указано, или я пропустил?
У МТ 16S2H сначала идут 15 и 16, а потом с 1 по 14
А это как раз встречается и у китайцев. Но применению I2C-модуля не мешает.geher
24.11.2018 13:42А что у них там справа буквами А и К помечено? В pdf об этом вроде ничего не указано, или я пропустил?
Судя по фото, к ним подпаиваются контакты А и К самого ЖК индикатора.
fki
23.11.2018 18:15Известно, что Mega вывести из состояния глубокого сна можно только внешним асинхронным прерыванием
На ардуино с 328p для выхода из SLEEP_MODE_PWR_DOWN удобно использовать WDT таймер, если отключить reset по WDT, то просыпаемся там же, где и заснули.
3lo1i
24.11.2018 00:02Дополню, что дисплеи МЭЛТ ОЧЕНЬ боятся статики, даже в датащите у всех это написано.
Видел, как MT–20S4M меняли десятками из-за пробитых контроллеров, один у меня прямо в руках превратился из дисплея в стекляшку, показывающую только черные квадратики.
За китайскими дисплеями такого не замечал.geher
24.11.2018 13:44Не замечал за ними такого. Но теперь буду осторожнее, спасибо за предупреждение.
cck7777
26.11.2018 03:30В комментариях к той статье мне справедливо указали по поводу конструкции датчиков, что ось подобного устройства должна иметь твердое острие и опираться на столь же твердое основание<...>. Я это, конечно, знал, но тогда не смог придумать способ обеспечить легкую ось с острием достаточной твердости, поэтому, наоборот, пошел по пути минимизации трения...
Вспоминается, «в старые времена» долговечную маломощную опору (без радиальной фиксации) с минимальным трением делали из отмытого наконечника от шариковой ручки и кусочка обычного стекла (важна перпендикулярность). Получалось почти бесплатно. Немного масла или смазки. Легко использовать для осей из трубок от антенн, ну и в алюминий можно запрессовать или вклеить, если есть возможность засверлить торец по центру.
С обычным фторопластом при мелких работах я перестал дружить после появления самоклеющейся каптановой (полиимидной) плёнки, ещё кличут термоскотчем. В теории антифрикционные свойства хуже, на практике из-за твёрдости легче получить неплохие результаты (особенно в паре с нержавейкой/никелированной латунью), например небольшой радиальный подшипник без требований по точности, как у Вас. «Аутдорз» можно защитить подручными средствами — колпачком от ручки, фетром и пр. Сотрётся куда медленнее ПТФЕ.YRevich Автор
26.11.2018 05:41Вспоминается, «в старые времена» долговечную маломощную опору (без радиальной фиксации) с минимальным трением делали из отмытого наконечника от шариковой ручки и кусочка обычного стекла
Отличная идея, вот только именно что «без радиальной фиксации» — при чисто осевой нагрузке. А здесь существенное боковое усилие на верхушку оси, острие будет стремиться уехать по стеклу в сторону, и шарик будет всячески этому способствовать. Придется как-то его ограничивать, и преимущества точеного касания потеряются.
после появления самоклеющейся каптановой (полиимидной) плёнки
Отсюда поподробнее, пожалуйста. Каптан же тонкий, как с его помощью соорудить радиальный подшипник? Металлическим острием он пропилится наверняка, медленнее, чем ПЭТФ, но все равно быстро.
holomen
фигурные скобки здесь не нужны
AllexIn
Писать однострочники в скобках — хорошая практика.
Во многих Code conventions это правило явно прописано.
Избавляет от множества ошибок.
holomen
От чего в этом случае защищают эти скобки «на всякий случай»?
В if`е понимаю, в for понимаю, во всех остальных случаях тоже понятно. Но в case они уж точно лишние.
AllexIn
Единый стиль — первое правило.
Если мы устанавливаем, что однострочников быть не должно, то не делаем исключение.
Собственно ради чего? Правило «однострочников быть не должно» проще чем «однострочников не должно быть нигде кроме case».
Тем более что как правило речь идет нео количестве строк, а о самом факте обособления блока кода.
holomen
ннууу… switch — он и так особенный с точки зрения формы. И отсутствие этих скобок — просто еще одна. Тем более что {lcd.print(«CСЗ»); break;} — совсем не однострочник, а только так записано и спокойно разбивается на несколько строк без потери формы и смысла. Это не
if (aa==bb)
func1();
else
func2();
где действительно эти скобки могут быть полезны.
И тем более совсем не страхуют от забывания вот этого последнего break.
Т.е. эти скобки бесполезны и бессмысленны чуть более чем полностью.
AllexIn
Единый стиль — этого достаточно.