Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет)

в 4:46, , рубрики: ambilight, arduino, diy или сделай сам, как нам врут в магазинах, Мониторы и ТВ

В этой статье я хочу поделиться с вами опытом изготовления полноценного проектора подключаемого к ПК, с поддержкой разрешения Full HD за 200 рублей.
Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет) - 1

С первым апрелем (для тех, кому лень читать статью. Осторожно, под спойлером спойлер!)

Насколько я вижу не все готовы дочитать до середины материал, который вполне очевидно не про разработку проектора. Жаль, я не хотел в самом начале раскрывать истину… Ну что ж. Эта статья не про Full HD проектор за 200 рублей (что было бы абсурдом). Эта статья про нечестный маркетинг и агрессивный обман со стороны маркетологов.

Итак, начнем.
Проектор состоит из двух в общем-то независимых частей.
Первая — это декодер видеосигнала.
Вторая — это непосредственно проекционное устройство.

Можно объединить обе части в одном модуле.
Но я за разделение. Поэтому начнем с модуля декодера.

Декодер видеосигнала

Для простоты будем работать с VGA.
VGA сигнал делится на три принципиальных части:
1) Передача цвета;
2) Вертикальная и горизонтальная синхронизция;
3) Передача на ПК информации о мониторе — родное разрешение, доступные частоты, инорфмация о производителе.

O VGA

Передача цвета производится аналоговым сигналом от 0 до 0.7 вольт.
Остальные данные передаются в цифровом виде.
Для работы с VGA будем использовать микроконтроллер atmega8.
После разводки у меня получилась вот такая плата:
Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет) - 2
Слева — кварцевый резонатор и питание, сверху — uart по которому мы будем проекционному устройству отдавать сигнал, справа — VGA и снизу — разъем для подключения программатора.
R2 и R3 — это резисторы для i2c канала, по которому передается информация о мониторе.

Об идентификации

Ранее VGA мониторы отдавали информацию подтягиванием четырех пинов на землю. Однако нам такой вариант не подходит, поскольку он не позволяет задать Full HD разрешение.
С приходом больших разрешений VGA обзавелся DDC (Display Data Channel). Это i2c совместимый канал обмена данными. VGA монитор является slave устройством с адресом 0x50 и при запросе от мастера просто отдает фиксированное содержимое — EDID (Extended Display Identification Data).
EDID подробно разобран в той же википедии. Но формировать 128 байт (именно столько занимает блок данных) с нуля — задачка не веселая, даже по подробной спецификации.
Поэтому я просто подключил VGA монитор к нашей плате и написал простенький скетч (даже не буду приводить код, ибо примитивный он), который открывал i2c соединение в роли мастера, делал запрос по адресу 0x50 и просто ретранслировал всё на uart.
Получилось вот так:
Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет) - 3

Мой монитор отдает два блока данных. Первый блок содержит всё что требуется. Второй весь забит 0xff.
Я взял все эти данные и забил в скетч.
Единственный момент — мой монитор имеет родное разрешение 1440x900, а нам нужно 1920х1080.
Поэтому 38 байт переписывается для соответствия Full HD и заново считается контрольная сумма (последний байт).
Контрольная сумма — так называемая Modular sum. То есть сумма всех байт (включая чек-сумму) должна быть 0.

Теперь, если подключить плату к видеокарте ПК по VGA кабелю, система определит второй монитор.
Стоит отметить, что далеко не все ПК у меня определили этот модуль в качестве монитора. То ли из-за того, что я не подключил 4 и 11 пины к земле, то ли потому, что я не стал брать питание с 9 пина… Точно не знаю. Проверять не стал.

О получении картинки

С картинкой всё просто:
Когда приходит VSync сигнал — начинается новый кадр.
Каждый HSync сигнал означает начало новой строки.
Значения из аналоговых RGB каналов, полученные в период между двумя HSync сигналами, и представляют строку пикселей на экране.
В теории все просто. Но есть нюанс:
Даже картинка 640х480 при частоте 60 герц требует для обработки 25 мегагерцовый процессор… Full HD почти на порядок требовательнее.
А у нас atmega8 с потолком в 15 мегагерц… Какие уж тут Full HD… Мы даже 640х480 не потянем…
Можно, конечно, прикрутить сюда stm32 и он справится без проблем… но зачем?
Мы пойдем другим путем. И будем полностью игнорировать сигналы синхронизации.
Просто в лоб, в течении 100 миллисекунд накапливаем r,g,b значения — сколько сможем, а потом получаем среднеарифметическое. Полученное RGB значение и будет средним цветом экрана… с некоторой погрешностью. Его и будем отдавать проекционному устройству.

Итоговый скетч выглядит примерно так:

VGA-to-UART.ino

#include "Wire.h"
const int EDID_BUFFER_SIZE = 256;
const int EDID_SIZE = 128;
uint8_t EDID[EDID_BUFFER_SIZE] = {
  0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
  0x1e,0x6d,
  0x7a,0x4b,
  0x02,0x12,0x01,0x00,
  0x0f,
  0x13,
  0x01,
  0x03,
  0x6e,0x29,0x1a,0x78,0xea,
  0xe5,0xb5,0xa3,0x55,0x49,0x99,0x27,0x13,0x50,0x54,
  0xbf,0xef,0x80,
  0x95,  //<<<PLACE RESOLUTION HERE (RES/8-31) EXAMPLE: 1440/8-31=0x95
  0x0f,
  0x45,0x4f,0x61,0x4f,0x81,0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
  0x9a,0x29,0xa0,0xd0,0x51,0x84,0x22,0x30,0x50,0x98,0x36,0x00,0x9a,0x00,0x11,0x00,0x00,0x1c,
  0x00,0x00,0x00,0xfd,0x00,0x38,0x4b,0x1e,0x53,0x0e,0x00,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,
  0x00,0x00,0x00,0xfc,0x00,0x57,0x31,0x39,0x33,0x34,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  0x00,0x00,0x00,0xfc,0x00,0x20,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  0x00,
  0x5b
};

int requestPos = 0;

void setup() {
  Serial.begin(115200);  
  Serial.println("start");  

  EDID[38] = 1920/8 - 31;
  uint8_t sum = 0;
  for (int i = 0; i<EDID_SIZE-1; i++)
    sum+=EDID[i];
  EDID[EDID_SIZE-1] = 0-sum;


  for (int i = EDID_SIZE; i<EDID_BUFFER_SIZE; i++)
    EDID[i] = 0xff;

  Wire.begin(0x50);
  Wire.setClock(100000);
  Wire.onRequest(requestEvent);
}

int maxValue = 1;
float r_v = 0;
float g_v = 0;
float b_v = 0;
int count = 0;

long lastUpdate = 0;
int loopTime = 0;
const int LOOP_TIME = 100;

void loop() {  
  int r = analogRead(0);
  int g = analogRead(1);
  int b = analogRead(2);
  if (r>maxValue)
    maxValue = r;
  if (g>maxValue)
    maxValue = g;
  if (b>maxValue)
    maxValue = b;    

  r_v += r / (float)maxValue;
  g_v += g / (float)maxValue;
  b_v += b / (float)maxValue;
  count ++;

  long dt = millis() - lastUpdate;
  lastUpdate+=dt;
  loopTime+=dt;
  if (loopTime>=LOOP_TIME){
    loopTime=0;

    r_v = r_v / count;
    g_v = g_v / count;
    b_v = b_v / count;

    Serial.println("RGB");
    Serial.println((int)(r_v*100),DEC);
    Serial.println((int)(g_v*100),DEC);
    Serial.println((int)(b_v*100),DEC);

    r_v = 0;
    g_v = 0;
    b_v = 0;
    count = 0;
  }
}

void requestEvent(int count) {  
  if (count+requestPos>EDID_BUFFER_SIZE)
    count = EDID_BUFFER_SIZE-requestPos;
  Wire.write(&EDID[requestPos],count);
  
  requestPos+=count;
  if (requestPos>=EDID_BUFFER_SIZE)
    requestPos = 0;
}

Пояснение по поводу maxValue:
Референсного вольтажа у нас нет. Какое конкретно питание приходит на атмегу — тоже вопрос открытый.
Поэтому мы считаем за референсный вольтаж самое большое значение, которое нам пришло по одному из цветовых каналов. Погрешность при таком подходе минимальна.

Итак, видеосигнал декодирован, получено среднеарифметичское и отправлено по uart… куда? Конечно же проекционному устройству. О нем и поговорим.

Проекционное устройство

Правда, разговор будет короткий. Проекционное устройство — это RGB светодиод. В моем случае я просто подключил его к arduino nano и после получения по uart значения цвета устанавливаю шимом нужную яркость каналов светодиода.
И на этом всё.

Комплектующие:
atmega8
небольшая кучка резисторов
небольшая кучка разъемов
rgb светодиод
vga разъем

P.S>
Не спешите минусовать, ниже я расскажу, что за фигню мы тут собрали. А пока — небольшое лирическое отступление.

Чувствуете себя обманутыми?

Я уверен, что да. Конечно же, вы сразу понимали что не бывает Full HD проекторов за 200 рублей. Но так хочется верить в чудо.
Спешу вас заверить, с точки зрения современного маркетинга я вам не соврал! Ведь вот он — проектор. И он честно поддерживает 1920х1080.
А сподвигли меня на написание этой статьи — именно в такой форме — ребята, которые открыли «магазин крутых дешевых проекторов». Вполне возможно сейчас справа от этого текста висит как раз их реклама. Во всяком случае я к ним пришел именно с geektimes. Я не буду писать название этого магазина — это не принципиально. Их миллион и они — мошенники.
Мошенники не потому, что присылают кирпичи вместо проекторов. Нет, я уверен что они так не делают.
И не потому, что исчезают с деньгами. Так они, вероятно, не делают тоже.
Они «честно» продают вам проектор. С заявленными характеристиками.
Вот только, если вы не специалист, вы поймете где обман слишком поздно. Когда предъявить будет уже нечего. Ведь так хочется верить, что может существовать Full HD проектор за 2007000 рублей.
Мне повезло — есть опыт работы с проекторами, есть понимание, что не может в конце 2016 года Full HD проектор стоить 7000 рублей. И поэтому я целенаправленно искал где обман.
Попросил прислать информацию о юрлице. И мне прислали. Попросил добавить опись в посылку с наложенным платежом (это защищает от кирпича в посылке) и они без проблем согласились. И понял я в чем подвох, только когда нашел китайского производителя этих проекторов.
Вот так выглядит список характеристик на сайте таких магазинов:

Поддержка разрешения: 1920х1080
Яркость 1000 Люмен
Контрастность 1000:1
Диагональ экрана 34~130 дюймов
Проекц. расстояние 1~4 м
Срок службы лампы 30 000 часов
Вход: USB-2шт, HDMI, AV, AUDIO, SD

И это корректные характеристики.
Видите подвох?
Вот вам подсказка — вот так я мог бы написать характеристики проектора, которые собрал для этой статьи:

Поддержка разрешения: 1920х1080
Диагональ экрана 34~130 дюймов
Проекц. расстояние 1~4 м
Срок службы лампы 30 000 часов
Вход: VGA

А теперь для тех, кому лень играть в угадайку:
В этих списках есть полная ерунда под названием «Поддержка разрешения», которая не значит вообще ничего. Это разрешение, которое может схавать декодер и не более того.
Причем, что характерно, тот же проектор у производителя имеет еще одну строку:
Native resolution: 800x480
Согласитесь, сразу всё встает на свои места!

Поддержка разрешения: 1920х1080
Родное разрешение: 800х480
Яркость 1000 Люмен
Контрастность 1000:1
Диагональ экрана 34~130 дюймов
Проекц. расстояние 1~4 м
Срок службы лампы 30 000 часов
Вход: USB-2шт, HDMI, AV, AUDIO, SD

Поддержка разрешения: 1920х1080
Родное разрешение: 1х1
Диагональ экрана 34~130 дюймов
Проекц. расстояние 1~4 м
Срок службы лампы 30 000 часов
Вход: VGA

И ведь нечего предъявить… Формально всё прекрасно! Проектор? Проектор! 1920х1080 поддерживает? Поддерживает!
Ну, а чтобы вы случайно не нашли проектор на китайском сайте — картинки проектора они показывают отраженными.
Не ведитесь, господа и дамы. Покупайте только хорошие проекторы. А такие маркетологи… Пожелаю им всего самого <добавить по своему вкусу>.
Засим лирическое отступление заканчиваем и возвращаемся к нашему проектору.
Который вовсе и не проектор.

Hardware ambilight первого поколения

Ambilight (Ambient Lighting Technology) — это технология подсветки пространства за экраном.
Philips были первыми, кто это придумал.
Первая версия ambilight просто брала среднее значение цвета на экране и освещала стену позади экрана этим средним цветом. Эффект достаточно интересный, т.к. усиливает погружение. Этот эффект возможен потому, что наше периферическое зрение значительно хуже различает детали, но при этом хорошо определяет общий цвет. То есть даже ambilight первого поколения обладает отличным эффектом.
На али вы можете легко купить комплект ambilight, но мне они не нравятся тем, что требуют установки китайского софта. Это и потеря производительности, и отсутствие кроссплатформы, и китайский софт на ПК…
Плата, созданная нами выше, позволяет обойтись без программных решений и достичь результата первого поколения.
Для того, чтобы сделать современный ambilight и процессор понадобится помощнее, и границы экрана нужно будет анализировать уже попиксельно.
Минус предложенного решения в том, что нужен свободный разъем в видеокарте (у меня его нету, например. Поэтому на видео с демонстрацией второй моник отключен. Его кабель воткнут в плату), плюс немного производительности видеокарты тратится на дублирование изображения. Не говоря уже о том, что не все ПК определяют эту плату как монитор.

Поэтому есть второй вариант аппаратного видеодекодера для ambilight.
Выглядит вот так (сделал под arduino nano — для простоты):
Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет) - 4
Как можно заметить — это просто врезка в VGA кабель, с пассивным чтением RGB канала.
Из минусов тут — возможное ухудшение качества сигнала. Хотя я ничего такого не заметил.
Плюсы очевидны — просто втыкаем перед монитором и имеем автономный декодер.

Выглядит в работе это вот так:

Светодиод, конечно, имеет очень посредственную передачу. Да еще и камера не успевает быструю смену цвета светодиода показать.

P.S.
VGA разъемы я, конечно же, не покупал. Я их выпаял из старой материнки и двух плат от мониторов.
Выпаял модным нынче гаджетом: автомобильным прикуривателем, запитанным от автомобильного же аккумулятора. Ну это так, если вдруг кто не в курсе, что можно жить и выпаивать без паяльного фена.
Делаем проектор с поддержкой Full HD за 200 рублей (на самом деле да, но нет) - 5

Автор: AllexIn

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js