Сканер ИК-пультов с записью на SD-карту

Проекты на Arduino Uno и Slot Shield

Устройство построено на оригинальной Arduino Uno. Плата управляет бытовой техникой с помощью ИК-передатчика. Коды команд управления заранее считываются ИК-приёмником с родного пульта и сохраняются на microSD. Сохранённую команду можно запустить из консоли монитора порта.

Видеоинструкция

Что потребуется

Как собрать

Установите Troyka Slot Shield на Arduino Uno

Вставьте ИК-приёмник в разъём С. Ножка S должна подключится к пину 4. Аналогично подключите ИК-передатчик к пину 9 слота E.

Подключите SD-картридер к пинам SPI слота D.

Скетч

Как прошить контроллер через Arduino IDE.

Оперативной памяти Arduino Uno не хватает для одновременной работы сканера и SD-карты. Поэтому приходится разбить задачу на два скетча. С помощью первого просканируем коды команд пульта дистанционного управления и сохраним их в текстовые файлы на SD-карту.

ir-remote-with-sd-scan.ino
// Библиотека для работы с SPI
#include <SPI.h>
// Библиотека для работы с SD-картами
#include <SD.h>
 
// Библиотека для работы с ИК-приёмником и передатчиком
#include <IRremote.h>
 
// Имя пина, которому подключен приёмник
#define RECV_PIN 4
// Имя пина, к которому подключен передатчик
#define SEND_PIN 9
// Имя для CS пина microSD-карты
#define SD_CS_PIN  8
 
// Строка с хранением данных введенных в последовательный порт
#define command_S1  "C_S1.txt"
#define command_S2  "C_S2.txt"
#define command_S3  "C_S3.txt"
#define command_S4  "C_S4.txt"
 
// Создаём объект для ИК-приёмника
IRrecv irrecv(RECV_PIN);
 
// Создаём объект для ИК-передатчика
IRsend irsend;
 
// Создаём объект для декодированных команд с ИК-пульта
decode_results results;
 
// Строка с хранением данных введенных в последовательный порт
String command = "";
 
void setup() {
  // открываем последовательный порт
  Serial.begin(9600);
    // Запускаем работу ИК-приёмника
    irrecv.enableIRIn();
  // выводим сообщение в Serial-порт о поиске карты памяти
  Serial.println("Initializing SD card...");
  // если microSD-карта не была обнаружена
  if (!SD.begin(SD_CS_PIN)) {
    // выводим сообщение об ошибке
    Serial.println("Card failed, or not present");
    // завершаем процесс
    return;
  } else {
    Serial.println("Card initialized.");
  }
}
 
void loop() {
  // пока в Serial port поступают символы...
  while (Serial.available() > 0) {
    // ...символ записываем в переменную
    char symbol = Serial.read();
    // если приходит символ разрыва строки...
    if (symbol == '\n') {
      // выводим полученную команду
      Serial.println(command);
      // идентифицируем полученную команду
      if ( command == "RC_S1") {
        // удаляем предыдущую команду
        SD.remove(command_S1);
        // если пришла команда C_S1, выполняем отправку соответствующей команды
        reading (&results, command_S1);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S1\" sent.");
      } else if (command == "RC_S2") {
        // удаляем предыдущую команду
        SD.remove(command_S2);
        // если пришла команда C_S2, выполняем отправку соответствующей команды
        reading (&results, command_S2);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S2\" sent.");
      } else if (command == "RC_S3") {
        // удаляем предыдущую команду
        SD.remove(command_S3);
        // если пришла команда C_S3, выполняем отправку соответствующей команды
        reading (&results, command_S3);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S3\" sent.");
      } else if (command == "RC_S4") {
        // удаляем предыдущую команду
        SD.remove(command_S4);
        // если пришла команда C_S4, выполняем отправку соответствующей команды
        reading (&results, command_S4);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S4\" sent.");
      }
      command = "";
    } else  {
      // ... если символ не является символом разрыва строки, то вписываем его в последовательность
      command += symbol;
    }
  }  
}
 
// функция режима "чтение ИК-сигнала"
void reading (decode_results *results, String command) {
  // создаём файл для записи
  File dataWrine = SD.open(command, FILE_WRITE);
  // если файл доступен для записи
  if (dataWrine) {
    // "Введите команду с пульта дистанционного управления"
    Serial.println("Enter the command from the remote control. ");
    while (1) {
      // ожидаем, пока придет команда с пульта
      if (irrecv.decode(results)) {
        for (int i = 1;  i < results->rawlen;  i++) {
          dataWrine.print(results->rawbuf[i] *USECPERTICK, DEC);
          dataWrine.print(' ');
        }
        break;
      }
    }
    dataWrine.close();
    // перезапустим ИК-приёмник
    irrecv.resume();
  } else {
    // если файл не доступен
    Serial.println("Error opening in \"reading\"");
  }
}

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

ir-remote-with-sd-send.ino
// Библиотека для работы с SPI
#include <SPI.h>
// Библиотека для работы с SD-картами
#include <SD.h>
 
// Библиотека для работы с ИК-приёмником и передатчиком
#include <IRremote.h>
 
// Имя пина, которому подключен приёмник
#define RECV_PIN 4
// Имя пина, к которому подключен передатчик
#define SEND_PIN 9
// Имя для CS пина microSD-карты
#define SD_CS_PIN  8
 
// Строка с хранением данных введенных в последовательный порт
#define command_S1  "C_S1.txt"
#define command_S2  "C_S2.txt"
#define command_S3  "C_S3.txt"
#define command_S4  "C_S4.txt"
 
// Создаём объект для ИК-передатчика
IRsend irsend;
 
// Частота (КГц) с которой будут передаваться сигналы
int khz = 38;
 
// Строка с хранением данных введенных в последовательный порт
String command = "";
 
void setup() {
  // открываем последовательный порт
  Serial.begin(9600);
  // выводим сообщение в Serial-порт о поиске карты памяти
  Serial.println("Initializing SD card...");
  // если microSD-карта не была обнаружена
  if (!SD.begin(SD_CS_PIN)) {
    // выводим сообщение об ошибке
    Serial.println("Card failed, or not present");
    // завершаем процесс
    return;
  } else {
    Serial.println("Card initialized.");
  }
}
 
void loop() {
  // пока в Serial port поступают символы...
  while (Serial.available() > 0) {
    // ...символ записываем в переменную
    char symbol = Serial.read();
    // если приходит символ разрыва строки...
    if (symbol == '\n') {
      // выводим полученную команду
      Serial.println(command);
      // идентифицируем полученную команду
      if ( command == "C_S1") {
        // если пришла команда C_S1, выполняем отправку соответствующей команды
        sending (command_S1);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S1\" sent.");
      } else if (command == "C_S2") {
        // если пришла команда C_S2, выполняем отправку соответствующей команды
        sending (command_S2);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S2\" sent.");
      } else if (command == "C_S3") {
        // если пришла команда C_S3, выполняем отправку соответствующей команды
        sending (command_S3);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S3\" sent.");
      } else if (command == "C_S4") {
        // если пришла команда C_S4, выполняем отправку соответствующей команды
        sending (command_S4);
        // выводим сообщение об отправке
        Serial.println("Signal \"C_S4\" sent.");
      }
      command = "";
    } else  {
      // ... если символ не является символом разрыва строки, то вписываем его в последовательность
      command += symbol;
    }
  }
}
 
// функция отправки ИК-команд
void sending (String command) {
  // создаём файл для отправки
  File dataRead = SD.open(command, FILE_READ);
  // если файл доступен для чтения
  if (dataRead) {
    // промежуточный массив для декодирования символов
    int num [6];
    // счетчик степеней декодированного сигнала
    int count = 0;
    // счетчик массива сигналов
    int j = 0;
    // пока считываются данные из файла
    while (dataRead.available()) {
      // записываем из файла посимвольно данные в промежуточный массив
      for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++) {
        // переменная для хранения полученного символа
        char point = dataRead.read();
        if (point == ' ') {
          break;
        } else {
          // преобразуем полученные символы в числа
          num[i] = point - '0';
          count++;
        }
      }
      // преобразуем массив с отдельными числами в единый сигнал и записываем его в массив
      for (int i = 0; i < count; i++) {
        irparams.rawbuf[j] += num[i] * ceil (pow(10, count - i - 1));
      }
      // переходим к следующему элементу массива
      j++;
      count = 0;
    }
    // отправляем массив сигналов
    irsend.sendRaw(irparams.rawbuf, sizeof(irparams.rawbuf) / sizeof(irparams.rawbuf[0]), khz);
    // после отправки очищаем массив
    for (int i = 0; i < sizeof(irparams.rawbuf) / sizeof(irparams.rawbuf[0]); i++) {
      irparams.rawbuf[i] = 0;
    }
    // закрываем файл
    dataRead.close();
  } else {
    // если файл не доступен
    Serial.println("Error opening in \"sending\"");
  }
}

Часто задаваемые вопросы

Где скачать необходимые библиотеки и как их установить?

Что дальше

  • Добавьте Power Shield — контроллер можно будет переносить по разным помещениям.
  • Вставьте устройство в корпус из #cтруктора. Slot Box придаст игре законченный вид.