«Магический глаз» тёплых ламповых времён — эмуляция на ардуино

В магнитофонах и приёмниках моей юности использовались исчезнувшие ныне ламповые индикаторы уровня на лампах 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 простенькой монтажной плате, весь монтаж выполнен проводами:

Диаграмма соединения деталей:
Для любопытствующих приведу мой код для Ардуино. Я отнюдь не считаю себя продвинутым программистом микроконтроллеров и никоим образом не претендую на совершенство стиля и кода, меня вполне устраивает что он просто работает.
Для плавности изображения я использую усреднение по 5 замерам. Усреднение написано «руками», пытался использовать стандартную библиотеку RunningAvg, но для простенькой ArduinoUno вместе с библиотекой дисплея не хватает памяти.
Я взял себе за правило добавлять простой информативный header в свой код а также пару строчек, которые при запуске напоминают из какого файла и когда этот код был залит.
Поскольку лампа требует высокого напряжения для работы, в современных устройствах это решается с помощью преобразователя напряжения на таймере 555 упроавлящим мощным полевым транзистором включенным в первичную обмотку повышающего трансформатора, и дальше вторичная обмотка подключается к умножителю напряжения из 4-5 ступеней. Этого достаточно чтобы преобразовать входные 5 вольт в 250 с током 1-2 ma.
Я хочу поделиться своим домашним проектом, суть которого в эмуляции, насколько возможно, «зелёного глаза» лампы 6E1П с помощью быстрого OLED дисплея, контролируемого платой Arduino:
Проект выполнен несколько лет назад.
Самым сложным оказалось подобрать подходящий дисплей. На рынке их огромное количество, и большинство из них легко управляется известной библиотекойAdafruit-GFX-Library. Это прекрасная универсальная библиотека, очень простая в использовании, однако при использовании обычных плат Arduino она слишком медленная и не позволяет выводить качественную анимацию. После большого количества неудач методом проб и ошибок был найден дисплей на чипе SH1106, размером 128х64 точек и с голубым свечением. Для него предлагается библиотека ардуино U8G2. Особенностью этой библиотеки является наличие страничного вывода, т.е. сначала изображение создаётся в памяти контроллера, и затем единственной командой выводится на дисплей. Это позволяет создавать простые анимации с хорошей частотой обновления. Библиотека также содержит команды для построения геометрических примитивов — прямоугольников, треугольников и окружностей. Также возможен вывод простых битмапов, однако он слишком медленный чтобы использовать для анимации. Однако битмапы могут работать как маски для вырезания части изображения, и я использовал такой битмап для придания характерной формы экрана «зеленого глаза» — вертикального прямоугольника с округлой верхней стороной.
Общий принцип построения геометрии из примитивов:

Как я уже говорил, эмуляция вполне приблизительная. Хотя геометрию изображения я считаю довольно близкой к оригиналу, монохромность дисплея не позволила создать правильный фон, так что у меня изображение на полностью чёрном фоне, тогда как в оригинальной лампе фон всегда бледно-зелёный.
Была еще одна техническая запинка, которую мне удалось преодолеть. Дисплей этот имеет синее свечение, а мне нужно ярко-зелёное. Проблема решилась с помощью высокотемпературного скотча дюймовой ширины, это интенсивно-жёлтая полиимидная липкая лента, материал также называют «каптон». По ширине она идеально соответствует дисплею и будучи аккуратно наклееной, прекрасно превращает голубое свечение экрана в зелёное, очень близкое по цвету к «ламповому».
Для эффектности я добавил к входу Arduino сигнал с простенькой платы микрофона с усилителем от Adafruit.
Дисплей и несколько дополнительных компонент для микрофона я разместил на вырезаной под размер Arduino простенькой монтажной плате, весь монтаж выполнен проводами:



Для плавности изображения я использую усреднение по 5 замерам. Усреднение написано «руками», пытался использовать стандартную библиотеку RunningAvg, но для простенькой ArduinoUno вместе с библиотекой дисплея не хватает памяти.
Я взял себе за правило добавлять простой информативный header в свой код а также пару строчек, которые при запуске напоминают из какого файла и когда этот код был залит.
/************************************************************
* WHEN: 07-SEP-2022
* 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>
#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);
U8G2_SSD1327_WS_128X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
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__);
// #if defined(__AVR_ATmega2560__)
// analogReference(INTERNAL1V1);
//analogReference(INTERNAL2V56);
//#else
// analogReference(INTERNAL);
// #endif
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();
}
Самые обсуждаемые обзоры
+35 |
3772
167
|
PS: Лампы продаются, стоит у меня в Ригонде mysku.club/blog/diy/76018.html
Вот такая вот у меня «ностальжи» по старой технике…
Да и не плоская она
Коробка DSG всем хороша, но не видит дорогу
Приходится иногда помогать — руками сбрасывать на передачу ниже. Ибо затяжной подъём на 1200 оборотах — оно такое себе. Хотя двиг и может
Но
На дачной дороге есть уклон градусов 15-20 с ухабами и колдобинами. Так вот на этой горке на принудительной первой ползёт вниз 5 км/ч. Дизель крутится под 3 тыс
Но опять же есть нюанс — классический автомат работает через гидромуфту (когда-то бывшей гидротрансформатором), DSG (aka Робот) — на «обычном» сцеплении. Здесь связь жёстче.