Код:
/*
* SD-картридер подключяется к выводам ардуино:
** MOSI - D11
** MISO - D12
** CLK - D13
** CS - D10
*
* Выход - D3
*/
#include <SdFat.h>
#include <TimerOne.h>
SdFat sd;
SdFile romFile;
volatile byte BUFF[256]; // буфер данных
volatile unsigned int CRB = 0; // индекс чтения из буфера
volatile byte bBit = 15; // индекс читаемого полубита
unsigned int CWB = 0; // индекс записи в буфер
// Заголовок
byte SB[27] = {
0x4E, 0x4F, 0x44, 0x49, 0x53, 0x43, 0x30, 0x30, // NODISK00
0x31, 0x34, 0x30, 0x32, 0x31, 0x38, // дата: 140218
0x74, 0x65, 0x73, 0x74, 0x74, 0x70, 0x20, 0x20, // testtp.....
0x20, 0x20, 0x20, 0x00, 0x00 };
int p = 3; // номер пина, на который будет вывод сигнала
const int Tpp = 256; // Длительность задержки сигнала в микросекундах (один полупериод)
void setup() //процедура setup
{
pinMode(p, OUTPUT); // объявляем пин как выход
pinMode(10, OUTPUT); // CS для SD-картридера
Timer1.initialize(Tpp); // инициализировать timer1, и установить период Tpp мкс.
Timer1.attachInterrupt(SendHalfBit); // прикрепить SendHalfBit(), как обработчик прерывания по переполнению таймера
Timer1.stop();
while (!sd.begin(10,SPI_FULL_SPEED)){ // SD-карта готова?
tone(p, 200, 100); // нет -- включаем на 200 Гц на 100 мс
delay(3000); // ждем 3 с
}
sd.chdir(); // устанавливаем корневую директорию SD
}
void loop() //процедура loop
{
tone(p, 500, 100); //включаем на 500 Гц на 100 мс
delay(1000); //ждем 1 с
if (romFile.open("cybernoi.rom",O_READ)) { // открываем файл. Открылся?
byte BLs = 0x01; // начальный блок
unsigned int Nbt = romFile.fileSize(); // всего байт
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++){
BUFF[CWB] = 0x00;
CWB++;
}
for (j=0; j<=24; j++){
BUFF[CWB] = 0x55;
CWB++;
}
}
Timer1.start(); // Запускаем таймер............
for (BLt=BLe; BLt>=1; BLt--){ // Вывод блоков данных в цикле
CSz = BLs;
CSz += BLe;
CSz += BLt;
for (j=0; j<=15; j++){ // 00h*16
ToBUFF(0x00);
}
for (j=0; j<=3; j++){ // 55h*4
ToBUFF(0x55);
}
ToBUFF(0xE6); // E6h*1
for (j=0; j<=3; j++){ // 00h*4
ToBUFF(0x00);
}
for (j=0; j<=26; j++){ // заголовок блока
CSz += SB[j];
ToBUFF(SB[j]);
}
ToBUFF(BLs); // начальный блок
ToBUFF(BLe); // конечный блок
ToBUFF(BLt); // осталось блоков
ToBUFF(CSz); // контр.сумма заголовка
for (Nst=0x80; Nst<=0x87; Nst++){ // вывод строк (8 шт.)
for (j=0; j<=3; j++){ // 00h*4
ToBUFF(0x00);
}
ToBUFF(0xE6); // E6h*1
CSs = Nst;
ToBUFF(Nst); // номер строки
CSs += CSz;
ToBUFF(CSz); // контр.сумма заголовка
// начинаем вывод строки данных
for (j=0; j<=31; j++){ // цикл на 32 байта
if (Nbt > 0){ // ещё есть данные?
St = romFile.read(); // читаем очередной байт из файла
Nbt--;
}
else { // нет -- дополняем нулями
St = 0x00;
}
ToBUFF(St); // передаём считанный байт
CSs += St;
}
ToBUFF(CSs); // контр.сумма строки
}
}
// close the file:
romFile.close();
for (j=0; j<=15; j++){ // 00h*16 -- завершение вывода программы (?)
ToBUFF(0x00);
}
}
else {
tone(p, 200, 300); // нет файла -- включаем на 200 Гц на 300 мс
}
while (CRB < CWB) { // Ждём опустошения буфера
delay(Tpp);
}
Timer1.stop(); // Останавливаем таймер............
CRB = 0; // Сбрасываем индексы.
CWB = 0;
bBit = 15;
delay(15000); // ждем 15 с
}
void ToBUFF(byte SBb){ // Подпрограмма записи байта в буфер
while (CWB > CRB + 255) {// Если позиция записи больше, чем позиция чтения + размер буфера - 1
delay(Tpp); // Задержка (Tpp*1000 мкс = Tpp мс)
}
BUFF[lowByte(CWB)] = SBb;
CWB++;
}
void SendHalfBit() { // Подпрограмма вывода полубита по циклу таймера
byte Pd=PORTD;
if (bBit & 1){ // проверка индекса полубитов на чётность
// if ((bitRead(Pd, p))^(bitRead(BUFF[lowByte(CRB)], bBit/2))){ // Старый вариант...
if (( (Pd >> p)^( BUFF[lowByte(CRB)] >> (bBit >> 1) ))&1){ // Если состояние порта и выводимый бит разные
Pd ^= (1 << p); // инвертируем бит в позиции p
}
}
else{ // нечётный -- просто инвертируем порт
Pd ^= (1 << p); // инвертируем бит в позиции p(=3)
}
PORTD = Pd; // вывод в порт p
if (bBit > 0) { // правим счётчики полубитов и байтов
bBit--;
}
else{
bBit = 15;
CRB++;
}
}