Простая игровая тв-приставка на Arduino

Вступление


При свете дня, а затем и во сне, возникла у меня идея создания собственной регламентированной тв-приставки. Собственно, тут-то открылся передо мной богатый и насыщенный мир радиотехники. Так как ранее я не имел дела с серьезной разработкой электроники, мой выбор пал на более простой вариант — Arduino и ее самая распространенная модель — Uno.




План работы

1. Разобраться с библиотекой
2. Спаять плату видео вывода
3. Написать код
4. Вырезать корпус


Финальная внешняя составляющая не особо важна в случае с подобными проектами.

Шаг 1. Разбираемся, что к чему


После нескольких десятков минут отчаянного гугления пришел к выводу, что создать приставку даже типа Денди у меня не получится. Ну, что тут делать, раз взялся, буду доводить дело до конца.

На сайте, посвященному проектам на Ардуино и вообще радиоэлектронике в целом (не реклама) нашел статью о подобной затее. Было решено использовать библиотеку TVout, так как приставка тв-шная. Для ее установки и работы пришлось немного пошаманить.

Необходимые функции библиотеки

Функции установки режима


Функция begin() инициализирует вывод видеосигнала (разрешение экрана по умолчанию 128x96).
Синтаксис:
TVOut.begin(mode);
TVOut.begin(mode, x, y);

Параметры:
mode – стандарт видеосигнала:
_PAL – режим PAL;
_NTSC – режим NTSC.
Возвращаемое значение:
0 – в случае удачного соединения, 4 – в случае неудачи (недостаточно памяти для буфера вывода).

Функции задержки


Функция delay() осуществляет задержку выведенного изображения.
Синтаксис:

TVOut.delay(ms);
Параметры:

ms – задержка в мс с точностью: 20 мс для PAL и 16 мс для NTSC.

Функция delay_frame() осуществляет задержку выведенного изображения.
Синтаксис:

TVOut.delay_frame(frames);
Параметры:

frames – количество кадров для задержки…
Функция полезна для сведения к минимуму или устранения на мерцание экрана, вызванные обновлением экрана.

Функции получения параметров


Функция hres() возвращает горизонтальное разрешение экрана.
Синтаксис:

TVOut.hres();
Параметры:

нет.
Возвращаемое значение:

unsigned char – горизонтальное разрешение экрана.

Функция vres() возвращает вертикальное разрешение экрана.
Синтаксис:

TVOut.vres();
Параметры:

нет.
Возвращаемое значение:

unsigned char – вертикальное разрешение экрана.

Функция char_line() возвращает максимально возможное количество символов в одной строке при выводе текстовой информации.
Синтаксис:

TVOut. char_line();
Параметры:

нет.
Возвращаемое значение:

unsigned char – количество символов.

Основные графические функции


Функция set_pixel() устанавливает цвет пикселя экрана в точке с заданными координатами.
Синтаксис:

TVOut.set_pixel(x,y,color);
Параметры:

x,y – координаты пикселя;
color – цвет пикселя:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция get_pixel() получает цвет пикселя экрана из точки с заданными координатами.
Синтаксис:

TVOut.get_pixel(x,y);
Параметры:

x,y – координаты пикселя.
Возвращаемое значение:

color – цвет пикселя:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция fill() заполняет экран заданным цветом.
Синтаксис:

TVOut.fill(color);
Параметры:

color – цвет заполнения:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция clear_screen() очищает экран, заполняя заданным цветом.
Синтаксис:

TVOut.clear_screen(color);
Параметры:

color – цвет заполнения:
0 – черный;
1 – белый;
2 – инвертировать цвет.

Функция invert() инвертирует содержимое экрана.
Синтаксис:

TVOut.invert();
Параметры:

нет.
Функция shift_direction() сдвигает содержимое экрана.
Синтаксис:

TVOut.shift_direction(distance, direction);
Параметры:

distance – расстояние для сдвига содержимого экрана.
direction – направление сдвига:
UP=0 – вверх;
DOWN=1 – вниз;
LEFT=2 – влево;
RIGHT=3 – вправо.

Функция draw_line() соединяет на экране линией две точки.
Синтаксис:

TVOut.draw_line(x0,y0,x1,y1,color);
Параметры:

x0,y0 – координаты первой точки;
x1,y1 – координаты второй точки;
color – цвет заполнения:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция draw_row() заполняет строку указанным цветом между двумя точками строки.
Синтаксис:

TVOut.draw_row(row,x0,x1,color);
Параметры:

row – вертикальная координата строки;
x1,x2 – горизонтальный координаты точек строки;
color – цвет заполнения:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция draw_column() заполняет строку указанным цветом между двумя точками столбца.
Синтаксис:

TVOut.draw_column(column,y0,y1,color);
Параметры:

column – горизонтальная координата столбца;
y1,y2 – вертикальные координаты точек столбца;
color – цвет заполнения:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция draw_rect() рисует на экране прямоугольник.
Синтаксис:

TVOut.draw_rect(x,y,w,h,color);
TVOut.draw_rect(x,y,w,h,color,fillcolor);

Параметры:

x,y – координаты левой верхней точки;
w,h – ширина и высота рисуемого прямоугольника;
color – цвет границ прямоугольника:
0 – черный;
1 – белый;
2 – инвертировать цвет.
fillcolor – цвет заполнения прямоугольника:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция draw_circle() рисует на экране круг.
Синтаксис:

TVOut.draw_ circle(x,y,r,color);
TVOut.draw_ circle(x,y,r,color,fillcolor);

Параметры:

x,y – координаты центра круга;
r – радиус круга;
color – цвет границ круга:
0 – черный;
1 – белый;
2 – инвертировать цвет.
fillcolor – цвет заполнения круга:
0 – черный;
1 – белый;
2 – инвертировать цвет.
Функция bitmap() выводит на экран растровое изображение.
Синтаксис:

TVOut.bitmap(x,y,bmp,w,h);
Параметры:

x,y – координаты левого верхнего угла точки вывода;
bmp – указатель на массив памяти, где хранится картинка;
w,h – ширина, высота выводимого изображения;
Ниже рассмотрим процесс создания кода выводимых растровых изображений.

Функции вывода текстовой информации


Для применения функций вывода текстовой информации требуетя подключение файлов с включенными в библиотеку или пользовательскими шрифтами. Для подключения пользовательского набора шрифтов необходимо в скетче подключить заголовочный файл:
#include
В состав библиотеки включены следующие наборы шрифтов:

font4x6;
font6x8;
font8x8;
font8x8ext.
Функция select_font() выбирает шрифт для вывода текстовой информации.
Синтаксис:

TVOut.select_font(font);
Параметры:

font – шрифт, подключенный в скетче.

Функция print_char() выводит символ на экран.
Синтаксис:

TVOut.print_char(x,y,char);
Параметры:

x,y – позиция на экране для вывода символа;
char – символ из текущего шрифта.

Функция set_cursor() устанавливает позицию курсора для вывода текстовой информации на экран.
Синтаксис:

TVOut.set_cursor(x,y);
Параметры:

x,y – координаты для курсора.
Функция print() выводит на экран строку, символ или число.
Синтаксис:

TVOut.print(x,y,string);
TVOut.print(x,y,char,base);
TVOut.print(x,y,int,base).

Параметры:

x,y – координаты курсора.
base – формат вывода:
BYTE = 0;
DEC = 10 (default);
HEX = 16.

Функция println() выводит на экран строку, символ или число и в конце символ перевода строки:
Синтаксис:

TVOut.println(x,y,string);
TVOut.println(x,y,char,base);
TVOut.println(x,y,int,base).

Параметры:

x,y – координаты курсора.
base – формат вывода:
BYTE = 0;
DEC = 10 (default);
HEX = 16.

Функции вывода аудио


Функции вывода звука позволяют отправлять на телевизор через аудиовыход сигнал определенной частоты.
Функция tone() выдает аудиосигнал определенной частоты.
Синтаксис:

TVOut.tone(frequency,duration);
TVOut.tone(frequency).

Параметры:

frequency – частота аудиосигнала;
duration – длительность сигнала.
Функция noTone() прекращает выдачу аудиосигнала.
Синтаксис:

TVOut.noTone().


Шаг 2. Паяем видеовывод


В первую очередь нам нужно спаять некую плату для вывода видеосигнала через композитный av-выход (RCA). Паяем по следующей схеме:



Расположим два резистора номиналом 470 ом и 1к ом параллельно друг другу и припаяем к ним «плюс» от кабеля-тюльпана. Далее отведем от резистора в 470 ом провод в седьмой пин на Arduino, т.к. он отвечает за вывод видео (video), а от резистора в 1к ом отведем провод в девятый пин, так как он отвечает за синхронизацию (sync). А «минус» от кабеля-тюльпана в «землю» на Arduino. Подробнее тут (англ.)

Шаг 3. Пишем код (игру)


Я не буду объяснять, что да как подключать, ведь необходимую информацию, как всегда, можно найти в интернете. Я описываю то, что очень сложно найти или этого вообще нет.

Начинаем с экрана приветствия, куда без него. Но тут встревает важный вопрос, как назвать сие чудо? Я пораскинул мозгами и придумал — Shimo. Звучит неплохо, даже технологично, по-китайски, конечно, но это не беда.

Дальше вернемся к самой игре. И снова сложный вопрос: какую игру делать? Так как я рукожоп не очень старательный и усердный человек, а также новичок, решил написать Пинг-понг.



Начинаем. Чертим линию через середину экрана с помощью TV.draw_line(60,0,60,96,1);. Появляется шарик ровно в центре экрана. Напишем функцию его движения void ballmove(int vel, int angle). Устанавливаем с помощью TV.set_pixel(x,y,1);, переменные я так и назвал.

Далее перед манипуляциями с шариком прописываем обновление экрана, а точнее, чтобы шарик не «наследил» на экране, поэтому при переходе на следующую позицию нужно закрашивать черным предыдущую. Для этого нам нужно прописать перед всем остальным TV.set_pixel(x,y,0);. После всех изменений переменных координат нужно прописать уже установку позиции и небольшую задержку — TV.delay(50);. Примерно вот так должно получиться:

void ballmove(int vel, int angle)
{
  TV.set_pixel(x,y,0);
  //Манипуляции с координатами
  TV.set_pixel(x,y,1);
}

Теперь о самих изменениях координат. Всего восемь направлений (1-8), переменная int angle. А там уже просто, в зависимости от поворота, отнимаем или прибавляем к переменным какую-либо часть от int velocity. Я сделал так:

 if(angle == 1)
  {
    y -= vel;
  }
  if(angle == 3)
  {
    x += vel;
  }
  if(angle == 5)
  {
    y += vel;
  }
  if(angle == 7)
  {
    x -= vel;
  }
  if(angle == 2)
  {
    x += round(vel/2);
    y -= round(vel/2);
  }
  if(angle == 4)
  {
    x += round(vel/2);
    y += round(vel/2);
  }
  if(angle == 6)
  {
    x -= round(vel/2);
    y += round(vel/2);
  }
  if(angle == 8)
  {
    x -= round(vel/2);
    y -= round(vel/2);
  }

Теперь движения ракеток. Здесь важное уточнение — я использовал только координаты по y, так как позиции ракеток по x не изменяются. Прописываем следующую функцию void racketsmove(). Далее рисуем ракетки, переменные int yb1, int yb2, TV.draw_line(10, yb1+8, 10, yb1-8, 1); и TV.draw_line(110, yb2+8, 110, yb2-8, 1);. Обновление экрана, то есть «без следа», аналогично случаю с шариком.

Управление ракетками производится с кнопок. Подключаем кнопки, пины 2 и 3 — первая ракетка, 4 и 5 — вторая ракетка. Проверяем нажатие кнопок и изменяем координаты.

Вот такая функция:

void racketsmove()
{
  TV.draw_line(10, yb1+8, 10, yb1-8, 0);
  TV.draw_line(110, yb2+8, 110, yb2-8, 0);
  if((yb1 - 8) > 1)
  {
    if(digitalRead(2) == HIGH)
    { yb1 -= 2;}
  }
  if((yb1 + 8) < 95)
  {
    if(digitalRead(3) == HIGH)
    {yb1 += 2;}
  }
  if((yb2 - 8) > 1)
  {
    if(digitalRead(4) == HIGH)
    {yb2 -= 2; }
  }
  if((yb2 + 8) < 95)
  {
    if(digitalRead(5) == HIGH)
    {yb2 += 2;}
  }
  TV.draw_line(10, yb1+8, 10, yb1-8, 1);
  TV.draw_line(110, yb2+8, 110, yb2-8, 1);
}

Сейчас снова вернемся к ball. Теперь пропишем его коллизию и отталкивание от стен и ракеток. Функция — void ballcol(). Для этого просто проверяем его местонахождение относительно объектов, а потом и его угол. Затем этот угол изменяем на другой. С углом легко угадать.
Угол отражения равен углу падения
Можно сделать некоторые физические исключения для определенных зон ракеток.

Функция:

void ballcol()
{
  if(x == 1 || x == 119 || (x == 10 && y < (yb1 + 3) && y > (yb1 - 3)) || (x == 110 && y < (yb2 + 3) && y > (yb2 - 3)))
  {
    if(a==1){a=5;}else if(a==2){a=8;}else if(a==3){a=7;}else if(a==4){a=6;}else if(a==5){a=1;}else if(a==6){a=4;}else if(a==7){a=3;}else if(a==8){a=2;}
  }
  if(x == 10 && y < (yb1 - 3) && y > (yb1 - 8))
  {
    a = 2;
  }
  if(x == 10 && y > (yb1 + 3) && y < (yb1 + 8))
  {
    a = 4;
  }
  if(x == 110 && y < (yb2 - 3) && y > (yb2 - 8))
  {
    a = 8;
  }
  if(x == 110 && y > (yb2 + 3) && y < (yb2 + 8))
  {
    a = 6;
  }
  if(y == 95 || y == 1)
  {
    if(a==1){a=5;}else if(a==2){a=4;}else if(a==3){a=7;}else if(a==4){a=2;}else if(a==5){a=1;}else if(a==6){a=8;}else if(a==7){a=3;}else if(a==8){a=6;}
  }
}

Самое сложное позади, можете успешно вздохнуть.

На данный момент нам остается только сделать систему подсчета баллов, таймер и рестарт.

Начнем с таймера. Есть переменная секунд float ts (в ней хранится абсолютно все время), переменная int tm (количество минут, которые мы получаем из ts). Задаем значение tm операцией tm = ts/60;. И выводим значения на экран, TV.print(81,1,tm); TV.print(97,1,"."); TV.print(100,1,int(ts-(tm*60)));.

Продолжим. Функция рестарта, называем void restart(). Здесь мы возвращаем изначальные значения переменных.

Код:

void restart()
{
  TV.clear_screen();
  x = 60;
  y = 48;
  yb1 = 48;
  yb2 = 48;
  a = 8;
  ts = 900.0;
  c1 = 0;
  c2 = 0;
}

Финал, система подсчета баллов, она чересчур проста. Открываем гугл и вбиваем «Правила игры в настольные теннис». Ищем, за что очки даются. Находим часть про штрафы, а дальше мы успешно находим следующее: «Очко считается выигранным, если противник не успеет отразить правильно посланный ему мяч после первого отскока». Назревает вопрос, как отсчитывать удары и прочее?.. А удары и не нужно отсчитывать, ведь наш пинг-понг с двухмерной графикой.

Мы спокойно находим выход из положения и, как всегда, просто проверяем координаты относительно боковых стенок. Если происходит столкновение, то начисляем балл игроку на противоположной стороне поля. Функция — void ballscount(). Когда выйдет таймер — мы сравниваем баллы первого игрока (переменная int c1) и второго игрока (переменная int c2), объявляем победителя, делаем задержку и вызываем рестарт.

Код:

void ballscount()
{
  if(x == 1)
  {
    c2++;
  }
  if(x == 119)
  {
    c1++;
  }
  if(c1 > c2 && ts == 0)
  {
    TV.println(10, 45, "Player 1 won!");
    delay(10000);
    restart();
  }
  else if(c1 < c2 && ts == 0)
  {
    TV.println(10, 45, "Player 2 won!");
    delay(10000);
    restart();
  }
  else if(c1 == c2 && ts == 0)
  {
    TV.println(10, 45, "You are equal");
    delay(10000);
    restart();
  }

Вот и все, друзья, мы полностью написали код игры. Получилось довольно забавно и можно поиграть.



Для ленивых я просто напишу весь код.

Полный скрипт
Всего 218 строк.
#include <TVout.h>
#include <fontALL.h>
 
TVout TV;
int x, y, a, c1, c2, yb1, yb2, tm, tsh, s;
float ts;
boolean paused = false;
 
void setup ( )
{
  TV.begin(NTSC, 120, 96);
  TV.clear_screen();
  TV.select_font(font6x8);
  TV.println( 0, 50, "Welcome to Shimo" );
  TV.delay (5000);
  TV.clear_screen();
  x = 60;
  y = 48;
  yb1 = 48;
  yb2 = 48;
  a = 8;
  ts = 900.0;
  s = 2;
}
 
void loop ( )
{
  if(!paused)
  {
    TV.draw_line(60,0,60,96,1);
    TV.select_font(font8x8);
    racketsmove();
    ballscount();
    TV.print(1,1,c1); TV.print(18,1,":"); TV.print(26,1,c2);
    tm = ts / 60;
    ts -= 0.04;
    if(ts < 0)
    {
      ts = 0;
    }
    TV.draw_rect(81,1,38,10,0,0);
    TV.print(81,1,tm); TV.print(97,1,"."); TV.print(100,1,int(ts-(tm*60)));
    ballcol();
    /*if(ts < 600)
    {
      s = 4;
    }
    if(ts < 300)
    {
      s = 6;
    }*/
    ballmove(s, a);
    TV.delay(50);
    if(digitalRead(6) == HIGH)
    {
      paused = true; 
      delay(1000);
    }
  }
  else
  {
    TV.println(40,4,"pause");
    if(digitalRead(6) == HIGH)
    {
      paused = false;
      delay(1000);
      TV.clear_screen();
    }
  }
}

void ballscount()
{
  if(x == 1)
  {
    c2++;
  }
  if(x == 119)
  {
    c1++;
  }
  if(c1 > c2 && ts == 0)
  {
    TV.println(10, 45, "Player 1 won!");
    delay(10000);
    restart();
  }
  else if(c1 < c2 && ts == 0)
  {
    TV.println(10, 45, "Player 2 won!");
    delay(10000);
    restart();
  }
  else if(c1 == c2 && ts == 0)
  {
    TV.println(10, 45, "You are equal");
    delay(10000);
    restart();
  }
}

void ballcol()
{
  if(x == 1 || x == 119 || (x == 10 && y < (yb1 + 3) && y > (yb1 - 3)) || (x == 110 && y < (yb2 + 3) && y > (yb2 - 3)))
  {
    if(a==1){a=5;}else if(a==2){a=8;}else if(a==3){a=7;}else if(a==4){a=6;}else if(a==5){a=1;}else if(a==6){a=4;}else if(a==7){a=3;}else if(a==8){a=2;}
  }
  if(x == 10 && y < (yb1 - 3) && y > (yb1 - 8))
  {
    a = 2;
  }
  if(x == 10 && y > (yb1 + 3) && y < (yb1 + 8))
  {
    a = 4;
  }
  if(x == 110 && y < (yb2 - 3) && y > (yb2 - 8))
  {
    a = 8;
  }
  if(x == 110 && y > (yb2 + 3) && y < (yb2 + 8))
  {
    a = 6;
  }
  if(y == 95 || y == 1)
  {
    if(a==1){a=5;}else if(a==2){a=4;}else if(a==3){a=7;}else if(a==4){a=2;}else if(a==5){a=1;}else if(a==6){a=8;}else if(a==7){a=3;}else if(a==8){a=6;}
  }
}

void racketsmove()
{
  TV.draw_line(10, yb1+8, 10, yb1-8, 0);
  TV.draw_line(110, yb2+8, 110, yb2-8, 0);
  if((yb1 - 8) > 1)
  {
    if(digitalRead(2) == HIGH)
    {
      yb1 -= 2;
    }
  }
  if((yb1 + 8) < 95)
  {
    if(digitalRead(3) == HIGH)
    {
      yb1 += 2;
    }
  }
  if((yb2 - 8) > 1)
  {
    if(digitalRead(4) == HIGH)
    {
      yb2 -= 2;
    }
  }
  if((yb2 + 8) < 95)
  {
    if(digitalRead(5) == HIGH)
    {
      yb2 += 2;
    }
  }
  TV.draw_line(10, yb1+8, 10, yb1-8, 1);
  TV.draw_line(110, yb2+8, 110, yb2-8, 1);
}

void ballmove(int vel, int angle)
{
  TV.set_pixel(x,y,0);
  if(angle == 1)
  {
    y -= vel;
  }
  if(angle == 3)
  {
    x += vel;
  }
  if(angle == 5)
  {
    y += vel;
  }
  if(angle == 7)
  {
    x -= vel;
  }
  if(angle == 2)
  {
    x += round(vel/2);
    y -= round(vel/2);
  }
  if(angle == 4)
  {
    x += round(vel/2);
    y += round(vel/2);
  }
  if(angle == 6)
  {
    x -= round(vel/2);
    y += round(vel/2);
  }
  if(angle == 8)
  {
    x -= round(vel/2);
    y -= round(vel/2);
  }
  TV.set_pixel(x,y,1);
}
void restart()
{
  TV.clear_screen();
  x = 60;
  y = 48;
  yb1 = 48;
  yb2 = 48;
  a = 8;
  ts = 900.0;
  c1 = 0;
  c2 = 0;
}


Шаг 4. Вырезаем корпус


Решил вырезать корпус на лазерном резаке (или фрезеровщике, я точно не знаю) из фанеры в 4mm. Нарисовал в InkScape, немного пошаманил и перевел в формат фрезеровщика.



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

Вывод


В процессе работы была создана простая игровая телевизионная игровая приставка на Arduino со стандартной игрой Ping Pong, с двумя геймпадами, в которую мы можем поиграть и даже залипать.

Дополнительные источники и Примечания



1. Информация про библиотеку
2. Информация про порты подключения
3. По некоторым просьбам, изображение обложки было сжато.
Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 30
    +1
    Видеоклип/фото в студию
    +1
    А сколько памяти занял скетч?
      0
      пробовали ли вы поставить разрешение больше 128*96?
        0
        Я не пробовал, но раз на программном уровне дается такая возможность, то, наверное, от этого хуже не станет…
        0
        Если мне память не изменяет, то треть от всей памяти
          0
          Большая часть — это библиотека
        +2
        Я удивился что Arduino успевает формировать видеосигнал, даже такого низкого разрешения.
        Лет 15 тому назад я сделал простой текстово-графический видеоконтроллер на ПЛИС Altera, который формировал видеосигнал 640х480. Но там формирование видео сигнала распаралеливалось и конвееризировалось, и схема получилась не самая простая.
        А тут простенький классический процессор общего назначения, работающий на частоте ниже моей ПЛИС, без всякого распаралеливания и конвееризации, все операции делает последовательно и все успевает. Круто!
          +2
          Вы можете написать про это пост, я с удовольствием прочитаю
            +2
            Игру ping-pong когда то и на простой 155 логике делали энтузиасты в 80-е годы.
            Ладно создать видеосигнал. Без сигналов цветности это не сложно.

            Я встречал проект, в котором аналоговое видео с камеры наблюдение на ATMega 8-и разрядном оцифровывается.
            Правда только черно белое и с ограниченной размерностью и количеством кадров в сек.

            Google «Оцифровка видео ATMega»

              0
              Да-да, спасибо, уже посмотрел, но правда мне данная возможность оцифровки не очень подходит.
              0
              У нас ребята на втором циклоне реализовали змейку, без фрейм буфера, схема получилась не очень большая работает под 1280х1024.
                0
                Довольно интересно, кстати, мне кажется, что в этой библиотеки буфер не используется и сигнал прямо отправляется на тв, но это только мои догадки…
                0
                Я как-то на Pic18 делал тетрис с выводом цветного видеосигнала. Хитрость была в том, что генерировались RGB сигналы и подавались в телевизор через Scart. Т.е. по вычислительной сложности это было не труднее, чем вывести черно-белую картинку.
                  0
                  Если есть об этом какая-либо информация, то можете мне дать ссылки на источники, я почитаю, возможно мне это поможет в совершенствовании данного проекта и разработки новых.
                    0
                    Вот, выложил на github все, что у меня есть из исходников: github.com/Dovgalyuk/PicTetris
                    Схемы нет, но там ничего особенного — к контроллеру просто подключены разъем SCART и джойстик от Dendy.
                    Еще информация про такие вещи есть здесь: www.rickard.gunee.com/projects/video/pic/howto.php
                      0
                      Спасибо большое
                  0
                  640х480

                  В этом, наверное, и дело? Перемножаем 640*480*25 кадров и получаем пиксельклок в 7.5 МГц. Ардуина не вытянет, разве что если ничем иным, кроме вывода на экран, заниматься не будет. А если речь идет о VGA (уж больно разрешение на это намекает), то там и частота кадров обычно выше, и цвет имеется.
                    0
                    Я читал на американском форуме про вывод через VGA. В принципе, изображение выводится с тем же разрешением, что и у меня, но уже цветное.
                      0
                      Да, это был обычный ЭЛТ VGA монитор. Цветов у меня было 8. Еще курсор от мышки был.
                      Каждый пиксель соответствовал то ли 20 то ли 40 наносекундам.

                      Кстати, наверное есть сейчас какие нибудь копеечные готовые решение, которые реализуют аппаратный видеоконтроллер для Ардуино. Надо поискать.
                        0
                        Хорошо. Поищу, если что, то я находил уже готовую плату для вывода такого типа изображения, но 50 баксов слишком дорогая цена
                    0
                    Статье, для тех у кого сейчас ограничения по скорости интернета, не хватает фотографии готового устройства с джойстиками.
                      0
                      На обложке используется габаритная фотка с одной макеткой вместо геймпадов. Я их попросту не присоедил. Подумываю сделать ракетки с акселлерометрами в качестве контроллеров
                      +2
                      Круто! Было бы интересно посмотреть на реализацию чего-то «потяжелее». Когда изучал вопрос VGA вывода при помощи Arduino встретил реализацию вывода через антенный кабель. Но там всё было жёстко завязано на такты, из-за чего после любого изменения игровой логики приходилось менять конечный delay до следующего кадра, что было весьма неудобно.
                      Недавно делал вывод на Altera Cyclone III, оказалось гораздо проще чем на Arduino:
                        0
                        Я смотрел вывод через VGA, но у меня возникло много вопросов, а еще, по-моему, телевизионная игровая приставка теряет часть от своего названия, именно, что она ТВ, а не VGA или «мониторная». К тому же, я хочу сделать, в качестве следующего проекта, умные часы или голосовую систему управления.
                        0
                        Спасибо, интересный проект!

                        Если смотреть на тему Ардуино и игровых приставок, то есть открытый (released under BSD license) проект gameduino2, Arduino+FT800 (сенсорный экран):
                          +1
                          Интересно, довольно классно и игровая логика просчитана, но для такого проще будет написать целый движок с компилятором и программатором для Arduino. К тому же, я хочу сделать, в качестве следующего проекта, умные часы или голосовую систему управления.
                            0
                            А есть ещё и раритетный CHIP-8 который имхо можно запилить на Ардуину, он как раз черно-белый и не особо замороченный.
                              0
                              Как вариант…

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

                        Самое читаемое