Код (C++): //управление нагрузками (светом) при помощи ик пульта и тактовой кнопки. команды ик пульта прописывать отдельно #include <EEPROM.h> #include <IRremote.h> #include <Bounce.h> #include <LiquidCrystal.h> //Подключаем библиотеку для работы с LCD LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); // инициализируем LCD, указывая управляющие контакты //дефайним значения пинов с кнопкой и со светодиодом #define BUTTON 6 #define learnbutton 7 #define led 13 #define learnled 15 #define RECV_PIN 9 //создаем объект класса Bounce. Указываем пин, к которому подключена кнопка, и время дребезга в мс. Bounce bouncer = Bounce(BUTTON,5); Bounce learnbouncer = Bounce(learnbutton,5); //задаем начальное состояние светодиода "выключен" int addr = 0; int ledValue = LOW; // переменные int ledStat = 0; int learnledValue = LOW; // переменные int learnledStat = 0; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { lcd.begin(16, 2);// задаем размерность дисплея //определяем режимы работы пинов pinMode(BUTTON,INPUT); pinMode(led,OUTPUT); Serial.begin(9600); irrecv.enableIRIn(); // Запуск приемника pinMode(learnled, OUTPUT); } void loop() { if ( learnbouncer.update() ) { //если считано значение 1 if ( learnbouncer.read() == HIGH) { //если свет был выключен, будем его включать if ( learnledValue == LOW ) { learnledValue = HIGH; //если свет был включен, будем выключать } else { learnledValue = LOW; } //записываем значение вкл/выкл на пин со светодиодом digitalWrite(learnled,learnledValue); } } if (learnledValue == HIGH) { if (results.value == 0xFFFFFFF) { EEPROM.write(addr, results.value); } } //если сменилось состояние кнопки if ( bouncer.update() ) { //если считано значение 1 if ( bouncer.read() == HIGH) { //если свет был выключен, будем его включать if ( ledValue == LOW ) { ledValue = HIGH; //если свет был включен, будем выключать } else { ledValue = LOW; } //записываем значение вкл/выкл на пин со светодиодом digitalWrite(led,ledValue); } } if (irrecv.decode(&results)) { Serial.println(results.value); //красный if (results.value = EEPROM.read(addr) && ledValue == 0) { digitalWrite(led, HIGH); ledValue = 1; } else if (results.value == 0xFF00FF && ledValue == 1) { digitalWrite(led, LOW); ledValue = 0; } irrecv.resume(); // Получить слудующее значение } if ( ledValue == LOW ) { lcd.setCursor(0, 0); // устанавливаем курсор в 0-ом // столбце, 1 строке (начинается с 0) lcd.print("Light is OFF"); lcd.setCursor(0, 1); // устанавливаем курсор в 0-ом столбце, 2 строке lcd.print("PUSH BUTTON"); // обозначение минимальной температры } else { lcd.setCursor(0, 0); // устанавливаем курсор в 0-ом // столбце, 1 строке (начинается с 0) lcd.print("Light is ON"); lcd.setCursor(0, 1); // устанавливаем курсор в 0-ом столбце, 2 строке lcd.print("PUSH BUTTON"); // обозначение минимальной температры } }
в общем без learnled и learnbutton все работает с заранее заданной командой ик пульта. на дисплей не обращайте внимания, он тут так - постольку поскольку. хочется прикрутить функцию обучения при нажатии кнопки обучения, чтобы считал код, записал в eeprom, а потом оттуда брал для управления светодиодом (нагрузкой). читал вот эту тему http://forum.amperka.ru/threads/Управление-светодиодом-с-ИК-пульта-Есть-режим-обучения-командам.3376/ там все здорово, и я бы ее модифицировал под себя, но пока не въезжаю в данный код, и ее минус - обучение запускается автоматом при подаче питания, а хотелось бы просто с кнопки. помогите кто чем может. этот код - то, что я имею своими скудными силами, обучение ик у меня не получается (светодиод загорается, иногда рабочий светодиод вместе с кнопкой). Еще мне понравилось в приведенной ссылке, что пульт от моего смарт тв (самсунг) тоже воспринимается. что там не понравилось - при длительном удержании кнопки пульта - светодиод моргает. Помогите, плз, всю голову сломал. нужно управление нагрузкой и с кнопки и с пульта ик. Спасибо
* Пример программы для управления светодиодом с ИК-пульта. https://github.com/altexdim/arduino-learn-ir-code Коды команд кнопок пульта сохраняются в памяти Arduino после сброса. Для обучения устройства новой команде (кнопке пульта) используется тактовая кнопка на Arduino. У устройства два режима работы. 1) В основном режиме работы устройство ждёт команд с ИК-пульта. Если пришла команда, то сравнивает её с тем значением, которое храниться в памяти. Если пришла команда, которая совпадает со значением из памяти, то тогда рабочий светодиод переключается - загорается или гаснет - от каждого нажатия кнопки ИК-пульта. 2) Второй режим - режим обучения. В этот режим устройство переводится нажатием и удержанием тактовой кнопки на Arduino. Если включен этот режим, то постоянно горит второй светодиод, предназначенный только для отображения режима работы. В этом режиме устройство ожидает от ИК-пульта нажатия любой кнопки. Если на ИК-пульте нажать на кнопку, то полученная команда сохранится в постоянной памяти Arduino, и устройство будет переведено обратно в основной режим работы. Если отпустить тактовую кнопку до команды с ИК-пульта, то устройство вернётся обратно в основной режим работы, при этом никаких изменений с прежней командой не произойдёт. Если устройство научилось новой команде, тогда рабочий светодиод можно переключать только с помощью этой новой команды, а предыдущая команда стирается. License: MIT http://opensource.org/licenses/mit-license.php Copyright (c) 2014 Ananyev Dmitry */ /* Подключаем библиотеку IRremote https://github.com/shirriff/Arduino-IRremote (LGPL) Install: cd C:\Users\<USERNAME>\Documents\Arduino\libraries git clone https://github.com/shirriff/Arduino-IRremote.git IRremote */ #include <IRremote.h> // Стандартная библиотека для работы с EEPROM. Нужна для сохранения кодов кнопок пульта между перезагрузками. #include <EEPROM.h> // Дополнительные функции для перевода long -> int и назад. #define makeLong(hi, low) (((long) hi) << 16 | (low)) #define highWord(w) ((w) >> 16) #define lowWord(w) ((w) & 0xffff) // Режим отладки // В этом режиме отладочная информация выводится в последовательный порт. #define DEBUG 0 /* Пин, к которому подключен ИК приёмник. У ИК приёмника один информационный выход, подключается напрямую к этому пину. Ещё у ИК приёмника обычно есть два контакта - Vcc и Ground. Они соответственно подключаются к питанию и земле. Используется ИК приёмник TSOP22 на 38 кГц. */ #define RECV_PIN 9 /* Пин, к которому подключена тактовая кнопка включения режима обучения командам пульта. Другим концом тактовая кнопка подключается к земле. Так что при замыкании кнопки на этом пине будет низкий уровень. Так же к пину подключен подтягивающий резистор 10кОм на Vcc. Используется обычная двухконтактная кнопка нормально-разомкнутая. */ #define LEARN_BUTTON_PIN 7 /* */ #define KNOPKA 6 //моя кнопка /* Пин, к которому подключен светодиод, показывающий, что включен режим обучения. Светодиод другим концом подключен к земле через резистор 200 Ом. Загорается от высокого уровня на пине. Используется обычный светодиод 20 мА на 2.3 В. */ #define LEARN_LED_PIN 13 /* Пин, который управляется командой с пульта. Здесь используется светодиод. По кнопке пульта он включается и выключается. Светодиод другим концом подключен к земле через резистор 200 Ом. Загорается от высокого уровня на пине. Используется обычный светодиод 20 мА на 2.3 В. Вместо светодиода можно подключить любую нагрузку. */ #define WORK_LED_PIN 15 // адрес, по которому сохраняются команды в постоянной памяти. Используется 4 байта. Указывается начальный адрес. #define IR_CODE_DATA_ADDRESS 0 // состояние кнопки режима обучения - нажата(1) или нет(0) boolean learnButtonState = 0; boolean KNOPKAState = 0; // моя кнопка // режим обучения - включен(1) или нет(0) boolean learnModeEnabled = 0; // управлеямый с пульта светодиод - включен(1) или нет(0) boolean workLedState = 0; // код команды пульта, по которому происходит включение управляемого светодиода long irCodeData = 0; // объект приёмника ИК-команд IRrecv irrecv(RECV_PIN); // объект декодированных результатов из приёмника ИК-команд decode_results irresult; // Стандартная процедура первоначальной настройки Arduino при запуске void setup() { #if DEBUG Serial.begin(9600); #endif pinMode(LEARN_LED_PIN, OUTPUT); pinMode(WORK_LED_PIN, OUTPUT); irCodeData = loadFromEeprom(IR_CODE_DATA_ADDRESS); // Загрузка кода команды пульта из постоянной памяти irrecv.enableIRIn(); // Запуск приёмника } // Основаная процедура цикла работы Arduino void loop() { processKNOPKAmode(); //МОЯ КНОПКА processLearnButton(); processLearnLed(); processWorkLed(); processIr(); } // Процедура обработки нажатий на ИК-пульте void processIr() { if (irrecv.decode(&irresult)) { // Если распознана команда с пульта long value = irresult.value; #if DEBUG Serial.print("Raw: "); Serial.println(value, HEX); #endif if (0xFFFFFFFF != value) { // Если пришла команда 0xFFFFFFFF, то её нужно игнорировать if (irresult.decode_type == RC6) { // Если протокол пульта RC6 (и возможно RC5), то нужно избавиться от toggle бита (0x8000) value &= ~0x8000LL; } processCode(value); } irrecv.resume(); // Прочитать следующее значение команды с ИК-пульта } } /* Функция возвращает состояние кнопки, с программной защитой от дребезга контактов. @param int pin - Номер пина, к которому подключена кнопка. @param boolean pullUp - Подтянута ли кнопка к Vcc или к земле. true = кнопка подтянута к Vcc false = кнопка подтянута к земле @return int - Состояние кнопки, нажата или нет. 0 = кнопка отпущена 1 = кнопка нажата -1 = неопределённое состояние, дребезг контактов */ int getButtonState(int pin, boolean pullUp) { int pinState = digitalRead(pin); for (int i = 0; i < 3; i++) { delay(10); if (digitalRead(pin) != pinState) { return -1; } } /* Если кнопка с подтягивающим резистором, то нажатие на кнопку инвертировано относительно уровня сигнала на пине. Кнопка нажата - уровень на пине низкий. Кнопка отжата - уровень на пине высокий. */ return pullUp ^ pinState; } // Процедура обработки нажатий на тактовую кнопку Arduino для запуска режима обучения командам пульта void processLearnButton() { int buttonState = getButtonState(LEARN_BUTTON_PIN, true); if (buttonState == -1) { // Неопределённое состояние кнопки return; } if (buttonState == learnButtonState) { // Состояние кнопки не поменялось return; } learnButtonState = buttonState; learnModeEnabled = buttonState; } // МОЯ КНОПКА void processKNOPKAmode() { int buttonState = getButtonState(KNOPKA, true); if (buttonState == -1) { // Неопределённое состояние кнопки return; } if (buttonState == KNOPKAState) { // Состояние кнопки не поменялось return; } if (KNOPKAState = buttonState) { workLedState = !workLedState; } } // Процедура управления светодиодом, показывающим режим обучения. // Если светодиод горит - значит работает режим обучения. void processLearnLed() { digitalWrite(LEARN_LED_PIN, learnModeEnabled); } // Процедура управления светодиодом с пульта. // Кнопка с пульта включает или отключает светодиод. void processWorkLed() { digitalWrite(WORK_LED_PIN, workLedState); } // Процедура обработки кода пульта void processCode(long value) { #if DEBUG Serial.println(value, HEX); #endif if (learnModeEnabled) { // Если включен режим обучения irCodeData = value; // Запомним код saveToEeprom(irCodeData, IR_CODE_DATA_ADDRESS); // Сохраним его в постоянной памяти learnModeEnabled = false; // Выключим режим обучения delay(100); // Задержка, чтобы не включить случайно рабочий светодиод во время режима обучения, если пульт повторяет команды слишком быстро } else if (irCodeData == value) { // Если не включен режим обучения, и если команда совпала с той, которой обучился наш Arduino workLedState = !workLedState; // То меняем состояние рабочего светодиода delay(650); // Задержка, чтобы не было ложных срабатываний рабочего светодиода, если пульт повторяет команды слишком быстро } } // Процедура сохранения 4-байтного целого в постоянную память void saveToEeprom(long value, int address) { int data[2]; data[0] = highWord(value); data[1] = lowWord(value); for (int i = 0; i < 2; i++){ EEPROM.write(address + i * 2, highByte(data)); EEPROM.write(address + i * 2 + 1, lowByte(data)); } #if DEBUG Serial.print("Saved to Eeprom value = "); Serial.print(value); Serial.print(" address = "); Serial.println(address); #endif } // Процедура чтения 4-байтного целого из постоянной памяти long loadFromEeprom(int address) { byte data[4]; for (int i = 0; i < 4; i++){ data = EEPROM.read(address + i); } int high = word(data[0], data[1]); int low = word(data[2], data[3]); long result = makeLong(high, low); #if DEBUG Serial.print("Loaded from Eeprom value = "); Serial.print(result); Serial.print(" address = "); Serial.println(address); #endif return result; }
Прикрутил кнопку, к той теме (которая не моя), ВОПРОС!!!! как убрать включение обучения при запуске контроллера? подскажите, пожалуйста!!! здесь вообще люди живые есть?
убрал автомат обучение при запуске...люди...ау... здесь кто нибудь сидит вообще? просто откликнитесь, помощи уже не прошу
обучение тема сложноватая и я думаю что мёртвая. у меня получилось "поиметь" только один пульт. никакие другие - а хотелось бы пульты от телевизора перехватить, не дались. В основном пытался бороться изменяя частоту. Приёмник TSOP34438 Передатчик TSAL6200 Если кто чего победит, пишите. Правки по коду приветствуются. Код (C++): // --- ir decoder #define IRpin_PIN PIND #define IRpin 2 // the maximum pulse we'll listen for - 65 milliseconds is a long time #define MAXPULSE 65000 //#define MAXPULSE 65535 // what our timing resolution should be, larger is better // as its more 'precise' - but too large and you wont get // accurate timing #define RESOLUTION 20 //#define RESOLUTION 10 // we will store up to 100 pulse pairs (this is -a lot-) uint16_t pulses_hi[100]; // pair is high and low pulse uint16_t pulses_low[100]; // pair is high and low pulse uint8_t currentpulse = 0; // index for pulses we're storing uint8_t pulses_count = 0; // Frequency of HI impulse double Freq = 38000; int Period; // --- ir player //#define IRledPin 13 #define IRledPin 13 #define NumIRsignals 96 //#define PlayIRDelay 10 int PlayIRDelay = 10; // -- file /* * SD карта подключается так: ** MOSI - пин 11 ** MISO - пин 12 ** CLK - пин 13 ** CS - пин 4 */ #include <SPI.h> #include <SD.h>; File myFile; void setup() { // put your setup code here, to run once: Serial.begin(9600); digitalWrite(IRledPin, LOW); //Make sure LED starts "off" // Calculate Period of HI impulse calculate_period(); initialize_sd(); } void loop() { String str; if (Serial.available() > 0) { str = Serial.readStringUntil('\n'); if (str == "decode") { Serial.println("Ready to decode IR!"); decode2(); Serial.print(pulses_count); Serial.println(" puls"); print_data(); } else if (str == "play") { Serial.println("Play"); play3(); Serial.println("Play end"); } else if (str == "print data") { print_data(); } else if (str == "set freq") { Serial.print("Curr Freq is "); Serial.println(Freq); Serial.println("Enter Freq, like 38000"); while (Serial.available() <= 0); Freq = Serial.parseInt(); Serial.println(Freq); calculate_period(); } else if (str == "auto") { for(double n = 10000; n <= 80000; n = n + 1000) { Freq = n; calculate_period(); Serial.print("play "); Serial.println(n); play3(); delay(1000); } } else if (str == "save") { Serial.println("Enter filename"); while (Serial.available() <= 0); String filename = Serial.readStringUntil('\n'); if(filename != "") { save_file(filename); } } else if (str == "load") { Serial.println("Enter filename"); while (Serial.available() <= 0); String filename = Serial.readStringUntil('\n'); if(filename != "") { load_file(filename); } } } }// loop void calculate_period() { double F1 = (1.0 / Freq) * 1000000; Period = round(F1); PlayIRDelay = round(F1 / 2) - 3; Serial.println(Period); Serial.println(PlayIRDelay); } void play3() { for (int i = 0; i < pulses_count; i++) { //Loop through all of the IR timings pulseIR(pulses_hi[i]); delayMicroseconds(pulses_low[i]); //Then turn it off for the right amount of time } } // This function allows us to PWM the IR LED at about 38khz for the sensor // Borrowed from Adafruit! void pulseIR(long microsecs) { // we'll count down from the number of microseconds we are told to wait cli(); // this turns off any background interrupts while (microsecs > 0) { // 38 kHz is about 13 microseconds high and 13 microseconds low digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen delayMicroseconds(PlayIRDelay); // hang out for 10 microseconds, you can also change this to 9 if its not working digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds delayMicroseconds(PlayIRDelay); // hang out for 10 microseconds, you can also change this to 9 if its not working // so 26 microseconds altogether //microsecs -= 26; microsecs -= Period; } sei(); // this turns them back on } void decode2() { uint16_t pulse_time = 0; bool signal_end = false; pulses_count = 0; // wait signal while (IRpin_PIN & (1 << IRpin)) { } while (signal_end == false) { // measure HI signal while (! (IRpin_PIN & _BV(IRpin))) { pulse_time++; delayMicroseconds(RESOLUTION); if (pulse_time > MAXPULSE) { //Serial.println("wait hi"); signal_end = true; } } pulses_hi[pulses_count] = pulse_time; pulse_time = 0; // measure LOW signal while ((IRpin_PIN & (1 << IRpin)) && (signal_end == false)) { pulse_time++; delayMicroseconds(RESOLUTION); if (pulse_time > MAXPULSE) { signal_end = true; //Serial.println("wait low"); } } pulses_low[pulses_count] = pulse_time; pulses_count++; pulse_time = 0; } pulses_low[pulses_count - 1] = 0; // multiple for (int n = 0; n < pulses_count; n++) { pulses_hi[n] = pulses_hi[n] * RESOLUTION; pulses_low[n] = pulses_low[n] * RESOLUTION; } Serial.println(pulses_count); } void print_data() { for (int n = 0; n < pulses_count; n++) { Serial.print(n); Serial.print("\t"); // tab Serial.print(pulses_hi[n]); Serial.print("\t"); // tab Serial.println(pulses_low[n]); } } bool initialize_sd() { //Serial.println("Init SD"); // Магия. Этот вывод должен быть настроен как выход. // Иначе, некоторые функции могут не работать. pinMode(10, OUTPUT); if (!SD.begin(4)) { Serial.println("sd failed!"); return false; } //Serial.println("sd done."); return true; } bool file_exists(String filename) { char char_filename[50]; filename.toCharArray(char_filename, filename.length() + 1); if (SD.exists(char_filename)) { return true; } else { return false; } } bool save_file(String filename) { char char_filename[50]; filename.toCharArray(char_filename, filename.length() + 1); if (SD.exists(char_filename)) { Serial.println("already exist"); SD.remove(char_filename); Serial.println("remove ok"); } myFile = SD.open(filename, FILE_WRITE); if (myFile) { myFile.println("freq"); myFile.println(Freq); myFile.println("puls"); myFile.println(pulses_count); myFile.println("data"); for (int n = 0; n < pulses_count; n++) { myFile.println(pulses_hi[n]); myFile.println(pulses_low[n]); } myFile.close(); Serial.println("file ok"); } else { Serial.println("error file"); } } bool load_file(String filename) { if(file_exists(filename) == false) { Serial.println("file not found"); return false; } myFile = SD.open(filename); String s = myFile.readStringUntil('\n'); // freq s = myFile.readStringUntil('\n'); Freq = s.toInt(); Serial.println(Freq); calculate_period(); s = myFile.readStringUntil('\n'); // pulses_count s = myFile.readStringUntil('\n'); pulses_count = s.toInt(); Serial.println(pulses_count); s = myFile.readStringUntil('\n'); // data for(int n = 0; n < pulses_count; n++) { s = myFile.readStringUntil('\n'); int a = s.toInt(); pulses_hi[n] = a; //Serial.print(pulses_hi[n]); Serial.print(n); Serial.print(" "); Serial.print(s); Serial.print(" "); s = myFile.readStringUntil('\n'); a = s.toInt(); pulses_low[n] = a; //Serial.println(pulses_low[n]); Serial.println(s); } myFile.close(); return true; }
и кстати даже в текущем коде ардуино привередлив к пинам. считывание только из 2го - возможно особенность кода считывания. но больше всего удивляет работа диода только на 13м - на других не пашет. на китайском уно на 341 чипе не пашет вообще ничего )