Как прикрутить обучение ик пульту? вот что я имею...(сырой новичок)

Тема в разделе "Arduino & Shields", создана пользователем lonely_jack, 19 окт 2015.

  1. lonely_jack

    lonely_jack Нуб

    Код (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");        // обозначение минимальной температры

    }
    }
     
     
  2. lonely_jack

    lonely_jack Нуб

    в общем без learnled и learnbutton все работает с заранее заданной командой ик пульта. на дисплей не обращайте внимания, он тут так - постольку поскольку. хочется прикрутить функцию обучения при нажатии кнопки обучения, чтобы считал код, записал в eeprom, а потом оттуда брал для управления светодиодом (нагрузкой). читал вот эту тему
    http://forum.amperka.ru/threads/Управление-светодиодом-с-ИК-пульта-Есть-режим-обучения-командам.3376/
    там все здорово, и я бы ее модифицировал под себя, но пока не въезжаю в данный код, и ее минус - обучение запускается автоматом при подаче питания, а хотелось бы просто с кнопки. помогите кто чем может. этот код - то, что я имею своими скудными силами, обучение ик у меня не получается (светодиод загорается, иногда рабочий светодиод вместе с кнопкой). Еще мне понравилось в приведенной ссылке, что пульт от моего смарт тв (самсунг) тоже воспринимается. что там не понравилось - при длительном удержании кнопки пульта - светодиод моргает. Помогите, плз, всю голову сломал. нужно управление нагрузкой и с кнопки и с пульта ик. Спасибо
     
  3. lonely_jack

    lonely_jack Нуб

    *
    Пример программы для управления светодиодом с ИК-пульта.
    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;
    }
     
  4. lonely_jack

    lonely_jack Нуб

    Прикрутил кнопку, к той теме (которая не моя), ВОПРОС!!!! как убрать включение обучения при запуске контроллера? подскажите, пожалуйста!!! здесь вообще люди живые есть?
     
  5. lonely_jack

    lonely_jack Нуб

    убрал автомат обучение при запуске...люди...ау... здесь кто нибудь сидит вообще? просто откликнитесь, помощи уже не прошу
     
  6. abdurino

    abdurino Нуб

    обучение тема сложноватая и я думаю что мёртвая.
    у меня получилось "поиметь" только один пульт.
    никакие другие - а хотелось бы пульты от телевизора перехватить, не дались.

    В основном пытался бороться изменяя частоту.
    Приёмник 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;
    }



     
     
  7. abdurino

    abdurino Нуб

    и кстати даже в текущем коде ардуино привередлив к пинам.
    считывание только из 2го - возможно особенность кода считывания.
    но больше всего удивляет работа диода только на 13м - на других не пашет.

    на китайском уно на 341 чипе не пашет вообще ничего )
     
  8. abdurino

    abdurino Нуб

    топикстартер свалил? ))))
    вот статья описывающая насколько это мутная тема
    http://anteh.ru/apg4.html