В магнитофонах и приёмниках моей юности использовались исчезнувшие ныне ламповые индикаторы уровня на лампах 6E1П или 6Е5С. Сейчас пришла пора ностальгирования по "старым временам" и на алиэкспрессе или амазоне можно купить собранные индикаторы, они почти также популярны как часы на лампах "Никси".
Поскольку лампа требует высокого напряжения для работы, в современных устройствах это решается с помощью преобразователя напряжения на таймере 555 упроавлящим мощным полевым транзистором включенным в первичную обмотку повышающего трансформатора, и дальше вторичная обмотка подключается к умножителю напряжения из 4-5 ступеней. Этого достаточно чтобы преобразовать входные 5 вольт в 250 с током 1-2 ma.
Я хочу поделиться своим домашним проектом, суть которого в эмуляции, насколько возможно, "зелёного глаза" лампы 6E1П с помощью быстрого OLED дисплея, контролируемого платой Arduino:
Самым сложным оказалось подобрать подходящий дисплей. На рынке их огромное количество, и большинство из них легко управляется известной библиотекой Adafruit-GFX-Library . Это прекрасная универсальная библиотека, очень простая в использовании, однако при использовании обычных плат Arduino она слишком медленная и не позволяет выводить качественную анимацию. После большого количества неудач методом проб и ошибок был найден дисплей на чипе SH1106, размером 128х64 точек и с голубым свечением. Для него предлагается библиотека ардуино U8G2. Особенностью этой библиотеки является наличие страничного вывода, т.е. сначала изображение создаётся в памяти контроллера, и затем единственной командой выводится на дисплей. Это позволяет создавать простые анимации с хорошей частотой обновления. Библиотека также содержит команды для построения геометрических примитивов - прямоугольников, треугольников и окружностей. Также возможен вывод простых битмапов, однако он слишком медленный чтобы использовать для анимации. Однако битмапы могут работать как маски для вырезания части изображения, и я использовал такой битмап для придания характерной формы экрана "зеленого глаза" - вертикального прямоугольника с округлой верхней стороной.
Общий принцип построения геометрии из примитивов:
Размеры примитивов меняются динамически в зависимости от напряжения на входе A0 платы Arduino.
Как я уже говорил, эмуляция вполне приблизительная. Хотя геометрию изображения я считаю довольно близкой к оригиналу, монохромность дисплея не позволила создать правильный фон, так что у меня изображение на полностью чёрном фоне, тогда как в оригинальной лампе фон всегда бледно-зелёный.
Была еще одна техническая запинка, которую мне удалось преодолеть. Дисплей этот имеет синее свечение, а мне нужно ярко-зелёное. Проблема решилась с помощью высокотемпературного скотча дюймовой ширины, это интенсивно-жёлтая полиимидная липкая лента, материал также называют "каптон". По ширине она идеально соответствует дисплею и будучи аккуратно наклееной, прекрасно превращает голубое свечение экрана в зелёное, очень близкое по цвету к "ламповому".
Для эффектности я добавил к входу Arduino сигнал с простенькой платы микрофона с усилителем от Adafruit .
Дисплей и несколько дополнительных компонент для микрофона я разместил на вырезаной под размер Arduino простенькой монтажной плате, весь монтаж выполнен проводами:
Диаграмма соединения деталей:
Сидя в карантине, я планирую сделать аналогичный вывод для старинного индикатора 6E5С (это западная лампа E81):
Для любопытствующих приведу мой код для Ардуино. Я отнюдь не считаю себя продвинутым программистом микроконтроллеров и никоим образом не претендую на совершенство стиля и кода, меня вполне устраивает что он просто работает.
Для плавности изображения я использую усреднение по 5 замерам. Усреднение написано "руками", пытался использовать стандартную библиотеку RunningAvg, но для простенькой ArduinoUno вместе с библиотекой дисплея не хватает памяти.
Я взял себе за правило добавлять простой информативный header в свой код а также пару строчек, которые при запуске напоминают из какого файла и когда этот код был залит.
/************************************************************
WHEN: 07-SEP-2020
WHAT: Magic eye emulator with OLED 1.3″ 128×64 I2C Blue Display I2C address 0x3C
https://protosupplies.com/product/oled-1-3-128x64-i2c-blue-display/
Uses Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
DETAILS:
without RunningAvg library as per
https://www.powertronika.com/2020/04/reducing-noise-from-sensor-data.html
bitmap for central triangle, side with circle and rectangle
On Mega2056 SDA A20, SCL A21
On UNO SDA A4, SCL A5
Use analogReference() for signal 1-2.5 v
Analog input on A0
Works on direct input from radio receiver /************************************************************/
#include <Arduino.h> #include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif
#define ARR_SIZE 5
// U8g2 Contructor List (Frame Buffer) // The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R1, /* reset=*/ U8X8_PIN_NONE); int sum, a, y_max, delta_side,delta_y; //delta_side,delta_y - for small side triangles when a>32; y_max - maximum height float p,p_avg,myRA[ARR_SIZE]; byte index;
#define owl_width 64 #define owl_height 36 static const unsigned char owl_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0xff };
void setup(void) { Serial.begin(115200); u8g2.begin(); Serial.print("Sketch: "); Serial.println(FILE); Serial.print("Uploaded: "); Serial.println(DATE);
delta_side=12; delta_y=40; y_max=100; sum=0; index=0; u8g2.setFont(u8g2_font_timR10_tr); u8g2.setFontDirection(2); }
void loop(void) { p=analogRead(A0); //averaging sum=sum-myRA[index]; myRA[index]=p; sum+=p; index=(index+1)%ARR_SIZE; p_avg=sum/ARR_SIZE; //myRA.addValue(p); //p_avg=myRA.getAverage(); a=min(map(p_avg,1,60,1,32),80); //drawScreen(a,p_avg,1); //print amplitude drawScreen(a,p_avg,0); //don't print amplitude }
void drawScreen(int a, int vu, boolean printVU) { int16_t delta, a_x,a_y,a1,r,r1; u8g2.clearBuffer(); delta=min(32,a); a1=min(a,72); a_y=min(map(a,4,32,18,32),50);//70 a_x=map(delta,4,32,16,10); r=map(delta,4,32,11,8); r1=map(delta,4,32,6,0); if (a<6) u8g2.drawBox(29,0,7,y_max); //central triangle else u8g2.drawTriangle(32,0,32-delta,y_max,32+delta,y_max); if (a1>32) { u8g2.drawTriangle(32-delta_side, delta_y,0,y_max,0,y_max-(a1-32)); u8g2.drawTriangle(32+delta_side, delta_y,64,y_max,64,y_max-(a1-32)); } //side triangles
u8g2.drawTriangle(28,10,a_x,a_y,a_x,10); u8g2.drawBox(0,10,a_x,a_y-10); u8g2.drawDisc(r1+1,a_y-r1-2,r,U8G2_DRAW_LOWER_RIGHT|U8G2_DRAW_LOWER_LEFT); u8g2.drawTriangle(36,10,64-a_x,a_y,64-a_x,10); u8g2.drawBox(64-a_x,10,a_x,a_y-10); u8g2.drawDisc(64-r1-1,a_y-r1-2,r,U8G2_DRAW_LOWER_RIGHT|U8G2_DRAW_LOWER_LEFT); u8g2.setDrawColor(0); u8g2.drawBox(0,0,64,14); u8g2.setBitmapMode(1); u8g2.setDrawColor(0); u8g2.drawXBMP(0,64,owl_width, owl_height, owl_bits); u8g2.setDrawColor(1); if (printVU) { u8g2.setCursor(40, 110); u8g2.print(vu); }
u8g2.sendBuffer();
}
.
Комментарии (27)
iliasam
06.09.2021 21:02+1В строну таких экранов не смотрели — www.technoblogy.com/show?L6I=?
Плотность пикселей несколько выше, можно цвет подобрать. Хотя OLED ярче будет, плюс у таких экранов могут быть сложности со скоростным обновлением.K_Chicago Автор
06.09.2021 22:30Смотрел, а какже. Анимация плохая, тормозит.
Sdima1357
06.09.2021 23:09+1Он не очень медленный, это Ардуино медленный. С stm32 или esp32 у этого экрана меньше 40 миллисекунд перерисовки всего фрейма .
K_Chicago Автор
06.09.2021 23:32моя цель здесь была использовать простейшую ардуинку и поэтому я долго подбирал дисплеи и отказался от использования библиотеки для усреднения.
Разумеется, если пойти по пути подбора микроконтроллеров, а не экранов, можно достичь желаемой скорости с любым почти экраном.
Sdima1357
06.09.2021 23:50+3Ардуинка и не проще и не дешевле. Это иллюзия из-за низкого порога вхождения . Именно поэтому Вам и пришлось долго перебирать дисплеи.
K_Chicago Автор
07.09.2021 00:00Вы будете возражать что из всего семейства ардуинок - Arduino Uno простейшая или по крайней мере одна из простейших?
Gdalex
07.09.2021 23:37+1Тут проблема не столько в процессоре, а в формате вывода. Контроллеры этих дисплеев (SSD1306 и SH1106) могут работать как по I2C, так и по SPI. Так вот я тоже в своей поделке использовал I2C и библиотеку от Adafruit (кстати, она тоже работает в страничном режиме, формируя изображение в памяти МК, а потом отправляет одной пачкой на экран). Получил скорость обновления порядка 2-4 кадра в секунду. А вот переведя свой дисплей в режим SPI скорость обновления кадров на той же самой Ардуине и в той же программе (только строку инициализации поменял) поднялась до 28 кадров в секунду. Так что, автору надо попробовать изменить схему подключения и качество картинки заметно увеличится. А вот при работе по SPI уже можно смотреть в сторону stm32. :-)
Sdima1357
08.09.2021 00:05Ну i2c для дислеев... Я даже и не вспомнил об этом извращении. А по SPI они вроде до 18Mbsps спокойно работают.
Gdalex
08.09.2021 10:47+2Зато автор вспомнил. Судя по диаграмме соединений в статье.
Потом увидел видео работы дисплея и понял, что он и вправду на I2C висит.
K_Chicago Автор
08.09.2021 22:06Может быть вы даже заметили, что плата дисплея которую я использовал, поддеживает только I2C.
Так что все эти рассуждения про SPI vs I2C это к данной теме отношения не имеет от слова совсем.
Sdima1357
09.09.2021 00:23+1Речь шла не о вашем дисплее , а о https://habr.com/ru/post/576582/comments/#comment_23453480
Gdalex
13.09.2021 13:57+1Не скажите, рассуждения на Хабре как раз-таки приветствуются, так как в споре рождается истина.
А то, что Вы выбрали не тот дисплей - это же не моя вина, так что не надо грубить. Я просто пытаюсь помочь улучшить неплохой проект. Идея хорошая, реализация очень неплохая, а вот дисплей, подключенный по SPI, поможет повысить частоту кадров и сгладить изображение.
Neuromantix
06.09.2021 21:09+3К сожалению, все виденные мной эмуляторы не передают искрящегося зеленого цвета и плавности движения границ сектора. Получается именно светодиодный свет, "жесткий".
K_Chicago Автор
06.09.2021 22:32про оттенок цвета совершенно согласен, это ничем не заменить. С плавностью в моём устройстве всё в порядке, после того как подобрал усреднение и фильтр RC на входе с микрофона.
Moskus
07.09.2021 01:03Ближе всего, возможно, был бы матричный монохромный LCD с электролюминесцентной подсветкой.
sav13
Можно обойтись без 555, если прямо с ардуины ШИМ брать на MOSFET с диодом и дросселем
p.s. Проект вызывает мысль о суррогатах. Если уж хочется ностальгии, то почему бы теплые лампы не запустить? Слабо?
engine9
Слышал инфу, что есть опасность устроить КЗ если МК зависнет с 1 на выходе ШИМ.
sav13
Там же дроссель в цепи. Ток ограничит, хоть и нагреется.
sim2q
Сработает как ватчдог. Через дроссель закоротится питание и всё запустится заново.
А может и нет :) Для Ардуино - норма)
Andy_Big
Поставить последовательно выходу МК конденсатор и пусть зависает сколько хочет :)
engine9
Я в схемотехнике не силён, разве такая схема будет работать? Куда заряд с затвора будет уходить? Вангую, что там поплывут фронты и будет мосфет греться как печка.
Andy_Big
В землю через резистор :)
Фронты поплывут, конечно, но там же и не нужно амперы прокачивать на сотнях кГц, так что ничего страшного :)
sav13
К сожалению, нужно. Если изначально питать все это от 5В, а на выходе получать 250В, то при 2мА на выходе через фет идет на меньше 1А. У меня при питании ИН12 и транзистор в ТО220 и дроссель греются. Хоть радиатор ставь.
Вот думаю, пора возвращаться к аутентичным схемам питания и от сети получать сразу 170В с трансофрматора. А то получается слишком много преобразователей туда-сюда. Или даже 220 через резистор, как в журнале радио публиковали
Andy_Big
Да, пожалуй соглашусь. Не учел, что требуется такой большой коэффициент повышения напряжения, а при нем скважность ШИМ должна быть близкой к 100%, что требует крутых фронтов и повышает средний ток через ключ.
RTFM13
От номиналов зависит. Проблема в другом. При резисторе на землю после конденсатора, напряжение на затворе будет меньше напряжения логической единицы в зависимости от коэффициента заполнения. При коэффициенте заполнения 0,5 напряжение будет 0,5 от логической единицы (при условии что тау RC существенно больше длины импульса). Тогда при логическом уровне 5В еще можно найти мосфет на 2,5В, то для 3,3В пригодных мосфетов думаю не найти или будет работать на пределе с повышенным тепловыделением и переходом в линейный режим при любой просадке.
Лучше конечно не экономить и поставить драйвер или сразу полумост с логическим входом.
K_Chicago Автор
"...почему бы теплые лампы не запустить? Слабо? "
Даже смешно говорить, это легче лёгкого, и никакой арудины не нужно от слова совсем. Была же статья здесь, супер дотошная. Я по сути уже описал свое устройство. Таймер 40 кгц, вч-трансформатор на ферритовом "горшке" (остался от развлечений с винтажными приемниками), 4 ступени умножителя Кокрофта-Валтона и все работает без проблем. Только кушает очень много, накал плюс трансформатор, только успевай свежие батарейки ставить. Когда лампа разогреется, напряжение падает до 190 вольт, но вполен хорошо светится. Полевик немного тёплый, трансформатор тоже не холодный. Но это именно "суррогат", неинтересно. Я в ардуину лучше. Вот схема таймера, прямо из datasheet (только номиналы другие, 40 кгц подбирал экспериментально по максимальному напряжению на вторичке трансформатора; и ещё с третьей ноги резистор на землю 10к):
Вот вам мой колхоз:
И для мучительно ностальгирующих на али есть отлично, прямо-таки образцово выполненная плата как раз для этой лампы. Я знаю про качество потому что раньше купил такую же плату для лампы EM87 (она появилась раньше, а нынешняя совсем недавно) и переделывал её под 6E1П. Но жрёт как не в себя и разъём питания нестандартный.