Универсальный ИК-контроллер с датчиком шума
Проекты на Arduino Uno и Slot Shield
Включать и выключать свет хлопками умеют многие, а вот управлять сложной бытовой техникой — например кондиционером — сложная задача даже для прожжённых DIY-щиков.
В этом устройстве количество хлопков в ладоши будет означать номер сохранённого в память температурного профиля — от одного до четырёх. Конечно, вы можете сделать больше, но для экспериментов мне пока и этого хватит.
Устройство построено на оригинальной Arduino Uno. Плата управляет бытовой техникой с помощью ИК-передатчика. Коды команд управления заранее считаем ИК-приёмником с родного пульта и сохраним на microSD. Сохранённую команду можно запустить вручную, похлопав в ладоши. Для этого в проекте предусмотрен датчик шума. Не хотите привлекать лишнего внимания, тихонько установите режим с помощью четырёхкнопочной клавиатуры.
- Язык программирования: Arduino (C++)
Видеоинструкция
Что потребуется
Полный сет компонентов проекта. В сет входят:
Как собрать
Установите Troyka Slot Shield на Arduino Uno
Вставьте ИК-приёмник в разъём С
. Ножка S
должна подключится к пину 4
. Аналогично подключите ИК-передатчик к пину 9
слота E
.
Подключите SD-картридер к пинам SPI
слота D
.
Установите четырёхкнопочную клавиатуру в пины разъёма B
. Сигнальный пин S1
модуля должен подключится к пину A2
платы.
Вставьте датчик шума в слот A
. Ножка E
модуля должна встать в пин А4
.
Скетч
Прошейте контроллер скетчем через Arduino IDE.
- ir-remoute-with-noise-sensor.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 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 // Создаём объект для ИК-передатчика IRsend irsend; // Флаги для однократного срабатывания кнопок 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; } } } // функция отправки ИК-команд 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; }
Часто задаваемые вопросы
Где скачать необходимые библиотеки и как их установить?
- Библиотека эмуляции ИК-пультов: arduino-irremote.7z
Что дальше
- Добавьте Power Shield — контроллер можно будет переносить по разным помещениям.
- Вставьте устройство в корпус из #cтруктора. Slot Box придаст игре законченный вид.