Универсальный ИК-контроллер с датчиком температуры

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

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

Температуру измерит аналоговый термометр. Оригинальная Arduino Uno сравнит данные с программными настройками и включит или выключит кондиционер с помощью ИК-передатчика. Коды команд управления заранее считаем ИК-приёмником с родного пульта и сохраним на microSD. Сохранённую команду можно запустить вручную, похлопав в ладоши. Для этого в проекте предусмотрен датчик шума. Не хотите привлекать лишнего внимания, тихонько установите режим с помощью четырёхкнопочной клавиатуры.

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

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

Как собрать

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

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

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

Установите четырёхкнопочную клавиатуру в пины разъёма B. Сигнальный пин S1 модуля должен подключится к пину A2 платы.

Вставьте датчик шума в слот A. Ножка E модуля должна встать в пин А4.

Подключите аналоговый термометр к пину A0 слота F.

Скетч

Прошейте контроллер скетчем через Arduino IDE.

ir-remoute-with-temperature-sensor.ino
// Библиотека для работы с SPI
#include <SPI.h>
// Библиотека для работы с SD-картами
#include <SD.h>
 
// Библиотека для работы с ИК-приёмником и передатчиком
#include <IRremote.h>
 
// библиотека для работы с аналоговым термометром
#include <TroykaThermometer.h>
 
// Имя пина, которому подключен приёмник
#define RECV_PIN 4
// Имя пина, к которому подключен передатчик
#define SEND_PIN 9
// Имя для CS пина microSD-карты
#define SD_CS_PIN  8
 
// Имена пинов для кнопок
#define BUTTON_S1 A2
#define BUTTON_S2 A3
#define BUTTON_S3 3
#define BUTTON_S4 6
 
// Строка с хранением данных введенных в последовательный порт
#define command_S1  "C_S1.txt"
#define command_S2  "C_S2.txt"
#define command_S3  "C_S3.txt"
#define command_S4  "C_S4.txt"
 
// Имя для пинов микрофона и шумомера
#define SOUND_PIN  A5
#define NOISE_PIN  A4
// Темп двойного звука
#define KNOCK_HIGH 300
// Темп внутри последовательности звуков
#define KNOCK_TIMEOUT 1000
// Длина кодовой последовательности звуков
#define CODE_LEN 4
 
// Температура отключения охлаждения
#define TEMP_MIN 29
// Температура включения охлаждения
#define TEMP_MAX 31
 
// Создаем объект для Термометра
TroykaThermometer thermometer(A0);
 
// Создаём объект для ИК-передатчика
IRsend irsend;
 
// Флаг для однократного срабатывания команды по температуре
bool fTemp = true;
 
// Флаги для однократного срабатывания кнопок
bool fS1 = false;
bool fS2 = false;
bool fS3 = false;
bool fS4 = false;
 
// Стартовый код для команды S_1
bool code_S1[CODE_LEN] = { 0, 1, 1, 1};
// Стартовый код для команды S_2
bool code_S2[CODE_LEN] = { 1, 0, 1, 1};
// Стартовый код для команды S_3
bool code_S3[CODE_LEN] = { 1, 1, 0, 1};
// Стартовый код для команды S_4
bool code_S4[CODE_LEN] = { 1, 1, 1, 0};
 
// Полученная кодовая последовательность
bool input[CODE_LEN] = { 0, 0, 0, 0};
// "Тук" и пауза - это "1"
// "Тук"-"тук" - это "0"
 
// Чувствительность замка
unsigned int knockLevel = 0;
 
// Частота (КГц) с которой будут передаваться сигналы
const int khz = 38;
 
void setup() {
  // определяем пины кнопок, как входы с подтяжкой
  pinMode(BUTTON_S1, INPUT_PULLUP);
  pinMode(BUTTON_S2, INPUT_PULLUP);
  pinMode(BUTTON_S3, INPUT_PULLUP);
  pinMode(BUTTON_S4, INPUT_PULLUP);
  // открываем последовательный порт
  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() {
  // считываем сигналы с кнопок
  bool bS1 = !digitalRead(BUTTON_S1);
  bool bS2 = !digitalRead(BUTTON_S2);
  bool bS3 = !digitalRead(BUTTON_S3);
  bool bS4 = !digitalRead(BUTTON_S4);
  // проверяем, какая из кнопок нажата, кнопка S1?...
  if (bS1 == true && fS1 == true) {
    fS1 = false;
    // если пришла команда C_S1, выполняем отправку соответствующей команды
    sending (command_S1);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S1\" sent.");
  }
  if (bS1 == false) fS1 = true;
  // ... кнопка S2?...
  if (bS2 == true && fS2 == true) {
    fS2 = false;
    // если пришла команда C_S2, выполняем отправку соответствующей команды
    sending (command_S2);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S2\" sent.");
  }
  if (bS2 == false) fS2 = true;
  // ... кнопка S3?...
  if (bS3 == true && fS3 == true) {
    fS3 = false;
    // если пришла команда C_S3, выполняем отправку соответствующей команды
    sending (command_S3);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S3\" sent.");
  }
  if (bS3 == false) fS3 = true;
  // ... кнопка S4?...
  if (bS4 == true && fS4 == true) {
    fS4 = false;
    // если пришла команда C_S4, выполняем отправку соответствующей команды
    sending (command_S4);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S4\" sent.");
  }
  if (bS4 == false) fS4 = true;
 
  // устанавливаем чувствительность микрофона
  knockLevel = analogRead(SOUND_PIN);
  // если получили последовательность звуков, производим сравнение
  if (readCode() == true) {
    Serial.println (" Notes code received! ");
    if (comparisonCode(code_S1) == true) {
      // если пришла команда C_S1, выполняем отправку соответствующей команды
      sending (command_S1);
      // выводим сообщение об отправке
      Serial.println("Signal \"C_S1\" sent.");
    } else if (comparisonCode(code_S2) == true) {
      // если пришла команда C_S1, выполняем отправку соответствующей команды
      sending (command_S2);
      // выводим сообщение об отправке
      Serial.println("Signal \"C_S2\" sent.");
    } else if (comparisonCode(code_S3) == true) {
      // если пришла команда C_S3, выполняем отправку соответствующей команды
      sending (command_S3);
      // выводим сообщение об отправке
      Serial.println("Signal \"C_S3\" sent.");
    } else if (comparisonCode(code_S4) == true) {
      // если пришла команда C_S4, выполняем отправку соответствующей команды
      sending (command_S4);
      // выводим сообщение об отправке
      Serial.println("Signal \"C_S4\" sent.");
    }
    // очищаем массив звуковой команды
    for (int i = 0; i < CODE_LEN; i++) {
      input[i] = 0;
    }
  }
 
  // считываем данные с аналогового термометра
  thermometer.read();
  int t = thermometer.getTemperatureC() * 100;
  // проверяем температуру
  if (t > TEMP_MAX * 100 && fTemp) {
    // если температура перешагнула через верхнюю отметку, выполняем отправку соответствующей команды
    sending (command_S1);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S1\" sent.");
    fTemp = false;
  }
  if (t < TEMP_MIN * 100 && !fTemp) {
    // если температура перешагнула через нижнюю отметку, выполняем отправку соответствующей команды
    sending (command_S2);
    // выводим сообщение об отправке
    Serial.println("Signal \"C_S2\" sent.");
    fTemp = true;
  }
}
 
// функция отправки ИК-команд
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\"");
  }
}
 
// Функция, идентифицирующая приходящую последовательность звуков
bool readCode() {
  // создаем переменную для промежуточного хранения
  char symbol;
  // проверяем, пришла ли кодировка звуков
  for (int i = 0; i < CODE_LEN; i++) {
    // записываем код
    symbol = get_blast();
    // если код равен -1, значит ничего не пришло, выходим
    if (symbol < 0) return false;
    // если код пришел, записываем его в сравниваемый массив
    input[i] = symbol;
  }
  return true;
}
 
// Функция, сравнивающая массивы звуковых команд
bool comparisonCode(bool code[CODE_LEN]) {
  // сравниваем массивы
  for (int i = 0; i < CODE_LEN; i++) {
    // если код не соответствует заданному, выходим
    if (input[i] != code[i]) {
      return false;
    }
  }
  return true;
}
 
// Функция распознавания последовательностей звуков, возвращает код:
// 0 - если двойной звук,
// 1 - если одинарный звук,
// -1,если в течении KNOCK_TIMEOUT никто не стучал.
char get_blast() {
  unsigned long timer = millis();
  while (!blast() && millis() - timer < KNOCK_TIMEOUT) {}
  if (millis() - timer >= KNOCK_TIMEOUT) return -1;
  timer = millis();
  while (blast()) {}
  while (!blast() && millis() - timer < KNOCK_HIGH) {}
  timer = millis() - timer;
  while (blast()) {}
  if (timer < KNOCK_HIGH) return 0;
  return 1;
}
 
 
// Функция преобразования аналогового сигнала с микрофона в бинарный:
// 1 - громко
// 0 - тихо
bool blast() {
  bool b1, b2;
  while (1) {
    b1 = analogRead(NOISE_PIN) > knockLevel;
    delay(1);
    b2 = analogRead(NOISE_PIN) > knockLevel;
    delay(1);
    if (b1 == b2) return b1;
  }
  return false;
}

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

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

Что дальше

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