Итак, продолжаем развивать проект...
Подключил SD-картридер, схема подключениея такая, как в сообщении #19 zebest, только пока без кнопок и экрана. Да, и вывод сигнала остался на D3.

Скетч


В корень SD-карты положить файл "cybernoi.rom". Если карта не обнаружена, то подаётся сигнал 200Гц/100мс, если не обнаружен файл, то сигнал 200Гц/300мс.
Код:
/*
 * SD-картридер подключяется к выводам ардуино:
 ** MOSI  - D11
 ** MISO  - D12
 ** CLK   - D13
 ** CS    - D10
 *
 *  Выход - D3
 */
#include <SD.h>

File romFile;

// Заголовок
byte SB[27] = { 
  0x4E, 0x4F, 0x44, 0x49, 0x53, 0x43, 0x30, 0x30, // NODISK00
  0x31, 0x39, 0x30, 0x31, 0x31, 0x38,             // дата: 190118
  0x74, 0x65, 0x73, 0x74, 0x74, 0x70, 0x20, 0x20, // testtp.....
  0x20, 0x20, 0x20, 0x00, 0x00 };

int p = 3; // номер пина, на который будет вывод сигнала

void setup() //процедура setup
{
  pinMode(p, OUTPUT); //объявляем пин как выход
  pinMode(10, OUTPUT);

  while (!SD.begin(10)){ // SD-карта готова?
    tone(p, 200, 100); // нет -- включаем на 200 Гц на 100 мс
    delay(3000);       // ждем 3 с
  } 
}

void loop() //процедура loop
{
  tone(p, 500, 100); //включаем на 500 Гц на 100 мс
  delay(1000);       //ждем 1 с

  romFile = SD.open("cybernoi.rom"); // открываем файл
  if (romFile) {                     // открылся?
    byte BLs = 0x01;    // начальный блок
    unsigned int  Nbt = romFile.size();  // всего байтов
    byte BLe = Nbt/256; // всего блоков
    byte BLt;           // осталось блоков
    byte Nst;           // номер строки
    byte St;            // выводимый байт

    byte CSz = 0x00;    // контрольная сумма заголовка
    byte CSs = 0x00;    // контрольная сумма строки
    byte i;
    byte j;

    if (Nbt%256 != 0){  // корректировка количества блоков, если размер файла не кратен 256
      BLe++;
    } 

    // Начинаем вывод
    for (i=0; i<=3; i++){           // преамбула (4*(00H*25+55H*25))
      for (j=0; j<=24; j++){
        SendByte(0x00);
      }
      for (j=0; j<=24; j++){
        SendByte(0x55);
      }
    }  

    for (BLt=BLe; BLt>=1; BLt--){   // Вывод блоков данных
      CSz = BLs;
      CSz += BLe;
      CSz += BLt;
      for (j=0; j<=15; j++){        // 00h*16
        SendByte(0x00);
      }
      for (j=0; j<=3; j++){         // 55h*4
        SendByte(0x55);
      }
      SendByte(0xE6);               // E6h*1
      for (j=0; j<=3; j++){         // 00h*4
        SendByte(0x00);
      }

      for (j=0; j<=26; j++){        // заголовок блока
        CSz += SB[j];
        SendByte(SB[j]);
      }
      SendByte(BLs);                // начальный блок
      SendByte(BLe);                // конечный блок
      SendByte(BLt);                // осталось блоков
      SendByte(CSz);                // контр.сумма заголовка

      for (Nst=0x80; Nst<=0x87; Nst++){   // вывод строк (8 шт.)
        for (j=0; j<=3; j++){       // 00h*4
          SendByte(0x00);
        }
        SendByte(0xE6);             // E6h*1
        CSs = Nst;
        SendByte(Nst);              // номер строки
        CSs += CSz;
        SendByte(CSz);              // контр.сумма заголовка

        for (j=0; j<=31; j++){      // собственно, строка данных
          if (Nbt > 0){          // ещё есть данные?
            St = romFile.read(); // читаем очередной байт из файла
            Nbt--;
          } 
          else {                 // нет -- дополняем нулями
            St = 0x00;
          }
          CSs += St;
          SendByte(St);
        }
        SendByte(CSs);              // контр.сумма строки
      }  
    }

    for (j=0; j<=15; j++){          // 00h*16 -- завершение вывода программы (?)
      SendByte(0x00);
    }
    // close the file:
    romFile.close();
  }
  else {      
    tone(p, 200, 300); // нет файла -- включаем на 200 Гц на 300 мс
  }
  delay(15000);   // ждем 15 с
}

void SendByte(byte SBt){          // Подпрограмма вывода байта
  byte Pd=PORTD;
  byte i=8;
  do{                 // Выводим биты начиная со старшего
    i--;
    if ((bitRead(Pd, p))^(bitRead(SBt, i))){ // Если состояние порта и выводимый бит разные
      Pd ^= (1 << p); // инвертируем бит в позиции p=3
      PORTD = Pd;     // вывод в порт p
    }
    else{
      delayMicroseconds(16); // Задержка для выравнивания длительности сигнала
    }
    delayMicroseconds(256);   // Задержка первого полупериода сигнала
    Pd ^= (1 << p);   // инвертируем бит в позиции p
    PORTD = Pd;       // вывод в порт p
    delayMicroseconds(256);   // Задержка второго полупериода сигнала
  } 
  while (i>0);
}
[свернуть]

Для проверки взял один из самых больших ROM-файлов, игру Cybernoid, на выгрузку ушло примерно 4 минуты. Всё, вроде, отработало здорово, но при распознавании в wav2rom вылезло 45 ошибок. :-( Причём все ошибки в первом байте блока (не каждого -- в 45 из 159 блоков):
Нажмите на изображение для увеличения. 

Название:	20_diff.jpg 
Просмотров:	405 
Размер:	75.5 Кб 
ID:	64163

Просмотр сигнала в той же программе выявил ошибку:
Нажмите на изображение для увеличения. 

Название:	20.jpg 
Просмотров:	400 
Размер:	81.0 Кб 
ID:	64164

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

Вот скетч в архиве: Test_TP_fromSD.ino.zip, WAV-файл не выкладываю -- нет смысла...

- - - Добавлено - - -

Цитата Сообщение от svofski Посмотреть сообщение
У страха глаза велики =) С таймерами самые невероятные вещи можно творить.

Но на самом деле ради переносимости я бы правда отложил эту идею.
Да, оставим на потом. А с другой стороны, с выводом без всяких таймеров легко справлялся проц КР580ВМ80А -- и ардуина тоже должна справится. :-)