ARDUINO VGA подсветка монитора или телевизора

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
Сделал подсветку используя переходник HDMI на VGA
Сигналы RGB преобразую в постоянные уровни и подаю на аналоговые входы ардуино
За схемы от руки простите
Все работает но как использовать сигналы V и H (вертикальной и горизонтальной синхронизации)чтобы была динамика
пока не как сообразить не могу
Код:
#include <Adafruit_NeoPixel.h>
int red,green,blue = 0;

//  IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIN 6
#define NUMPIXELS 79
#define VGA_R_PIN A0
#define VGA_G_PIN A1
#define VGA_B_PIN A2
// Initialize the neopixel strip
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

 void setup() {
    // Set the pins connected to the potentiometer as inputs
    pinMode(0,INPUT);
    pinMode(1,INPUT);
    pinMode(2,INPUT);
    
    
 strip.begin();
 strip.show(); //  Initialize all pixels to 'off'
 rainbowCycle( 1 ); // Flash rainbows at the begining
}

void loop() {

    // Read and store the potentiometer values
    // We are scaling them from a 12bit scale to an 8 bit scale
 red = map(analogRead(A0), 0, 820, 0 , 255);
 green = map(analogRead(A1), 0, 820, 0 , 255);
 blue = map(analogRead(A2), 0 , 820, 0 , 255);
 

    // set colors of all the eight neopixles
    for(int pixel = 0 ;pixel <   NUMPIXELS   ;pixel++)
    {
 strip.setPixelColor(pixel, red, green, blue);
    }
 strip.show(); // Update the strip with new color values
    delay(50);
}

void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0 ; j<256 * 5 ; j++) { //  5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
 strip.setPixelColor(i, Wheel(((i * 256  / strip.numPixels()) + j) & 255));
    }
 strip.show();
    delay(wait);
  }
}

//  Helper function for rainbows
//  Input a value 0 to 255 to get a color value.
//  The colours are a transition r - g - b - back to r.
 uint32_t Wheel(byte WheelPos) {
 WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
 WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
 WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
20200917_140844.jpg20200917_140903.jpg
 

Вложения

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Видимо надо на 2-ой и 3-ий пины заводить, ловить прерывание , выставлять фланги . И далее в зависимости от того, что надо

Если надо одним цветом заполнить ленту, или ее часть у библиотеки есть функция fill. тогда вместо цикла:
C++:
for(int pixel = 0 ;pixel <   NUMPIXELS   ;pixel++)
    {
 strip.setPixelColor(pixel, red, green, blue);
    }
можно будет написать
C++:
 strip.fill( strip.Color( red, green, blue));
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
(Как я понимаю) горизонтальная синхронизация это столбцы а вертикальная строки
VGA выводит 1024*1024 1024 пикселя по горизонтали 1024 по вертикали яркость и цвет идет от RGB уровней
По этому с помощью H и V надо как то указывать номер пикселя на ленте которая расположена по периметру ТВ

VGA-V.png
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Значит имеем 2 переменные V_S_COUNTER H_S_COUNTER, в прерываниях их увеличиваем на 1, если они достигают 1024, то обнуляются. и в том прерывании, что чаще вызывается выставляем флаг F=true
в цикле loop если F == true (на самом деле просто если F) то смотрим что там такое и F=false.
Но я совсем не уверен, что это будет работать . Пустой цикл loop крутиться 200к раз в секунду, а при разрешении 800 на 600 это будет 480 000 тысяч прерываний. При частоте кадров 50 Герц это еще надо умножить на 50.. что то многовато выходит для ардуины. Или я где то ошибся ?
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
А если просто управлять включением отключением пикселей по горизонтали и вертикали как в матрице
Задаем как будто у нас лента матрица с началом в верхнем левом углу предположим 20+10+20+10
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Вчера долго думал... считаем дальше. 800*600*25/ 1 000 000 = 0,08 микросекунды для вывода одного пикселя. Аналоговое чтение , что у в цикле loop , работает стандартно, т.е. делает 1 занимает 125 микросекунд. Получается что цвета R G и B берутся с каких попало пикселей...
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
Как я думаю--RGB у меня это средний постоянно изменяющийся уровень получаемый через пиковый детектор он преобразуется в яркость
каждого канала получается средний цвет экрана если преобладает красный то красный и так далее так что цвета и яркость меняется и нужно
их синхронизировать по включению какому гореть и не гореть начиная с верхнего левого угла
Это импульсы синхронизации 1- V и 2-3-H . V- 60Hz /H-45kHz

Добавлю это как в ЭЛТ мониторе 3-прожектора электронов RGB( а отклоняющая система управляет в какую часть экрана придут лучи)
и пробегают слева на право 1 строка потом также 2 строка и так далее

Короче надо управлять позицией пикселя
uint8_t Hpos = (Hpos + count)%(strip.numPixels()+1);
может как то так я в программировании никак
 

Вложения

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Вот и я про то...за 125 мс он собирает данные практически по все линии. Именно про это мне и пришла вчера мыслЯ.
И как то это работает, и что то показывает.
Какие появились идеи.
В начале, при включении надо определить частоту кадров. Она вроде бы получается 60Гц. ? т.е. 60 раз в секунду. Понятно что такой скорости не достичь на ардуино. Но будем исходить из разрешения 800 на 600 - мне так проще считать. Еще одна ситуация - надо ускорить ADC , Как это сделать - есть у Алекса. Я чуть поменял под свои цели:
C++:
void SuperFastADC(byte n)
{
  ADCSRA = ADCSRA & B11111000;
  ADCSRA = ADCSRA | n;
}
Получаемое значение должно быть от 1 до 7, это скорость обработки , при большей скорости меньше точность. 1 самое быстрое, не факт что сработает четко. Попробовать можно, но лучше ставить 2. При этом читать данные можно будет 200 000 секунду, что гораздо быстрее , чем 8 000 :)

Если я правильно понял, то горизонтальная синхронизация - это начало линии. Кстати, 45 000 /60 выходит 750 линий - Количество линий хотелось бы тоже определять во время включения. Получается что линия проходит за 22 микросекунды. Округлим до 20. Имеем замер в 5 мкс. = 4 замера на линию.
Какой цикл можно провернуть для начала.
Начало кадра.
Начало линии 1-ой линии.
Делаем 4 замера R цвета и запоминаем из
Начало линии 2-ой линии.
Делаем 4 замера G цвета и запоминаем из
Начало линии 3-ой линии.
Делаем 4 замера B цвета и запоминаем из

Итого: есть 4 замера цветов приблизительно равномерно распределенных по горизонтали. Можем поделить верхнюю ленту на 4 части и задать соотв. куску нужный цвет.

Далее можно повторить то, что делали для 3-х линий несколько раз. 10 -20 - это получиться взять среднее значение не по 3-м линиям а по области.

Параллельно по прерыванию гор. синхронизации считаем номера линий.

Для средних линий можно ничего не делать

Нижнюю группу линий обработать так же как и верхнюю - получить нижнюю ленту цветов.

Боковины пока не трогаем. Отдельно будут мысли

Далее как только получили информацию по цветам - отправляем их в ленту и плевать , что придется пропустить следующий кадр - на это пофиг. да хоть 3 кадра пропустить, не заметим.

Отправили - ждем сл. начала кадра

По боковинам думаю надо делать тогда, когда сделали верхнюю линию.
Примерно так
сделать замер R, пауза 10 микросекунд , замер R
сделать замер G, пауза 10 микросекунд , замер G
сделать замер B, пауза 10 микросекунд , замер B

Так же как и для верхней линии у нас не будет цвета одной точки, но будут компоненты соседних точек.
Если брать среднее значение для нескольких групп, то может оказаться нормально.

еще совет, не знаю на сколько нужен, значения R G B лучше сначала накапливать в 32-битной пременной и уже только перед отправкой высчитывать среднее. Избегать использовать float.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,410
976
58
Марий-Эл
Я никак не пойму, в чём проблема то.
Берёте микросхему - декодер HDMI сигнала. На выходе получаете RGB и два синхроимпульса.
Если пришли и кадровый и строчный, это начало координат, считываем в этом месте RGB и обнуляем счётчик строк.
Время между двумя строчными импульсами известно или его можно померять при инициализации. При приходе строчного импульса запускаем таймер и ждём когда отработает. Таймер настраиваем на то время, что мы имеем между строчными импульсами минус какой тоинтервал. Читаем RGB поджигаем нужный диод уже справа. Увеличиваем счётчик строк на 1. И поехали дальше. Остаётся посчитать сумеет ли ардуинка всё это обрабатывать.
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
А вот с этим я согласен осталось добавить в код
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,410
976
58
Марий-Эл
Рано.
Сначала нужно посчитать.
Здесь уже публиковалась подобная разработка. Но она была проще и сделана на STM32.
А для вашей задачи нужно забыть про Arduino IDE, про ядро и перейти на ассемблер.
Тогда что нибудь и получится.
Но, может быть я ошибаюсь. Нужно считать.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Я очень сильно сомневаюсь , что ардуино с попиксельной разработкой справиться. Та подсветка, что есть у Гайвера завязана на по установленом на компе или на телевизоре, а ардуина только принимает нужную комбинацию цветов. Тут же полноценная , ну почти, обработка изображения...
Я привел алгоритм того, как , пока чисто теоретически, это можно попробовать вывезти на ардуино нано.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Спасибо, да, получается выбирается какое то усредненное значение яркости. Но в целом работает по общему фону. На это хватает. По кускам можно попробовать сделать как я выше описал. Думаю будет приятнее и какое то подобие амбилайта для любого тв должно получиться.
 
  • Лойс +1
Реакции: superflint

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
У нас 5 сигналов RGB HV RGB аналоговые -0.7V а H и V TTL уровня 0-5V
Я RGB преобразовываю в усредненный меняющийся уровень от 0 до 3.5V и читаю его ардуино на выходе получается средний цвет и яркость сигнала RGB по всей длине ленты.
Лента наклеена по периметру экрана сзади .
А с помощью H и V управлять включением пикселей по строкам и столбцам как будто на матрице с началом в верхнем левом угле H ---->/ V вниз20200921_104832.jpg20200921_105005.jpg20200921_104832.jpg20200921_105005.jpg
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Если H и V без преобразования, то их напрямую можно на прерывания пустить, V по низпадающему сигналу, если я не ошибаюсь, а H по любому.
Ну и далее читать аналоги по времени и исходя из расчетов включать диоды.
Но тут вопросы вот в чем... Если у меня нет vga выхода , то нужен конвертор. А я его не хочу, как лишнее устройство. у меня есть уже лишнее устройство для подключения соундбара и сабвуфера к тв... Иначе звук тв говеный. мне хватит. Я бы хотел ставить что то в разрыв hdmi, а это уже stm.
С другой стороны мне интересна задача именно для ардуино. интересно , что выйдет..
Попробую в ближайшее время написать скетч, который будет делать тест сигналов H и V. посмотреть свободное время. А там видно будет.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
А можешь вот что сделать:
V_S подключить к D2, H_S подключить к D3, лучше наверное через резисторы.
Включить что бы работал VGA Переходник и на выходе VGA были сигналы , ессно интересуют верт. и гор. синхронизации
Запустить скетч и вывести что выведет в монитор порта. Скорость порта 115200


C++:
#define V_S_pin 2
#define H_S_pin 3

const uint16_t Kolvo = 10000;

void SuperFastADC(byte n);
void MeasuereADC();
void Measuere_V_S();
void Measuere_H_S();

void setup() {
  Serial.begin(115200);
  pinMode(V_S_pin, INPUT);
  digitalWrite(V_S_pin, LOW);
  pinMode(H_S_pin, INPUT);
  digitalWrite(H_S_pin, LOW);
  Serial.println("START");
  MeasuereADC();
  Serial.println(" ");
  Measuere_V_S();
  Serial.println(" ");
  Measuere_V_S();
  Serial.println(" ");
  Measuere_H_num();
  Serial.println("END");
}

void loop() {
  //Serial.println((PIND & 0b1100)>>2,BIN);

}

void SuperFastADC(byte n)
{
  ADCSRA = ADCSRA & B11111000;
  ADCSRA = ADCSRA | n;
}

void MeasuereADC()
{
  uint32_t t_start = 0;
  uint32_t t_stop = 0;

  for (int i = 1; i < 8; i++)
  {
    Serial.print("ADC №"); Serial.println(i);
    SuperFastADC(i);
    t_start = micros();
    for (int j = 0; j < Kolvo; j++) analogRead(A0);
    t_stop = micros();
    Serial.print("1 mes:");
    Serial.println((float)(t_stop - t_start) / Kolvo);
  }
}

void Measuere_V_S()
{
  uint32_t t_sred = 0;
  uint32_t t_start = 0;
  uint32_t t_stop = 0;
  for (int j = 0; j < Kolvo; j++)
  {
    while ((PIND & 0b00000100) < 1);
    while ((PIND & 0b00000100) > 0);
    t_start = micros();
    while ((PIND & 0b00000100) < 1);
    t_stop = micros();
    t_sred = t_sred + (t_stop - t_start);
  }
  Serial.println((float)t_sred / Kolvo);
}


void Measuere_H_S()
{
  uint32_t t_sred = 0;
  uint32_t t_start = 0;
  uint32_t t_stop = 0;
  for (int j = 0; j < Kolvo; j++)
  {
    while ((PIND & 0b00001000) > 0);
    while ((PIND & 0b00001000) < 1);
    t_start = micros();
    while ((PIND & 0b00001000) < 1);
    t_stop = micros();
    t_sred = t_sred + (t_stop - t_start);
  }
  Serial.println((float)t_sred / Kolvo);
}

void Measuere_H_num()
{
  uint16_t n = 0;

  while ((PIND & 0b00000100) < 1);
  while ((PIND & 0b00000100) > 0);
  while ((PIND & 0b00001000) < 1)
  {
    static bool f = false;
    if (PIND & 0b000001000 > 0)
    {
      if (!f)
      {
        f = true;
        n++;
      }
    }
    else f = false;
  }
  Serial.print("Strok:");
  Serial.println(n);
}
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
https://lektsii.org/2-89302.html

START
ADC ⸮1
ADC ⸮3
1 mes:8.13
ADC ⸮4
1 mes:15.06
ADC ⸮5
1 mes:28.06
ADC ⸮6
1 mes:56.00
ADC ⸮7
1 mes:112.00

START
ADC ⸮1
1 mes:3.15
ADC ⸮2
1 mes:5.03
ADC ⸮3
1 mes:8.13
ADC ⸮4
1 mes:15.06
ADC ⸮5
1 mes:28.06
ADC ⸮6
1 mes:56.00
ADC ⸮7
1 mes:112.00
 

AlexBAN

✩✩✩✩✩✩✩
12 Сен 2020
18
0
Я не программист поэтому только методом тыка но пока как было
Упростил слегка
C++:
#include <Adafruit_NeoPixel.h>
int RED,GREEN,BLUE,H,V = 0;
#define PIN 6
#define VGA_13_H 3
#define VGA_14_V 2

#define NUMPIXELS 79
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int VGA_1_R = A0;
int VGA_2_G = A1;
int VGA_3_B = A2;


void setup() {
pinMode(0,INPUT);
pinMode(1,INPUT);
pinMode(2,INPUT);

pinMode(VGA_13_H, INPUT);
pinMode(VGA_14_V, INPUT);
//digitalWrite(VGA_13_H, LOW);
//digitalWrite(VGA_14_V, LOW);


Serial.begin(115200);
strip.begin();
strip.show();
}
void loop() {

RED  = map( analogRead(A0), 0, 820, 0, 255);
GREEN  = map(analogRead(A1), 0, 820, 0, 255);
BLUE  = map( analogRead(A2), 0, 820, 0, 255);
H = digitalRead(VGA_13_H);                                                                          
V = digitalRead(VGA_14_V);



Serial.print("r= ");
Serial.println( RED);
Serial.print("g= ");
Serial.println(GREEN);
Serial.print("b= ");
Serial.println( BLUE);

Serial.println(digitalRead("h= "));
Serial.println(digitalRead(H));

Serial.println(digitalRead("v= "));
Serial.println(digitalRead(V));

if (digitalRead(H) == HIGH) {
uint8_t pos = H %(strip.numPixels()-1);
}
  if (digitalRead(V) == HIGH) {
uint8_t pos = V %(strip.numPixels()+1);

  }  
int matrix[79] =         {27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
                          26,                                                                     52,
                          25,                                                                     53,
                          24,                                                                     54,
                          23,                                                                     55,
                          22,                                                                     56,
                          21,                                                                     57,
                          20,                                                                     58,
                          19,                                                                     59,
                          18,                                                                     60,
                          17,                                                                     61,
                          16,                                                                     62,
                          15,                                                                     63,
                          14,                                                                     64,
                          13,                                                                     65,
                          12,                                                                     66,
                          11,10,9,8,7,6,5,4,3,2,      1,      0, 78,77,76,75,74,73,72,71,70,69,68,67
} ;                  
     


for(int i = 0; i < 79 ; i++)
{


   strip.setPixelColor(matrix[i],  RED, GREEN, BLUE);



}
strip.show();
}
r= 74
g= 51
b= 59
0
1
0
1
r= 73
g= 51
b= 58
0
1
0
1
r= 72
g= 50
b= 58
0
1
0
1
r= 71
g= 50
b= 58
0
1
0
1
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Я в скетче пытался поймать сигналы с VS и HS, но они почему то не прошли. Я правда без прерывания пробовал. Не просто поймать, а замерить время в микросекундах.
VS надо было подключить к пину 2 , а HS к пину 3.