Библиотека VGAX для Arduino UNO

Добавлено 27 июня 2018 в 07:57

Что такое VGAX?

Это VGA библиотека для Arduino UNO. Для использования данной библиотеки вам необходимы только 4 резистора и один разъем DSUB15. Данная библиотека требует микроконтроллер ATmega328 (или выше), она не работает с семейством ATtiny и ATmega168.

Вывод изображения с помощью библиотеки VGAX для Arduino UNO
Вывод изображения с помощью библиотеки VGAX для Arduino UNO

Youtube видео:

Некоторые фотографии:

Вывод изображения с помощью библиотеки VGAX для Arduino UNO
Вывод изображения с помощью библиотеки VGAX для Arduino UNO
Макет
Макет
Подключение разъема DSUB15 к Arduino UNO
Подключение разъема DSUB15 к Arduino UNO

Содержание:

Загрузки:

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

Видео

Данная библиотека реализует кадровый буфер 120x60px, где каждый пиксель хранится как 2 бита (четыре цвета). Кадровый буфер хранится внутри SRAM и требует 1800 байтов. Ваша программа не может использовать более 200 байтов, поэтому будьте внимательны! Если хотите, то можете использовать другую плату Arduino UNO для управления платой, которая использует библиотеку VGAX.

Кадровый буфер VGAX использует 2 бита для каждого пикселя. Внутри каждого байта хранится 4 пикселя, упакованных в следующем порядке: самый левый пиксель – это самые старшие 2 бита, самый правый пиксель – это самые младшие 2 бита:

Порядок хранения пикселей в байте кадрового буфера
Порядок хранения пикселей в байте кадрового буфера

Аудио

Данная библиотека также реализует асинхронную генерацию тона (аудио)! Аудиосигнал генерируется во время примерно 15 периодов тактового сигнала, внутри задней площадки строчного гасящего импульса VGA. Качество этого сигнала плохое, но его можно использовать для воспроизведения некоторых мелодий. Для управления длительностью нот вы можете использовать методы tone(frequency) и noTone(). Ваш зуммер должен быть подключен к выводу A0.

Подключение

Вам необходимы:

  • 2 x резистор 470 Ом
  • 2 x резистор 68 Ом
  • 1 x разъем DSUB15 (мама)

Подключите их, как показано на следующей схеме.

Примечание: разъем DSUB15 показан с задней стороны.

Схема организации VGA интерфейса на Arduino UNO
Схема организации VGA интерфейса на Arduino UNO

4 цвета

4 цвета, генерируемые библиотекой, не предопределены.

Вы может соединить PIN6 и PIN7 с двумя RGB выводами разъема VGA DSUB15, выбрав комбинацию цветов, которую предпочитаете.

Ниже приведены некоторые из возможных комбинаций, которые реализуются без дополнительных компонентов:

Комбинация цветов 0
Комбинация цветов 0
Комбинация цветов 1
Комбинация цветов 1
Комбинация цветов 2
Комбинация цветов 2
Комбинация цветов 3
Комбинация цветов 3
Комбинация цветов 4
Комбинация цветов 4
Комбинация цветов 5
Комбинация цветов 5

Выводы и порты

Генерирование видео реализовано при использовании порта PORTD, поэтому вы не можете использовать любые выводы на PORTD.

Сигнал вертикальной синхронизации генерируется на выводе 9. Версия от Гаммона использует вывод 10, но я предпочитаю сохранить выводы 10, 11, 12, 13 для использования SPI.

Прерывания

Библиотека VGAX генерирует видеосигнал, используя только прерывания, поэтому внутри функции main(), вы можете делать что угодно. Ваш код будет прерываться, когда необходимо будет сгенерировать VGA сигнал.

Оригинальный код от Ника Гаммона генерирует пиксели строки внутри main(). Я предпочитаю генерировать строку внутри прерываний, чтобы оставить микроконтроллер свободным для других вещей, например, запуск игр или проигрывание звуков.

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

Таймеры

Данная библиотека использует все 3 таймера микроконтроллера ATmega328.

TIMER1 и TIMER2 настроены для генерирования импульсов HSYNC и VSYNC. Код настройки этих двух таймеров написан Ником Гаммоном. Я сделал только несколько изменений для использования вывода 9 вместо вывода 10.

TIMER0 используется для исправления джиттера прерываний. Я изменил ассемблерный код, изначально написанный Charles CNLOHR.

По умолчанию TIMER0 используется на Arduino для реализации следующих функций:

unsigned millis();
unsigned long micros();
void delay(ms); 
void delayMicroseconds(us);

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

Использование библиотеки

Чтобы воспользоваться библиотекой, вам необходимо включить ее заголовочный файл.

#include <VGAX.h>

Класс VGAX – статический, поэтому вы можете использовать его без создания его объекта:

void setup() 
{
  VGAX::begin();
}

Или, если предпочитаете, вы можете создать собственный объект, но помните, что в какой-либо момент времени не может быть более одного объекта VGAX:

VGAX vga;

void setup() 
{
  vga.begin();
}

Пиксель

Это простой пример использования функции putpixel4. Функция putpixel4 помещает за раз 4 пикселя. Следующий код создает шаблон цветов в функции setup:

#include <VGAX.h>

VGAX vga;

void setup() 
{
  vga.begin();
  vga.clear(11);
  for (int y=0; y!=VGAX_HEIGHT; y++) 
  {
    for (int x=0; x!=VGAX_BWIDTH; x++) 
    {
      vga.putpixel4(x, y, y%2 ? 27 : 228);
    }
  }
}

void loop() 
{
}

Изображения

Пример изображения
Пример изображения

Данный пример показывает функцию copy. Функция copy копирует все пиксели из массива байтов. Массив должен быть сохранен в PROGMEM, и размер этого массива должен быть равен размеру кадрового буфера VGAX:

VGAX_BWIDTH * VGAX_HEIGHT
(30 * 60)

Обратите внимание, что размер в байтах рассчитывается с помощью BWIDTH вместо WIDTH, поскольку пиксели упакованы в байты (4 пикселя в одном байте).

#include <VGAX.h>

//изображение, созданное с помощью 2BITIMAGE - Sandro Maffiodo
#define IMG_PIRATE_BWIDTH 30
#define IMG_PIRATE_HEIGHT 60

//размер данных = 900 байтов
const unsigned char img_pirate_data[IMG_PIRATE_HEIGHT*IMG_PIRATE_BWIDTH] PROGMEM={
    0,  7,255,192,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0, 63,252,  6, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,192,  0,  0,  0,  0,  0,
    2,255,112, 96,129,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
   15,222,  2,  4,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  0,  0,  0,  0,  0,  0,
  255,240,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
  252, 65,144, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,
  248,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,144,  0,  0,  0,  0,  0,  0,
   65,132,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,
    0, 16, 16,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  0,  0,  0,  0,  0,  0,  0,
   36,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0,
   65,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,  0,
    8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,  0,
   16,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,192,  0,  0,  0,  0,  0,  0,  0,  0,
   32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,130,168,160,  0, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 34,138, 42, 32,  0,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
   16,  0,  0,  0,  0,  0,  0,  0,  0, 34, 34, 34,136, 32,130,  0,  0, 32,  0,  0,  0,  1, 69, 64, 80,  0, 20,  5,  4,  0,
   32,  0,  0,  0,  0,  0,  0,  8,170,160,  0,  0,170,170, 40, 42,170,136,  0,  0,  0,  0, 64, 17,  4, 68, 64, 16, 68,  0,
    0,  0,  0,  0,  0,  0,  0,162, 10,  2,170,170,170,170,168, 32,  0, 34,  0,  0,  0,  0, 65, 65,  4, 16, 84, 16, 68,  0,
   64,  0,  0,  0,  0,  0, 10,130,171,239,255,238,170,170,160,162,170,162,  0,  0,  0,  0, 68,  1,  4, 16, 65, 16, 64,  0,
   36,  0,  0,  0,  0,  0,  8, 42,187,250,170,170,187,238,250,  0,  0, 34,  0,  0,  0,  0, 69, 80, 80, 68, 20,  5,  4,  0,
    0,  0,  0,  0,  0,  0, 34,170,255,234,170,170,171,187,178, 60,  0,170,160,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  152,  0,  0,  0,  0,  0,  0,171,254,170,  0,  2,186,255,248, 61,  3,  2, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1,196,  0,  0,  0,  0, 10,187,254,168,112,  4,171,191,248, 54,  0, 40,136,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  8,198, 96,  0,  0, 42,191,250,163,240, 14,174,255,254,136,170,138, 34,128,  1,128,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,139,191,250,168, 53, 26,171,255,252,138, 34,186,162,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0, 42,251,250,170,170,170,174,191,254, 34,187,174,232,128,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  2,170,174,255,186,170,170,187,255,255, 34,234,251,170,128,  0,128,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  1,  0,  0,138,187,187,171,170,238,187,191,255,138,175,255,238, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0, 10,239,255,186,186,170,238,239,255,224,235,255,250, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0, 46,175,255,255,238,186,190,255,255,248,171,255,250,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,170,191,255,255,250,171,187,239,255,254, 42,255,238, 32,  0,144,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0, 42,238,255,255,251,170,174,187,255,254,174,190,234,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  1,128,  0,  0,174,187,255,255,254,235,171,255,255,254, 10,171,170,128,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0, 32,  0,  0,  0,138,174,255,255,255,186,163,255,255,255,162,186,186,128,  0,  4, 36,  0,  0,  0,  0,  0,  0,  0,
    0,  4,  0,  0,  0,  0, 43,187,239,255,254,170,234,170,174,234, 34, 42,168,  0,  0,  8,  2,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0, 10,174,186,255,251,171,168,128, 10,128,  2, 34,226,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,
    0,  0, 64,  0,  0,  0,  2,171,239,187,254,234,170, 40,  0,  0,  0, 40, 32,  0,  0,  2,170,168,  0,  0,  0,  0,  0,  0,
    0,  0, 40,  0,  8,  0,  0, 42,190,239,190,186,128,  0,  0,  0,  0,  0,160,  0,  0, 64,170,170,160,  0,  0,  0,  0,  0,
    0,  2,160,  0, 60,  0,  0, 42,171,190,250,168,  0,  0, 10,170,168,  0,  0,  0,  0,128, 16, 10,168,  0,  0,  0,  0,  0,
    0, 42,128,  2,240,  0,  0,130,234,186,170,160,  0,170,170,170,174,128,  0,  0,  0,  6,  0,170,170,128,  0,  0,  0,  0,
    0,170,128, 47,  0,  0,  0, 10, 42,170,170,128, 42,170,175,255,250, 32,  0,  0,  1,  0, 42,170,170,168,  0,  0,  0,  0,
   10,170, 64, 40, 48,  0,  0,  0, 40,162,170,  0,171,255,255,255,234,136,  0,  0,  2,  0,  2,170,170,170,  0,  0,  0,  0,
  170,170,  0,160,176,  0,  0,  0,  0,130,168,  2,191,186,175,250,170, 32,  0,  0,  1, 56,  0,170,170,170,  0,  0,  0,  0,
  170,170,130,130, 64,  0,  0,  0,  2,  8,168, 10,239,255,234,170,170,136,  0,  0, 16, 60,128,170,170,170,  0,  0,  0,  0,
  170,170,128,138,  0, 60,  0,  0,  0,  8, 32,  2,255,255,255,234,186,128,  0,  0,  0,  7,232, 42,170,170,128,  0,  0,  0,
  170,170,160,168,  0,252,  0,  0,  0,  0,  0, 10,175,255,255,251,170,128,  0,  0,  0,  0, 26, 42,170,170,128,  0,  0,  0,
  170,170,168,  8,  0,240, 32,  0,  0,  0,  0,  8,190,187,235,238,168, 32,  0,  0,  0,  0,  4,170,170,170,160,  0,  0,  0,
  170,170,160,170,  0,240,192,  0,  0,  0,  0,  0,170,254,238,170,186,  0,  0,  0,  0,  0, 72, 42,170,170,168,  0,  0,  0,
  170,168,  0,170,128,  2, 64,  0,  0,  0,  0,  0,  2,171,170, 58,160,  0,  0,  0,  0,  0,  2, 10,170,170,170,128,  0,  0,
  170,170, 42,170,168,  3,  0,  0,  0,  0,  0,  0,  2, 10, 42,  8,  0,  0,  0,  0,  0,  0,  1, 42,170,170,170,168,128,  0,
  170,170,170,170,169,  8,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0, 18, 42,170,170,170,170,168,  0,
  170,170,170,170,168,  4,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 54,128,  0, 42,170,170,170,170,170,  0,
  170,170,170,168, 36, 11,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,188, 96, 15,170,170,170,170,170,170,  0,
  170,170,170,170,  0,130, 14, 96,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0, 95,  0, 63,234,170,170,170,170,170,128,
  170,170,170,170,170,170,143,255,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12,  0,  0,249,240, 63,234,170,170,170,170,170,128,
  170,170,170,170,170,170,144, 63,240,  0,  0,  0,  0, 65,  0,  0,  0, 15,192,  0, 63,144, 63,170,170,170,170,170,170,160,
  170,170,170,170,170,170,175,239,240,  0,  1,  0,  0,  2, 24,  0,  0, 15,252,  0,  7,228, 15,218,170,170,170,170,170,168,
  170,170,170,170,170,170,168,255,240, 48, 64,  0, 13,129,  1,  0,  0,  3,255,  0,  0,114, 15,250,170,170,170,170,170,170,
  170,170,170,170,170,170,170, 62,192,188,  0,  0, 63,126,192, 36,  0,  2,127,208,  0,185,191,250,170,170,170,170,170,170,
};

VGAX vga;

void setup() 
{
  vga.begin();
  vga.copy((byte*)img_pirate_data);
}

Спрайты

Пример спрайта
Пример спрайта

Смотрите Example of a masked blit implementation.

#include <VGAX.h>

// изображение, созданное 2BITIMAGE - Sandro Maffiodo
#define IMG_MARIOMASK_WIDTH 16
#define IMG_MARIOMASK_BWIDTH 4
#define IMG_MARIOMASK_HEIGHT 16
#define IMG_MARIOMASK_SPRITES_CNT 5

// размер данных = 512 байтов
const unsigned char img_mariomask_data[IMG_MARIOMASK_SPRITES_CNT][IMG_MARIOMASK_HEIGHT][IMG_MARIOMASK_BWIDTH] PROGMEM={
{ { 255, 255, 255, 255, }, { 255, 192,   3, 255, }, { 255,   0,   0,  63, }, { 252,   0,   0,  15, }, { 252,   0,   0,  63, }, { 240,   0,   0,  15, }, { 240,   0,   0,  15, }, { 252,   0,   0,  63, }, { 255,   0,   0, 255, }, { 252,   0,   3, 255, }, { 240,   0,   0, 255, }, { 240,   0,   0, 255, }, { 252,   0,   0, 255, }, { 252,   0,   3, 255, }, { 255,   0,   3, 255, }, { 255,   0,   3, 255, }, },
{ { 255, 255, 255, 255, }, { 255, 192,   3, 255, }, { 255,   0,   0,  63, }, { 252,   0,   0,  15, }, { 252,   0,   0,  63, }, { 240,   0,   0,  15, }, { 240,   0,   0,  15, }, { 252,   0,   0,  63, }, { 255,   0,   0, 255, }, { 252,   0,   0,  63, }, { 252,   0,   0,  15, }, { 240,   0,   0,  15, }, { 240,   0,   0,  63, }, { 252,   0,   0,  63, }, { 252,   0,   0,  63, }, { 255,   3, 192, 255, }, },
{ { 255, 192,  15, 255, }, { 255,   0,   0,  63, }, { 252,   0,   0,  15, }, { 252,   0,   0,  63, }, { 240,   0,   0,  15, }, { 240,   0,   0,  15, }, { 252,   0,   0,  63, }, { 252,   0,   0, 255, }, { 192,   0,   0,  63, }, {   0,   0,   0,  15, }, {   0,   0,   0,   3, }, { 192,   0,   0,   3, }, { 240,   0,   0,  15, }, { 192,   0,   0,  15, }, { 192,   3,   0,  63, }, { 240,   3, 192, 255, }, },
{ { 255, 192,  15,   3, }, { 255,   0,   0,   0, }, { 252,   0,   0,   0, }, { 252,   0,   0,   3, }, { 240,   0,   0,   3, }, { 240,   0,   0,   3, }, { 252,   0,   0,  15, }, { 252,   0,   0,  15, }, { 240,   0,   0,  63, }, { 192,   0,   0,   3, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, { 192,   0,   0,   3, }, {   0,   0,   0,   3, }, {   0,   0,  63,  15, }, { 195,   3, 255, 255, }, },
{ { 255, 192,   3, 255, }, { 252,   0,   0,  63, }, { 240,   0,   0,  15, }, { 192,   0,   0,   3, }, { 192,   0,   0,   3, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, { 192,   0,   0,   3, }, { 240,   0,   0,  15, }, { 240,   0,   0,  15, }, { 252,   0,   0,  63, }, { 255,   0,   0, 255, }, },
};

// изображение, созданное 2BITIMAGE - Sandro Maffiodo
#define IMG_MARIO_WIDTH 16
#define IMG_MARIO_BWIDTH 4
#define IMG_MARIO_HEIGHT 16
#define IMG_MARIO_SPRITES_CNT 5

// размер данных = 1408 байтов
const unsigned char img_mario_data[IMG_MARIO_SPRITES_CNT][IMG_MARIO_HEIGHT][IMG_MARIO_BWIDTH] PROGMEM={
{ {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,  42, 168,   0, }, {   0, 170, 170, 128, }, {   0,  15,  48,   0, }, {   3, 195,  63, 192, }, {   3, 195, 207, 192, }, {   0,  63,   0,   0, }, {   0,  15, 252,   0, }, {   0, 162, 160,   0, }, {   2, 168, 168,   0, }, {   2, 168,  84,   0, }, {   0, 252,  20,   0, }, {   0, 250, 128,   0, }, {   0,  42, 160,   0, }, {   0,   0,   0,   0, }, },
{ {   0,   0,   0,   0, }, {   0,   0,   0,   0, }, {   0,  42, 168,   0, }, {   0, 170, 170, 128, }, {   0,  15,  48,   0, }, {   3, 195,  63, 192, }, {   3, 195, 207, 192, }, {   0,  63,   0,   0, }, {   0,  15, 252,   0, }, {   0, 162, 162,   0, }, {   0, 168, 168, 128, }, {   3, 232,  20, 192, }, {   3, 192,  20,   0, }, {   0,   0,   2,   0, }, {   0, 168,  42,   0, }, {   0,   0,   0,   0, }, },
{ {   0,   0,   0,   0, }, {   0,  42, 160,   0, }, {   0, 170, 170, 128, }, {   0,  15,  48,   0, }, {   3, 195,  63, 192, }, {   3, 195, 207, 192, }, {   0,  63,   0,   0, }, {   0,  15, 252,   0, }, {   2, 162, 160,   0, }, {  62, 168, 168, 128, }, {  63, 161,  84, 176, }, {  15,   5,  84,  48, }, {   0,   1,  82, 128, }, {  10,   0,  10, 128, }, {  10, 160,  42,   0, }, {   0,   0,   0,   0, }, },
{ {   0,   0,   0,   0, }, {   0,  42, 160,   0, }, {   0, 170, 170,   0, }, {   0,  15,  48,  32, }, {   3, 195,  63, 224, }, {   3, 195, 207, 224, }, {   0,  63,   0,   0, }, {   0,  15, 255, 128, }, {   2, 162, 162,   0, }, {   0, 168, 168,   0, }, {  63,  40,  85,  40, }, {  63,  33,  84, 168, }, {   0,   4,   0, 160, }, {  42,  16,   0, 160, }, {  40,   0,   0,   0, }, {   0,   0,   0,   0, }, },
{ {   0,   0,   0,   0, }, {   0,  61, 124,   0, }, {   3, 245,  95, 192, }, {   5,  95, 245,  80, }, {   5, 127, 253,  80, }, {  53, 255, 255,  92, }, {  61, 255, 255, 124, }, {  61, 255, 255, 124, }, {  53, 127, 253,  92, }, {  21,  95, 245,  84, }, {  21,   0,   0,  84, }, {   0, 243, 207,   0, }, {   3, 243, 207, 192, }, {   3, 255, 255, 192, }, {   0, 255, 255,   0, }, {   0,   0,   0,   0, }, },
};

VGAX vga;

void setup() 
{
  vga.begin();
  vga.clear(11);
}

void loop() 
{
  static byte sidx=1;
  static unsigned cnt;
  vga.blitwmask((byte*)(img_mario_data[sidx]), (byte*)(img_mariomask_data[sidx]), IMG_MARIO_WIDTH, IMG_MARIO_HEIGHT, rand()%VGAX_WIDTH-IMG_MARIO_WIDTH/2, rand()%VGAX_HEIGHT-IMG_MARIO_HEIGHT/2);
  sidx=sidx==1 ? 2 : 1;
  if (cnt>=180) 
  {
    cnt=0;
    vga.clear(3);
  }
}

Шрифты

Для создания собственных шрифтов вы можете использовать мою утилиту 2bitfont. Я разработал два супермаленьких шрифта, которые могут использоваться совместно с VGAX или в других проектах. Они показаны ниже:

  • ufont.png:
    ufont
  • ufont2.png:
    ufont2

Следующий пример использует первый шрифт.

#include <VGAX.h>

// шрифт, созданный с помощью 2BITFONT - Sandro Maffiodo
#define FNT_UFONT_HEIGHT 6
#define FNT_UFONT_SYMBOLS_COUNT 95

// размер данных =570 байтов
const unsigned char fnt_ufont_data[FNT_UFONT_SYMBOLS_COUNT][1+FNT_UFONT_HEIGHT] PROGMEM={
{ 1, 128, 128, 128,   0, 128,   0, }, //глиф '!' код = 0
{ 3, 160, 160,   0,   0,   0,   0, }, //глиф '"' код = 1
{ 5,  80, 248,  80, 248,  80,   0, }, //глиф '#' код = 2
{ 5, 120, 160, 112,  40, 240,   0, }, //глиф '$' код = 3
{ 5, 136,  16,  32,  64, 136,   0, }, //глиф '%' код = 4
{ 5,  96, 144, 104, 144, 104,   0, }, //глиф '&' код = 5
{ 2, 128,  64,   0,   0,   0,   0, }, //глиф ''' код = 6
{ 2,  64, 128, 128, 128,  64,   0, }, //глиф '(' код = 7
{ 2, 128,  64,  64,  64, 128,   0, }, //глиф ')' код = 8
{ 3,   0, 160,  64, 160,   0,   0, }, //глиф '*' код = 9
{ 3,   0,  64, 224,  64,   0,   0, }, //глиф '+' код = 10
{ 2,   0,   0,   0,   0, 128,  64, }, //глиф ',' код = 11
{ 3,   0,   0, 224,   0,   0,   0, }, //глиф '-' код = 12
{ 1,   0,   0,   0,   0, 128,   0, }, //глиф '.' код = 13
{ 5,   8,  16,  32,  64, 128,   0, }, //глиф '/' код = 14
{ 4,  96, 144, 144, 144,  96,   0, }, //глиф '0' код = 15
{ 3,  64, 192,  64,  64, 224,   0, }, //глиф '1' код = 16
{ 4, 224,  16,  96, 128, 240,   0, }, //глиф '2' код = 17
{ 4, 224,  16,  96,  16, 224,   0, }, //глиф '3' код = 18
{ 4, 144, 144, 240,  16,  16,   0, }, //глиф '4' код = 19
{ 4, 240, 128, 224,  16, 224,   0, }, //глиф '5' код = 20
{ 4,  96, 128, 224, 144,  96,   0, }, //глиф '6' код = 21
{ 4, 240,  16,  32,  64,  64,   0, }, //глиф '7' код = 22
{ 4,  96, 144,  96, 144,  96,   0, }, //глиф '8' код = 23
{ 4,  96, 144, 112,  16,  96,   0, }, //глиф '9' код = 24
{ 1,   0, 128,   0, 128,   0,   0, }, //глиф ':' код = 25
{ 2,   0, 128,   0,   0, 128,  64, }, //глиф ';' код = 26
{ 3,  32,  64, 128,  64,  32,   0, }, //глиф '<' код = 27
{ 3,   0, 224,   0, 224,   0,   0, }, //глиф '=' код = 28
{ 3, 128,  64,  32,  64, 128,   0, }, //глиф '>' код = 29
{ 4, 224,  16,  96,   0,  64,   0, }, //глиф '?' код = 30
{ 4,  96, 144, 176, 128, 112,   0, }, //глиф '@' код = 31
{ 4,  96, 144, 240, 144, 144,   0, }, //глиф 'A' код = 32
{ 4, 224, 144, 224, 144, 224,   0, }, //глиф 'B' код = 33
{ 4, 112, 128, 128, 128, 112,   0, }, //глиф 'C' код = 34
{ 4, 224, 144, 144, 144, 224,   0, }, //глиф 'D' код = 35
{ 4, 240, 128, 224, 128, 240,   0, }, //глиф 'E' код = 36
{ 4, 240, 128, 224, 128, 128,   0, }, //глиф 'F' код = 37
{ 4, 112, 128, 176, 144, 112,   0, }, //глиф 'G' код = 38
{ 4, 144, 144, 240, 144, 144,   0, }, //глиф 'H' код = 39
{ 3, 224,  64,  64,  64, 224,   0, }, //глиф 'I' код = 40
{ 4, 240,  16,  16, 144,  96,   0, }, //глиф 'J' код = 41
{ 4, 144, 160, 192, 160, 144,   0, }, //глиф 'K' код = 42
{ 4, 128, 128, 128, 128, 240,   0, }, //глиф 'L' код = 43
{ 5, 136, 216, 168, 136, 136,   0, }, //глиф 'M' код = 44
{ 4, 144, 208, 176, 144, 144,   0, }, //глиф 'N' код = 45
{ 4,  96, 144, 144, 144,  96,   0, }, //глиф 'O' код = 46
{ 4, 224, 144, 224, 128, 128,   0, }, //глиф 'P' код = 47
{ 4,  96, 144, 144, 144,  96,  16, }, //глиф 'Q' код = 48
{ 4, 224, 144, 224, 160, 144,   0, }, //глиф 'R' код = 49
{ 4, 112, 128,  96,  16, 224,   0, }, //глиф 'S' код = 50
{ 3, 224,  64,  64,  64,  64,   0, }, //глиф 'T' код = 51
{ 4, 144, 144, 144, 144,  96,   0, }, //глиф 'U' код = 52
{ 3, 160, 160, 160, 160,  64,   0, }, //глиф 'V' код = 53
{ 5, 136, 168, 168, 168,  80,   0, }, //глиф 'W' код = 54
{ 4, 144, 144,  96, 144, 144,   0, }, //глиф 'X' код = 55
{ 3, 160, 160,  64,  64,  64,   0, }, //глиф 'Y' код = 56
{ 4, 240,  16,  96, 128, 240,   0, }, //глиф 'Z' код = 57
{ 2, 192, 128, 128, 128, 192,   0, }, //глиф '[' код = 58
{ 5, 128,  64,  32,  16,   8,   0, }, //глиф '\' код = 59
{ 2, 192,  64,  64,  64, 192,   0, }, //глиф ']' код = 60
{ 5,  32,  80, 136,   0,   0,   0, }, //глиф '^' код = 61
{ 4,   0,   0,   0,   0, 240,   0, }, //глиф '_' код = 62
{ 2, 128,  64,   0,   0,   0,   0, }, //глиф '`' код = 63
{ 3,   0, 224,  32, 224, 224,   0, }, //глиф 'a' код = 64
{ 3, 128, 224, 160, 160, 224,   0, }, //глиф 'b' код = 65
{ 3,   0, 224, 128, 128, 224,   0, }, //глиф 'c' код = 66
{ 3,  32, 224, 160, 160, 224,   0, }, //глиф 'd' код = 67
{ 3,   0, 224, 224, 128, 224,   0, }, //глиф 'e' код = 68
{ 2,  64, 128, 192, 128, 128,   0, }, //глиф 'f' код = 69
{ 3,   0, 224, 160, 224,  32, 224, }, //глиф 'g' код = 70
{ 3, 128, 224, 160, 160, 160,   0, }, //глиф 'h' код = 71
{ 1, 128,   0,   128, 128, 128, 0, }, //глиф 'i' код = 72
{ 2,   0, 192,  64,  64,  64, 128, }, //глиф 'j' код = 73
{ 3, 128, 160, 192, 160, 160,   0, }, //глиф 'k' код = 74
{ 1, 128, 128, 128, 128, 128,   0, }, //глиф 'l' код = 75
{ 5,   0, 248, 168, 168, 168,   0, }, //глиф 'm' код = 76
{ 3,   0, 224, 160, 160, 160,   0, }, //глиф 'n' код = 77
{ 3,   0, 224, 160, 160, 224,   0, }, //глиф 'o' код = 78
{ 3,   0, 224, 160, 160, 224, 128, }, //глиф 'p' код = 79
{ 3,   0, 224, 160, 160, 224,  32, }, //глиф 'q' код = 80
{ 3,   0, 224, 128, 128, 128,   0, }, //глиф 'r' код = 81
{ 2,   0, 192, 128,  64, 192,   0, }, //глиф 's' код = 82
{ 3,  64, 224,  64,  64,  64,   0, }, //глиф 't' код = 83
{ 3,   0, 160, 160, 160, 224,   0, }, //глиф 'u' код = 84
{ 3,   0, 160, 160, 160,  64,   0, }, //глиф 'v' код = 85
{ 5,   0, 168, 168, 168,  80,   0, }, //глиф 'w' код = 86
{ 3,   0, 160,  64, 160, 160,   0, }, //глиф 'x' код = 87
{ 3,   0, 160, 160, 224,  32, 224, }, //глиф 'y' код = 88
{ 2,   0, 192,  64, 128, 192,   0, }, //глиф 'z' код = 89
{ 3,  96,  64, 192,  64,  96,   0, }, //глиф '{' код = 90
{ 1, 128, 128, 128, 128, 128,   0, }, //глиф '|' код = 91
{ 3, 192,  64,  96,  64, 192,   0, }, //глиф '}' код = 92
{ 3,  96, 192,   0,   0,   0,   0, }, //глиф '~' код = 93
{ 4,  48,  64, 224,  64, 240,   0, }, //глиф '£' код = 94
};

VGAX vga;

void setup() 
{
  static const char str0[] PROGMEM="VGAX Hello World!";
  vga.begin();
  vga.clear(11);
  vga.print((byte*)fnt_ufont_data, FNT_UFONT_SYMBOLS_COUNT, FNT_UFONT_HEIGHT, 3, 1, str0, 10, 10, 1);
}

void loop() 
{
}

Аудио

VGAX также генерирует аудиосигналы! Данный пример демонстрирует два метода, которые могут использоваться для генерирования аудиосигналов: tone(frequency) и noTone().

#include <VGAX.h>

VGAX vga;

void setup() 
{
  vga.begin();
}

void loop() 
{
  static unsigned cnt;
  if (!(cnt % 10))
    vga.noTone();
  if (!(cnt++%20))
    vga.tone(cnt*5+11);
  if (cnt>=160)
    cnt=0;
}

Утилиты

2bitimage

2bitimage
2bitimage

Для преобразования изображений в формат VGAX (2 бита на пиксель) я написал простое веб-приложение, которое читает изображение и создает исходный файл C/C++ для использования с VGAX.

Изображение, которое вы можете использовать в исходниках, должно использовать только те цвета, которые вы генерируете аппаратно. Например, если вы используете выводы красного и зеленого цветов, вы должны сначала преобразовать ваше изображение с помощью другой утилиты, поскольку ваше изображение должно использовать только эти четыре цвета: красный, зеленый, желтый и черный. 2bitimage упаковывает из в 2-битный формат, используемый библиотекой VGAX, но не выполняет какого-либо конвертирования цветов.

Исходный файл веб-приложения находится в каталоге tools. Вы можете открыть 2bitimage.html с помощью веб-браузера и запустить его локально. Я использую Google Chrome, поэтому не знаю, работает ли всё с другими браузерами.

2bitfont

2bitfont
2bitfont

С помощью 2bitfont вы можете создавать свои собственные шрифты из одного изображения и конвертировать их для использования с библиотекой VGAX. Утилита читает изображения, которое содержит все символы шрифта, разделенные вертикальной пустой линией. Все символы извлекаются и конвертируются в исходный файл C/C++.

FAQ

  • Как центрировать видеосигнал по горизонтали? В настоящий момент я не смог центрировать сигнал по горизонтали без потери нескольких пикселей или генерации аудиосигнала. Вы можете откалибровать смещение по горизонтали вручную на своем мониторе, или, если на нем есть автокалибровка, использовать ее.
  • Как центрировать видеосигнал по вертикали? Вы можете сделать это, изменяя постоянную RENDERLCOUNT в VGAX.cpp.
  • Как изменить аудиовывод с ANALOG0 на другой? Вы можете изменить этот вывод на другой аналоговый вывод. Изменить эту строку в VGA.cpp:
    pinMode(A0, OUTPUT);
    и измените 1 на другой вывод в ассемблерной строке в том же файле:
    "      ldi r18, 1                       \n\t" //c1
    "      out %[audiopin], r18             \n\t" //c1
    (1 означает A0, 2 означает A1, 4 означает A3, 8 означает A4, и так далее)
  • Как предотвратить мерцание экрана? В настоящий момент нет механизма для предотвращения мерцания. Правильный способ предотвращения мерцания заключается в использовании двойного (кадрового) буфера, но для этого недостаточно памяти.

Теги

ArduinoArduino UnoVGAВидеоГрафикаПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.