IR+Arduino

Тема в разделе "Arduino & Shields", создана пользователем Sashok26rus, 29 май 2012.

  1. Sashok26rus

    Sashok26rus Нерд

    Здравствуйте!

    Вопрос такой, как сделать, чтобы при получении конкретных команд включались светодиоды на пинах ардуино?ардуина принимает и распознаёт сигналы пульта. То есть напрмер кнопка "вкл" расшифровыется - 502A0540 а кнопка off - F0FE1FC3

    Полученные значения свободно выводяся в ком порт

    Вот нашел аналогичный вопрос, но ответа на него так и не нашел: http://arduino.ru/forum/programmirovanie/vypolnit-komandy-s-ik-pulta

    Пробовал через оператор If ничего не выходит =(
    вот код:

    Код (Text):
    volatile unsigned long IR_KEY;  //код кнопки на пульте
     
    void setup() {    
      Serial.begin(9600);
      pinMode(2, INPUT);    // ИК приемник подключим сюда
      IR_KEY = 0;
      attachInterrupt(0,IRinterrupt,FALLING); // назначим прерывание
    }
     
    void loop() {
    if(IR_KEY) {
      Serial.println(IR_KEY,HEX); //выводим код в терминал.
      IR_KEY = 0;
    }
    }
     
    /* обработчик прерывания*/
    void IRinterrupt(){
      static unsigned long key, prevTime;
      unsigned long currTime, d;
      currTime = micros();
      d = currTime - prevTime;
      if(d < 1100) return;        // "дребезг"
      if(d < 1400){              // "0"
        key = key << 1;
        prevTime = currTime;
        return; }
      if(d < 2400){              // "1"
        key = key << 1;
        key++;
        prevTime = currTime;
        return;}
      if(d < 13000) IR_KEY = key; // код кнопки получен
      prevTime = currTime;
    }
     
  2. Unixon

    Unixon Оракул Модератор

    Ну вы верно мыслите, сравнивайте IR_KEY с известными кодами через if-else или switch-case и прописывайте реакции на команды.

    Код (Text):

    switch (IR_KEY)
    {
     case 0x502A0540UL:
     {
      // turn LED on
      break;
     }
     case 0xF0FE1FC3UL:
     {
      // turn LED off
      break;
     }
     default:
     {
      // reaction for unknown code
      break;
     }
    }
     
    Единственная проблема здесь, поскольку платформа программно 16-разрядная (а аппаратно вообще 8-разрядная), то для обработки 32-разрядных чисел возможно что-то придется подкорректировать.
     
    nailxx и Sashok26rus нравится это.
  3. nailxx

    nailxx Официальный Нерд Администратор

    Должен, должен получиться if:

    Код (Text):

    void loop() {
        if (!IR_KEY) {
            return;
        }

        // пусть, если кнопка не известна включается
        // светодиод на пине 13
        int ledToLightUp = 13;

        if (IR_KEY == 0x502A0540)
            ledToLightUp = 12;
        else if (IR_KEY == 0xF0FE1FC3)
            ledToLightUp = 11;

        digitalWrite(ledToLightUp, HIGH);

        Serial.println(IR_KEY,HEX); //выводим код в терминал.
        IR_KEY = 0;
    }
     
    Ясна ли идея?
     
    Sashok26rus нравится это.
  4. Sashok26rus

    Sashok26rus Нерд

    Спасибо большое за ответ.
    Я попробовал вот так:
    Код (Text):
    volatile unsigned long IR_KEY;  //код кнопки на пульте
     int ledPin = 11;
     int ledPin2 = 13;
    void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(ledPin2, OUTPUT);
      Serial.begin(9600);
      pinMode(2, INPUT);    // ИК приемник подключим сюда
      IR_KEY = 0;
      attachInterrupt(0,IRinterrupt,FALLING); // назначим прерывание
    }
     
    void loop() {
    if(IR_KEY) {
      Serial.println(IR_KEY,HEX); //выводим код в терминал.
      IR_KEY = 0;
    }
    }
     
    /* обработчик прерывания*/
    void IRinterrupt(){
      static unsigned long key, prevTime;
      unsigned long currTime, d;
      currTime = micros();
      d = currTime - prevTime;
      if(d < 1100) return;        // "дребезг"
      if(d < 1400){              // "0"
        key = key << 1;
        prevTime = currTime;
        return; }
      if(d < 2400){              // "1"
        key = key << 1;
        key++;
        prevTime = currTime;
        return;}
      if(d < 13000) IR_KEY = key; // код кнопки получен
      prevTime = currTime;
     
        if (!IR_KEY) {
            return;
        }
        // пусть, если кнопка не известна включается
        // светодиод на пине 13
        int ledToLightUp = 13;
     
        if (IR_KEY == 0x502A0540)
            ledToLightUp = 12;
        else if (IR_KEY == 0xF0FE1FC3)
            ledToLightUp = 11;
     
        digitalWrite(ledToLightUp, HIGH);
     
        Serial.println(IR_KEY,HEX); //выводим код в терминал.
        IR_KEY = 0;
    }
     
    При нажатии 13 пин светится, аналогично при нажатии кнопки off светится светодиод на пине 11. Но оба они еле светят.
     
  5. nailxx

    nailxx Официальный Нерд Администратор

    Еле светят — странно. Можно было бы объяснить эффектом ШИМ, но мы же их нигде не выключаем, только включаем.

    Уверенны, что это не аппаратная проблема? Не забыли ли для них сделать pinMode(lala, OUTPUT)? Можете в setup'е их напрямую включить и посмотреть на яркость?
     
    Sashok26rus нравится это.
  6. Unixon

    Unixon Оракул Модератор

    А вы pinMode(*,OUTPUT) в setup() не забыли случайно ?
     
    Sashok26rus нравится это.
  7. Sashok26rus

    Sashok26rus Нерд

    Ой ну конечно же забыл, спасибо. Исправил яркость как надо!
     
  8. Sashok26rus

    Sashok26rus Нерд

    Unixon, Спасибо! Очень хорошая и понятная система switch-case вот по вашему примеру:
    Код (Text):
      switch (IR_KEY)
    {
    case 0x502A0540UL:
    digitalWrite(ledPin,HIGH); // при нажатии на кнопку светодиод ставим в HIGH
    {
        break;
    }
    case 0xF0FE1FC3UL:
    digitalWrite(ledPin,LOW); // нажатием на другую кнопку светодиод выключаем
    {
      break;
    }
    default:
    {
      break;
    }
    }
    И еще можно подробнее о
    default:
    {
    break;

    СПАСИБО ОГРОМНОЕ ЗА ПОМОЩЬ!
     
  9. Steelwolf

    Steelwolf Нерд

    Default описывает состояние, когда ни одно значение не совпадает с предлагаемыми. То есть, если сравниваемый параметр/значение не совпадает с перечисляемыми внутри оператора switch, то происходит действие по умолчанию (default), описываемое внутри самого default.
    Default не является обязательным, его можно опустить, тогда по умолчанию, если совпадений нет, действия не будет происходить.
    Иначе можно представить условным оператором и уже внутри условного оператора описывать действие в случае если совпадений не было. Но это изобретение велосипеда и нужно лишь тогда, когда надо проверить изменяемые переменные или массивы переменных.
    По поводу break - прерыватель/выход из цикла, то есть если конец явно не указан, то перебор будет осуществляться по всем параметрам, а не до первого совпадения.
     
  10. Иван С

    Иван С Гик

    Офтоп. Обязательно прерывания юзать для ir?
     
  11. Unixon

    Unixon Оракул Модератор

    Нет, не обязательно. Но, видите какое дело... Тут выбор то не велик: или постоянный опрос датчика (polling) или прерывания, третьего способа как то пока никто не придумал. Опрос означает либо невозможность делать что-то еще, либо вероятный пропуск команд. Прерывания в этом смысле более надежны, поскольку позволяют МК заниматься своими делами, пока от датчика ничего не приходит, но гарантируют своевременную реакцию на отслеживаемое воздействие
     
  12. Steelwolf

    Steelwolf Нерд

    Ну да, иначе говоря, с прерываниями МК будет действовать с запозданием, то есть часть начальных команд он пропустит. Если опрос ведется постоянно, то МК принимает все состояния датчика с нужной нам частотой.
    Вот конкретно с прерыванием команды опроса датчика я себе плохо представляю, так как если импульс приходит от передатчика к приемнику а МК в этот момент его не опрашивает, а скажем просто следит за изменением напряжения на выходе датчика (что проще), то какое-то начальное количество команд он пропустит и только потом через n попыток начинает обрабатывать последовательность команд. Например, нажимаем на пульте кнопку включения 5 раз и только на 5й раз команда включения была обработана МК, так как он не опрашивал порт, а только следил за изменением напряжения, то есть напряжение изменилось, МК перешел в режим опроса.
     
  13. Unixon

    Unixon Оракул Модератор

    Ровно наоборот. С прерываниями пропуск возможен только если другое прерывание происходит во время обработки первого и приоритет прерываний всего один.

    Вы как то не так себе обработку прерывания представляете. Как оно работает: дернулась нога - МК положил текущий адрес в стек и немедленно перешел к обработчику прерывания (который у вас тут же считывает команду с датчика) потом МК берет адрес со стека и продолжает выполнение основной программы. И так по каждому фронту импулься. С ИК приемниками разница между частотой импульсов и тактовой частотой МК такая, что ничего пропустить невозможно.
     
    Sashok26rus нравится это.
  14. Steelwolf

    Steelwolf Нерд

    Хм. Вполне вероятно. Я плохо еще представляю принцип работы прерывания в архитектуре МК.
     
  15. Sashok26rus

    Sashok26rus Нерд

    Здравствуйте!
    Появился вопросик как можно изменить код:
    Код (Text):
    volatile unsigned long IR_KEY;  //код кнопки на пульте
    int ledPin = 11;
    int ledPin3 = 12;
    int ledPin2 = 13;
    void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    pinMode(ledPin3, OUTPUT);
      Serial.begin(9600);
      pinMode(2, INPUT);    // ИК приемник подключим сюда
      IR_KEY = 0;
      attachInterrupt(0,IRinterrupt,FALLING); // назначим прерывание
    }
     
    void loop() {
    if(IR_KEY) {
      Serial.println(IR_KEY,HEX); //выводим код в терминал.
      IR_KEY = 0;
    }
    }
     
    /* обработчик прерывания*/
    void IRinterrupt(){
      static unsigned long key, prevTime;
      unsigned long currTime, d;
      currTime = micros();
      d = currTime - prevTime;
      if(d < 1100) return;        // "дребезг"
      if(d < 1400){              // "0"
        key = key << 1;
        prevTime = currTime;
        return; }
      if(d < 2400){              // "1"
        key = key << 1;
        key++;
        prevTime = currTime;
        return;}
      if(d < 13000) IR_KEY = key; // код кнопки получен
      prevTime = currTime; // ПОЛУЧЕНИЕ КОДА С ПУЛЬТА
     
     
      switch (IR_KEY)
    {
    case 0x2E7265CE:
    digitalWrite(ledPin,HIGH);
    {
      // turn LED on
      break;
    }
    case 0x2E74E5CE:
    digitalWrite(ledPin,LOW);
     
      case 0x2E7065CE:
    digitalWrite(ledPin3,HIGH);
    {
      // turn LED on
      break;
    }
    case 0x2E7465CE:
    digitalWrite(ledPin3,LOW);
    {
      // turn LED off
      break;
    }
     
    {
      // reaction for unknown code
      break;
    }
    }
    }
     
    Цель: чтобы при зажатии кнопки светодиод светился, а как бросил сразу же погас.
    прошу помочь!
     
  16. Unixon

    Unixon Оракул Модератор

    В обработчике прерывания если (d>=13000), т.е. код не получен, можно все выключать. Вообще, лучше всё, начиная с switch(IR_KEY), вынести в loop(). Старайтесь всегда делать обработчики прерываний максимально короткими. Добавьте что-нибудь вроде if (d>26000) IR_KEY=0; т.е. через два максимальных времени приема убираем код команды, а switch внури loop() при этом пойдет по ветке case default и внутри нее отключит индикацию.
     
  17. Sashok26rus

    Sashok26rus Нерд

    Спасибо, попробую!
     
  18. КвазИ

    КвазИ Нерд

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

    т.е. когда выключено то на другие кнопки с ик пульта чтобы не реагировал..
     
  19. Salk

    Salk Гик

    Зависит от пульта. Если у Вас пульт имеет на одной кнопке два кода, которые чередуются, то просто расписывайте действие для каждого кода.
    Если же только один, то можно воспользоваться банальным счетчиком
    PHP:
    int h;
    // Жмем кнопку пульта
    if (results.value == 66589)
        {
          h = h + 1; // к переменной "h" каждый раз, при нажатии одной кнопки, прибавляем +1
          // Если нужно вернуться к первому действию при достижении последнего
          if (h == 2)
          {
            h = 0; // сбрасываем "h", возвращаемся в начало
          }
        }

    // Тут выполняем любые действия согласно нашему счетчику
    if (h == 0) // изначально выключено
    {
    off;
    }
    if (h == 1) // нажали кнопку - включили
    {
    on;
    }
     
  20. КвазИ

    КвазИ Нерд

    у меня пульт выдает один код а при длительном нажатии fffffff