выполнить команды с Ик пульта

Vitaly
Offline
Зарегистрирован: 12.09.2011

 Всем привет.

Суть в следующем: с помощью библиотеки  IRremote.h

(взято отсюда http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html)

 ардуина принимает и распознаёт сигналы пульта. То есть напрмер кнопка "вкл" расшифровыется - 41BEF00F, а кнопка "ок" - 41BEE01F.

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

Вопрос такой, как сделать, чтобы при получении конкретных команд включались светодиоды на пинах ардуино? Я так понимаю, что раз команды распознаются, то их можно сравнить с заранее указанными значениями и если они совпадают, то включать светодиод. С помощью каких функций это возможно сделать?

вот собственно код:

#include <IRremote.h>
int RECV_PIN = 11;
int RELAY_PIN = 4;
int pin5 =5;
IRrecv irrecv(RECV_PIN);
decode_results results;
// Dumps out the decode_results structure.
// Call this after IRrecv::decode()
// void * to work around compiler issue
//void dump(void *v) {
// decode_results *results = (decode_results *)v
void dump(decode_results *results) {
int count = results->rawlen;
Serial.print(results->value, HEX);
Serial.println("");
}
void setup()
{
delay (1000);
pinMode(RELAY_PIN, OUTPUT);
pinMode(5, OUTPUT);
pinMode(13, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
int on = 0;
unsigned long last = millis();
void loop() {


if (irrecv.decode(&results)) {
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
on = !on;
digitalWrite(RELAY_PIN, on ? HIGH : LOW);
digitalWrite(13, on ? HIGH : LOW);
dump(&results);
}
last = millis();
irrecv.resume(); // Receive the next value
}
}

 

В этой программе ардуино включает и выключает светодиод просто по любой команде с пульта. А полученый код отправляет в ком порт.

UPDATE от модератора: я поправил фоматирование. Вы можете сами пользоваться кнопочкой вставки кода, также красивше.

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

Ни разу не работал с IR, взможно там и есть какие-то функции для этого, но думаю можно сделать как-то так:

switch (value) { // value - это переменная, содержащая сигнал с пульта
   case 41BEF00F: // следующие строки (до оператора break) выполнятся если value = 41BEF00F
      digitalwrite(10,1);
      break;

   case 41BEE01F: // а следующие строки выполнятся если value = 41BEE01F
      digitalwrite(11,1);
      break;

   // так можно продолжать и далее

   default: // а вот эти строки выполнятся, если value не будет равно ни одному из указанных выше значений
      digitalwrite(10,0);
      digitalwrite(11,0);

}

 

Vitaly
Offline
Зарегистрирован: 12.09.2011

 HOCKU, не получается обратится к "value". Ошибка "value" is not declarated in this scoupe. пробовал и results.value., всё равно не срабатывает.  Нужно по другому как то. 

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

А в какую собственно переменную записывается значение, получаемое с IR сенсора?

Вот эту переменную и надо подставить вместо value в конструкции switch-case.

Vitaly
Offline
Зарегистрирован: 12.09.2011

 Вот так нужно написать: if (results->value == 0x41BEF00F) { }. Работает.

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

Ну отлично. а если results->value подставить в switch вместо value?

  switch(results->value)

Вероятно так тоже заработает)

Просто конструкция switch-case более удобна в том случае, когда нужно перебирать много значений одной переменной.

Diemon
Offline
Зарегистрирован: 18.11.2011

Для начала хотелось бы сказать,что библиотека IRremote на arduino-1.0 не заработала. Скетч не хотел компилиться и выдавал кучу ошибок. Скачав прошлую версию arduino-0023 скетч без проблем скомпилился.

Лично у меня способ с if (results.value == 0x41BEF00F) { } не заработал. Я так понимаю что код с пульта это 41BEF00F. У меня заработало когда я в Serial.println глянул значение НЕ в HEX, и уже потом его ввел в конструкцию if. Примерно вот так:

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(10, OUTPUT);

}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value);
     if (results.value == 4151455000) { 
     digitalWrite(10,HIGH);
   }
    irrecv.resume(); // Receive the next value
  }
}

 

 

mitos
Offline
Зарегистрирован: 11.12.2011

думал только у меня проблема с библиотекой для IR.

есть ли возможность использовать ее с   arduino-1.0 ?

 

Diemon
Offline
Зарегистрирован: 18.11.2011

Оказывается возможность есть! Одно из изменений в ардуино-1.0 это переименование WProgram.h в Arduino.h . Соответственно чтобы работала ардуино нужно все упоминания в библиотеке об WProgram.h нужно заменить на Arduino.h. Проделав это, у меня скетч скомпилировался. Переделанная библиотека:

www3.zippyshare.com/v/24546193/file.html

mitos
Offline
Зарегистрирован: 11.12.2011

Diemon

Большое спасибо !

Все заработало !

mitos
Offline
Зарегистрирован: 11.12.2011

Немного поигрался с приемом сигнала с пульта и возник вопрос.

Почему вместо кода который распознается надо писать 0x и код , что означает 0x ?

 

step962
Offline
Зарегистрирован: 23.05.2011

mitos пишет:

Почему вместо кода который распознается надо писать 0x и код , что означает 0x ?

Префикс 0x означает, что далее следует шестнадцатиричный код.

Префикс 0 означает, что далее следует восьмиричный код.

Префикс B означает, что далее следует двоичный код.

www.arduino.ru/Reference/IntegerConstants

mitos
Offline
Зарегистрирован: 11.12.2011

как все просто, когда знаешь где смотреть.

Спасибо ! 

Diemon
Offline
Зарегистрирован: 18.11.2011

 а получилось ли у когото использовать конструкцию switch case? Типа такого:

   switch(results.value) {
     case 0xF7722D18:
       digitalWrite(FORWARD_PIN,HIGH);
     case 0xEC74525E:
       digitalWrite(RIGHT_PIN,HIGH);
       digitalWrite(FORWARD_PIN,HIGH);
     case 0x4FDA1A25:
       digitalWrite(LEFT_PIN,HIGH); 
       digitalWrite(FORWARD_PIN,HIGH);
     case 0x52DA1EDC:
       digitalWrite(BACKWARD_PIN,HIGH);
      case 0x5A75109A:
       digitalWrite(RIGHT_PIN,HIGH); 
       digitalWrite(BACKWARD_PIN,HIGH);
     case 0xDCC5C566:
       digitalWrite(RIGHT_PIN,HIGH); 
       digitalWrite(BACKWARD_PIN,HIGH);
     default:
       digitalWrite(RIGHT_PIN,LOW); 
       digitalWrite(BACKWARD_PIN,LOW);
       digitalWrite(LEFT_PIN,LOW); 
       digitalWrite(FORWARD_PIN,LOW);
   }  

У меня такой код не захотел работать. Хотя такой работает без проблем:

if (results.value == 0xF7722D18) {
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0xEC74525E) {
     digitalWrite(RIGHT_PIN,HIGH);
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0x4FDA1A25) {
     digitalWrite(LEFT_PIN,HIGH); 
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0x52DA1EDC) {
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else if (results.value == 0x5A75109A) {
     digitalWrite(RIGHT_PIN,HIGH); 
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else if (results.value == 0xDCC5C566) {
     digitalWrite(LEFT_PIN,HIGH); 
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else {
       digitalWrite(RIGHT_PIN,LOW); 
       digitalWrite(BACKWARD_PIN,LOW);
       digitalWrite(LEFT_PIN,LOW); 
       digitalWrite(FORWARD_PIN,LOW);
     
        }     

 

step962
Offline
Зарегистрирован: 23.05.2011

 В каждую ветвь case после уже имеющихся инструкций поместите оператор break; - вдруг поможет?

Elektro
Offline
Зарегистрирован: 10.02.2012

я использую конструкцию с IF  проблема в том что если нажать и держать кнопку пульт сначала передаст индивидуальный код кнопки а потом начинает слать код что кнопка нажата, этот код ля все один, как сделать что бы при удерживании кнопки например горел светодиод а при отпускании гас? 

Diemon
Offline
Зарегистрирован: 18.11.2011

 Когда делал код, столкнулся с той же проблемой. Пульт передает периодически один и тот же сигнал(нажата кнопка). Тоесть сигнал-пауза-сигнал-пауза и так далее. Поидее нужен какойто таймер, чтобы если через определенный промежуток времени после последнего сигнала не следует следующий, то нужно выключать двигатель/светодиод.

У меня сделано так, коряво но кое как работает. Как сделать по другому - не знаю

#include <IRremote.h>

int RECV_PIN = 8;
int FORWARD_PIN = 5;
int BACKWARD_PIN = 4;
int LEFT_PIN = 6;
int RIGHT_PIN = 7;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(FORWARD_PIN, OUTPUT);
  pinMode(BACKWARD_PIN, OUTPUT);
  pinMode(LEFT_PIN, OUTPUT);
  pinMode(RIGHT_PIN, OUTPUT);

}

void loop() {
        delay (300);
       digitalWrite(RIGHT_PIN,LOW); 
       digitalWrite(BACKWARD_PIN,LOW);
       digitalWrite(LEFT_PIN,LOW); 
       digitalWrite(FORWARD_PIN,LOW);     
  if (irrecv.decode(&results)) {
   if (results.value == 0xF7722D18) {
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0xEC74525E) {
     digitalWrite(RIGHT_PIN,HIGH);
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0x4FDA1A25) {
     digitalWrite(LEFT_PIN,HIGH); 
     digitalWrite(FORWARD_PIN,HIGH);
     }
   else if (results.value == 0x52DA1EDC) {
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else if (results.value == 0x5A75109A) {
     digitalWrite(RIGHT_PIN,HIGH); 
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else if (results.value == 0xDCC5C566) {
     digitalWrite(LEFT_PIN,HIGH); 
     digitalWrite(BACKWARD_PIN,HIGH);
     }
   else {
       digitalWrite(RIGHT_PIN,LOW); 
       digitalWrite(BACKWARD_PIN,LOW);
       digitalWrite(LEFT_PIN,LOW); 
       digitalWrite(FORWARD_PIN,LOW);
        }     
     irrecv.resume(); // Receive the next value  4151455000
  }
}    

То есть через delay (300); ардуино выключает двигатели а потом снова включает по сигналу пульта. Так как выключение-включение происходит быстро, то это почти не заметно изза инерционности самих двигателей.  Задержка подбиралась методом тыка.

Elektro
Offline
Зарегистрирован: 10.02.2012

 хм... спасибо попробую потестирую с delay

 

а еще вот у меня пульт другой он немного не так работает, сначала шлет код кнопки а за ним идет общий код если кнопку удерживать тоесть смотри в Serialпример

111111000 - нажали один раз

111111111 - если удерживать

111111111

111111111

 

есть мысли какие? 

Diemon
Offline
Зарегистрирован: 18.11.2011

 Вся соль в том, что пульт шлет сигналы с некоторым промежутком. И ардуине непонятно, то ли пауза между сигналами то ли кнопка отжата и сигнала больше не будет. Через delay конечно коряво и неправильно)

В университете, когда изучали intel 8051 нам рассказывали что применяют спец таймер. Задается время таймера, и он циклически работает. А из программы микроконтроллера этот таймер сбрасывается в начало.

Например: задержка между сигналами с пульта 0.2 сек. Таймер настраивается на время >0.2с, пусть будет 0.3с. Так вот, когда пришел сигнал с пульта, то таймер опять сбрасывается в начало и начинает считать от 0.3 до 0. Если через 0.2с сигнал опять пришел, то таймер опять сбрасывается и т.д. То есть если идут сигналы с пульта, то таймер никогда не доходит до 0. А вот если сигнал не пришел через 0.2 секунды, то таймер доходит до нуля, и должен, в вашем случае выключить светодиод. 

Но как это сделать на ардуине - пока не знаю, про таймеры честно говоря не читал, пока времени не хватает. Другой способ решения проблемы пока себе не представляю.

Elektro
Offline
Зарегистрирован: 10.02.2012

вообшем нашел пример http://www.youtube.com/watch?v=_1om5E--8FM&feature=endscreen&NR=1 тут у человека работает все как надо) 

if (remote()=="551489775") {
delay(50);
    while(remote()=="4294967295") {
digitalWrite(led, HIGH);
    }
     digitalWrite(led, LOW);
  } 

//The function
String remote () {
  String code = "";
 if (irrecv.decode(&results)) {
   code += String (results.value, HEX);
   irrecv.resume(); // Receive the next value
       return(code);
   } 
}

скетч вроде тот что он использовал(как написано на форуме) 

я пока что не могу заставить его работать( 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

...

а еще вот у меня пульт другой он немного не так работает, сначала шлет код кнопки а за ним идет общий код

...

есть мысли какие? 

Не совсем понятно какие мысли вас интересуют. 

Ну да.. разные пульты работают по разному (особенно разных производителей). По разному кодируют сигналы, по разному сообщают о "удерживании кнопки". Я встречал три основных подхода:

  1. Тупо повторяет код нажатой кнопки. Самый плохой вариант. Невозможно отличить быстрое нажатие от удержания.
  2. Первый раз шлем код кнопки, а потом "код повторения" (и он тоже может быть у разных пультов разный). Похоже это ваш случай.
  3. Каждая кнопка имеет два кода. Отличающиеся одним битом. Как правило первым. Например кнопка "Volume Up" может иметь  два кода B00001101 и B10001101. При каждом нажатии пульт шлет их "по очереди". Один раз нажали послал первый код, второй раз нажали - послал второй, третий - опять первый. Нажали и держим - посылает все время один и тот же (тот который на данное нажатие был "на очереди").

 

Или вас интересовало "как обрабатывать" такую ситуацию? (когда шлется код повторения)

 

 

 

Elektro
Offline
Зарегистрирован: 10.02.2012

 я столкнулся с двумя типами который сначала шлет код кнопки а потом код повторения, и с пультом который поочереди шлет два разных кода.

у меня не получается оброботать ни один из вариантов и я хотел бы получить помощи))) 

на видео у человека пульт второго типа( я знаю, потому что у меня такойже) так вот он смог обработать такой сигнал на форуме есть пример кода, но я немогу его заставить работать. можете помоч мне? 

leshak
Offline
Зарегистрирован: 29.09.2011

 

Elektro пишет:

но я немогу его заставить работать. можете помоч мне?

Не знаю. Но попытаться можно. По крайней мере указать на те ошибки которые мне видны (но не факт что нет других).

Для начала, я думаю сделать две вещи: "плюнуть на код который вы нашли на форуме" (он может работать только при удачной фазе луны) и танцевать от кода данного Diemon. С ним тоже не "все здорово", но пошагово его можно привести в чувство. И второе: где только можно - отказаться от delay (не буду сейчас расписывать почему, но он очень часто является "самонаступаемыми граблями").

Слона нужно "есть по кусочку". Для начала, мне  видится две задачи которые нужно решить:

  1. Добится что-бы светодиод горел какое-то время после нажатия кнопки (без использования delay, с сохранением способности контроллера выполнять другие задачи).
  2. Добится что-бы "код повторения" обратывался так же и "последняя нажатая клавиша".

Согласны идти по этим шагам? (а я, пока, подниму машину с Arduino IDE, давно не брал в руки шашку, да попробую накидать пару примеров).

 

Elektro
Offline
Зарегистрирован: 10.02.2012

 у меня получился изначально такойж код как у Diemon. так что можно и от него плясать.

как раз над этим я и ломаю голову. 

давайте, буду вам благодарен)  

leshak
Offline
Зарегистрирован: 29.09.2011

Попробуйте вот такой скетч

int LED_PIN = 9;
int ledCounter=0;// будем использовать этот счетчик, для определения сколько раз нужно прокрутить loop перед тем как погасить диод

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  irrecv.enableIRIn(); // Start the receiver
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN,LOW);

}

void loop() {
  
   // Логика получения нажатий от пульта, тут мы фактически "регистрируем факт нажатия"
   if(irrecv.decode(&results)){ // на пульте что-то нажали
   
       if(results.value == 0xEC74525E){ // тут подставляем код кнопки которая должна включать светодиод

          ledCounter=5000; // подбираем это число. оно указывает сколько раз прокрутиться loop, прежде чем выключится диод (если в это время не будет новых нажатий).
       }
       
       irrecv.resume(); // получить следующие значение
   } 
   
   // а теперь обрабатываем "зарегистрированные факты"
   if(ledCounter>0){ // тут что-то не нулевое, значит нужно включить или продолжать светить
       digitalWrite(LED_PIN,HIGH);
       ledCounter--; // уменьшаем счетчик, один проход выполнен
       
   } else { // счетчик дошел до нуля, значит "пора гасить"
       digitalWrite(LED_PIN,LOW);
   }

}    

 Ожидаемое поведение: после нажатия кнопки, диод должен еще гореть "какое-то время". "Время" подкручиваем в строке 21.

Если даже на больших цифрах видимой на глаз задержки нет - пробуем в конце loop вставить маленький delay. В диагностических целях. Потом уберем его. Прийдется чуть сложней логику сделать, но нужно вначале попробовать "что попроще".

Если "ожидаемое поведение" наблюдается - сообщите, будем дальше копать.

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

leshak
Offline
Зарегистрирован: 29.09.2011

 Ладно, поехали дальше.
Обрабатываем "повторение".
Кстати код 111111111 - это не пульт шлет. О повторении он сообщает несколько сложней. Это уже сама библиотека IRremote.h так сообщает о том что "распознала повторение".
У нее есть дефайнах есть REPEAT 0xffffffff. Лучше использовать его.

...

int lastPressedKey=0; //  тут будем запоминать последнюю нажатую клавишу, что-бы знать что делать, если пришел код повторения.

...

 void loop(){ 
   if(irrecv.decode(&results)){ // на пульте что-то нажали
   
       int keyCode=results.value; // дальше будем проверять значение этой переменной, а не  results.value

       if(keyCode==REPEAT) keyCode=lastPressedKey; // пришел код ПОВТОРЕНИЕ, значит нужно сделать вид что еще раз нажали предыдущую клавишу.
       
       if(keyCode == 0xEC74525E){ // тут подставляем код кнопки которая должна включать светодиод
...
       }
       
       // запоминаем код нажатой клавиши, пригодится если прийдет код повторения
       if(keyCode!=REPEAT){ // сам код повторения запоминанть не нужно, предотвращаем затирание кода реальной клавиши
          lastPressedKey=keyCode; // запомнили
       }
       
 ...
   } 
   
 ....

Троеточия означают "ничего не поменялось". Все так же как в предыдущем скетче

Elektro
Offline
Зарегистрирован: 10.02.2012

leshak пишет:

 
Кстати код 111111111 - это не пульт шлет.

я знаю, это я просто как пример привел

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

leshak пишет:

 
Кстати код 111111111 - это не пульт шлет.

я знаю, это я просто как пример привел

Ну я же не телепат. Лучше перебдеть... :) Тем более что и другие ветку читать могут. Вы знаете, а другие могут не знать. Тут люди очень разного уровня.

Так что со скетчами, как себя ведут?

Elektro
Offline
Зарегистрирован: 10.02.2012

 вообще первый скетч работает, нажимаем кнопку светодиод вспыхивает и тухнит,

второй, может быть я не правельно их совместил, не работает вот проверте меня

#include <IRremote.h>
int LED_PIN = 13;
int RECV_PIN = 11;
int ledCounter=0;
int lastPressedKey=0; //  тут будем запоминать последнюю нажатую клавишу, что-бы знать что делать, если пришел код повторения.
IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  irrecv.enableIRIn(); // Start the receiver
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN,LOW);

}

void loop() {
  
   // Логика получения нажатий от пульта,&nbsp;тут мы фактически "регистрируем факт нажатия"
   if(irrecv.decode(&results)){ // на пульте что-то нажали
    int keyCode=results.value; // дальше будем проверять значение этой переменной, а не  results.value
       if(keyCode==REPEAT) keyCode=lastPressedKey; // пришел код ПОВТОРЕНИЕ, значит нужно сделать вид что еще раз нажали предыдущую клавишу.
       if(keyCode == 0x40BF00FF){ // тут подставляем код кнопки которая должна включать светодиод

          ledCounter=5000; // подбираем это число. оно указывает сколько раз прокрутиться loop, прежде чем выключится диод (если в это время не будет новых нажатий).
       }
      if(keyCode!=REPEAT){ // сам код повторения запоминанть не нужно, предотвращаем затирание кода реальной клавиши
        lastPressedKey=keyCode; // запомнили
      }
       irrecv.resume(); // получить следующие значение
   } 
   
   // а теперь обрабатываем "зарегистрированные факты"
   if(ledCounter>0){ // тут что-то не нулевое, значит нужно включить или продолжать светить
       digitalWrite(LED_PIN,HIGH);
       ledCounter--; // уменьшаем счетчик, один проход выполнен
       
   } else { // счетчик дошел до нуля, значит "пора гасить"
       digitalWrite(LED_PIN,LOW);
   }

}    

 

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

 вообще первый скетч работает, нажимаем кнопку светодиод вспыхивает и тухнит,

Ключевой вопрос "как тухнет", есть видимая задержка? Или "сразу как отпустили"?

Elektro пишет:

второй, может быть я не правельно их совместил, не работает вот проверте меня

На глаз вроде все верно. А в чем именно проявляется "не работает"?

Попробуйте вставить "Serial.print("results:");Serial.println(results->value, HEX);" перед ""int keyCode=results.value"
и

"Serial.print("keycode:");Serial.println(keyCode, HEX);" перед "if(keyCode == 0x40BF00FF)"

И киньте сюда что видно при этом в сериал мониторе (ну и в setup не забудте инициализацию serial порта добавить)

Elektro
Offline
Зарегистрирован: 10.02.2012

<< Ключевой вопрос "как тухнет", есть видимая задержка? Или "сразу как отпустили"?>>

нажали кнопку он загорелся на некоторое время , может быть на 1 сек., и тухнет, кнопку при этом не отпускали. теперь отпускаем - нажимаем и сново вспыхивает и тухнит

 

сейчас попробую

leshak
Offline
Зарегистрирован: 29.09.2011

Посмотрев свежим взглядом, вижу что можно чуток упростить код (но, по идее это ни на что не должно влиять).

Строчку

if(keyCode==REPEAT) keyCode=lastPressedKey;

заменить на 

    if(keyCode==REPEAT) keyCode=lastPressedKey; // пришел код ПОВТОРЕНИЕ, значит нужно сделать вид что еще раз нажали предыдущую клавишу.
       else  lastPressedKey=keyCode; // запоминаем код реальной клавиши, для последнующего повторения

А  строчки 

    // запоминаем код нажатой клавиши, пригодится если прийдет код повторения
       if(keyCode!=REPEAT){ // сам код повторения запоминанть не нужно, предотвращаем затирание кода реальной клавиши
          lastPressedKey=keyCode;
       }

 выкинуть. На одну проверку меньше будет.

Update: строчки "что выкинуть" неправильно дал. Теперь правильно.

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

<< Ключевой вопрос "как тухнет", есть видимая задержка? Или "сразу как отпустили"?>>

нажали кнопку он загорелся на некоторое время , может быть на 1 сек., и тухнет, кнопку при этом не отпускали. теперь отпускаем - нажимаем и сново вспыхивает и тухнит

Ну по описанию "то что доктор прописал" :) А вто втором скетче есть это "на 1 сек и тухнет"? Или вообще не зажигается?

Значит трабла где-то в обработке повторений. Может быть все таки код повторения не равен REPEAT (возможно если пульт работает не по NEC протоколу). А пульт вы взяли именно тот который "код повторения" дает, не тот который "чередует коды"? Если в serial выведете коды, то по идее, мы должны увидеть ответы на эти вопросы :)

Elektro
Offline
Зарегистрирован: 10.02.2012

 вообщем на Serial.println(results->value, HEX); прога ругаться начала я сделал так Serial.println(results.value, HEX); сработало, есть разница?

вот результат: нажали на первую клавишу и подержали ее 

results:40BF00FF
keycode:FF
results:FFFFFFFF
keycode:FF
results:FFFFFFFF
keycode:FF
results:FFFFFFFF
keycode:FF

на другую нажал и тоже подержал:

results:40BF807F
keycode:FFFF807F
results:FFFFFFFF
keycode:FFFF807F
results:FFFFFFFF
keycode:FFFF807F
 

что дальше делать? 

 

Elektro
Offline
Зарегистрирован: 10.02.2012

 Ну по описанию "то что доктор прописал" :) А вто втором скетче есть это "на 1 сек и тухнет"? Или вообще не зажигается?

 

нет. во втором скетче ни чего не происходит.

leshak
Offline
Зарегистрирован: 29.09.2011

Сделайте переменным lastPressedKey и keyCode тип "unsigned long" вместо int.  Похоже я не угадал c int и в него код клавиши не помещается. Годы C# подвели. Там бы такую ошибку компилятор просто не пропустил, сразу бы послал подальше :)

То есть должно быть 

...
unsigned long lastPressedKey=0;
...
unsigned long keyCode=results.value; // даль...
....

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 ну и опять "что в serial воводится" покажите, после этой замены.

Elektro
Offline
Зарегистрирован: 10.02.2012

 теперь светодио загорается и начинает быстро моргать, сть какойнибудь способ чтоб убрать эти моргания или сделать их незаметными? просто мне нужно управлять двигателями и двигатель дергается при таком раскладе...вообщем ничего хорошего)

 

вот что Serial выдает

нажал и подржал кнопку:

results:40BF00FF
keycode:40BF00FF
results:FFFFFFFF
keycode:40BF00FF
results:FFFFFFFF
keycode:40BF00FF
results:FFFFFFFF
keycode:40BF00FF
results:FFFFFFFF
keycode:40BF00FF
 

 

и вторую кнопку:

results:40BF807F
keycode:40BF807F
results:FFFFFFFF
keycode:40BF807F
results:FFFFFFFF
keycode:40BF807F
 

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

вот что Serial выдает

Ну похоже, теперь в логике потоврений все нормально. Можно закомментить эти serial (но пока не выкидывайте может еще пригодятся)

Elektro пишет:

 теперь светодио загорается и начинает быстро моргать, сть какойнибудь способ чтоб убрать эти моргания или сделать их незаметными?

Конечно. Для этого нужно понять "почему они есть". Думаю потому, что он успевает потухнуть раньше чем успевает прийти-обработаться код повторения. Боротся с этим можно несколькими способами:

  1. Как я писал выше закоментить serial.print - они тоже дают задержки/помехи.
  2. Попробовать увеличить ту самую магическую  ledCounter=5000; что-бы диод горел подольше в отсутсвии нажатий клавиш.

Но в любом случае, механизм через ledCounter=5000; это временное решение. Только что-бы "проверить подход". Он слишком зависит от того за какое время выполняются другие части кода. Его все время нужно будет "подкручивать". Поэтому нужно будет перейти на использование внутренних часов (счас накидаю как это делается).

 

Elektro
Offline
Зарегистрирован: 10.02.2012

 ммм я вроде убрал "моргание" ledCounter=7500; вроде бы не видно как мигает светодиод.

куда теперь вписывать дополнительные фукции для того чтоб работать с другими кнопками? 

leshak
Offline
Зарегистрирован: 29.09.2011

 "лобовой вариант" это завести еще несколько ledCounter2,ledCounter3, ledCounter4 и т.п.

для каждой нопки увеличивать свой счетчик, и для каждого повторить весь if после комментария ""// а теперь обрабатываем "зарегистрированные факты""

ну и каждый будет включать свой диод.

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

Чуток подождите, покажу как это сделать более аккуратно с помощью  массивов.

leshak
Offline
Зарегистрирован: 29.09.2011

 Вообщем поехали :)

Раз у нас "моторы", то дальше я термин LED использовать не буду. Буду просто назвыать PIN, включить PIN и т.п. Пины я условно обозвал ВПЕРЕД, НАЗАД, ВЛЕВО, ВПРАВО

Буду по кусочкам давать, пока не дойду до конца, скетч компилироваться не будет.

вместо 

int LED_PIN = 9;

 

вставляем

#define PINS_TOTAL 4 // задаем сколько у нас вообще есть управляющих пинов. Нужно менять каждый это число каждый раз как добавляем/убираем новый пин. Всегда должно совпадать с длинной массива пинов

int PINS[]={9,10,11,12}; // задаем номера пинов
int COUNTERS[]={0,0,0,0,0}; //массив счетчиков, должен быть той же длины что и массив пинов

//определяем константы, что-бы не нужно было помнить какой пн под каким индексом лежит в массиве. Значение константы это индекс в массиве PINS
#define FORWARD_PIN 0 // 9-тый пин
#define BACK_PIN 1 // 10-тый пин
#define LEFT_PIN 2  // 11-тый пин
#define RIGHT_PIN 3  // 12-тый пин

//определяем константы для кодов клавиш что-бы код легче читался
#define FORWARD_KEY 0x40BF00FF
#define BACK_KEY 0x40BF807F
#define LEFT_KEY 0x01 // подставте нужный код клавиши
#define RIGHT_KEY 0x02 // подставте нужный код 

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Перед setup()

задаем две новые функции. Первая будет включать пин и взводить счетчик, вторая выключать пин и уменьшать счетчик

// функция включает pin с индексом pinIndex и инициализирует счетчик с таким же индексом
void turnONPin(int pinIndex){
   digitalWrite(PINS[pinIndex],HIGH); // включаем пин
   COUNTERS[pinIndex]=7500;// теперь цифра "магической задержки" будет тут
}

// функция выключает пин с индексом pinIndex если соотвествующий ему счетчик достиг нуля, или уменьшает счетчик в противном случае
void turnOFFPinIfRequired(int pinIndex){
  if(COUNTERS[pinIndex]>0){
     // влючать пин уже не требуется, мы его включили в turnONPin
     COUNTERS[pinIndex]--;// уменьшаем счетчик
  } else { // счетчик нулевой - пора выключать
    digitalWrite(PINS[pinIndex],LOW);
  }
  
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Теперь внутри setup выствляем для наших пинов режим.

Вместо 

pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN,LOW);

Пришем 

// всем пины в массиве PINS устанавдиваем в OUTPUT и LOW
  for( int i=0;i<PINS_TOTAL;i){ 
    pinMode(PINS[i], OUTPUT);
    digitalWrite(PINS[i],LOW);
  }

 

leshak
Offline
Зарегистрирован: 29.09.2011

Дальше переходим логике "какая клавиша нажата". Переходим от if к кошерному, в данном случае, switch и не напрямую включаем наши пины, а через функцию turnONPin

вместо 

  if(keyCode == 0xEC74525E){ // тут подставляем код кнопки которая должна включать светодиод
          ledCounter=7500; // подбираем это число. оно указывает сколько раз прокрутиться loop, прежде чем выключится диод (если в это время не будет новых нажатий).
       }

пишем

  //  задаем соотвествие что делать на нажития кнопок пульта, тут нам и пригодятся объявленные константы
       switch(keyCode){
           case FORWARD_KEY: 
                       turnONPin(FORWARD_PIN);

                       break;
           case BACK_KEY: 
                       turnONPin(BACK_PIN);
                       break;                       
           case LEFT_KEY: 
                       turnONPin(LEFT_PIN);
                       break;                             
           case RIGHT_KEY: 
                      turnONPin(RIGHT_PIN);
                       break;                             
            default:
                   // неизвестный код пульта - ничего не делаем
                   break;

       }

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Ну и осталось, уменьшать счетчики и выключать, когда пришло "время" пины.

Вместо 

  if(ledCounter>0){ // тут что-то не нулевое, значит нужно включить или продолжать светить
       digitalWrite(LED_PIN,HIGH);
       ledCounter--; // уменьшаем счетчик, один проход выполнен
       
   } else { // счетчик дошел до нуля, значит "пора гасить"
       digitalWrite(LED_PIN,LOW);
   }

пишем

 for(int i=0;i<PINS_TOTAL;i++)turnOFFPinIfRequired(i);// пробегаемся во всем счетчикам и или уменьшаем их или выключаем пин    

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Все. Теперь мы, по идее, сделали так, что на при нажатии каждой клавиши у нас включается соответсвующий пин (все-го их четыре).

Пробуйте.

Elektro
Offline
Зарегистрирован: 10.02.2012

ругается на void turnONPin(int) 

и вот что выдает

IRrecvDemo.cpp: In function 'void loop()':
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
IRrecvDemo.pde:-1: error: too few arguments to function 'void turnONPin(int)'
IRrecvDemo.pde:-1: error: at this point in file
 

 

leshak
Offline
Зарегистрирован: 29.09.2011

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

Предлагаю еще уйти от магических 7500. Сделать скетч более устойчивым к временным измененим.

Для этого вместо счетчиков будем использовать фунцию arduino.ru/Reference/Millis

Итак вместо массива счетчиков

int COUNTERS[]={0,0,0,0,0}; //массив счетчиков, должен быть той же длины что и массив пиновint

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

unsigned long OFF_TIMES[] ={0,0,0,0,0}; //массив времен, должен быть той же длины что и массив пиновint

#define OFF_DELAY 500;// время в миллесекундах, сколько должен "гореть " пин после нажатия клавиши

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

Теперь в функции turnONPin вместо 

 COUNTERS[pinIndex]=7500;// теперь цифра "магической задержки" будет тут

пишем

   OFF_TIMES[pinIndex]=millis()+OFF_DELAY; // вычисляем время когда пин нужно будет "погасить"

Ну и напоследок, выкидываем все из функции turnOffPinIfRequired, теперь она будет проще (не нужно счетчик уменьшать, время само тикает), и вставляем

if(millis()>OFF_TIMES[pinIndex]){ // если текущие время уже больше расчетного времени выключения
     digitalWrite(PINS[pinIndex],LOW);// выключаем
  }

 Вот теперь вроде "все хорошо". Теперь если где-то в loop будет "времяемкие задержки", они не будут "автоматически" умножатся на "магическое число". В крайнем случае, если эта задержка будет больше OFF_DELAY, то пин будет гаснуть чуть позже чем "ему положено" (потому-то и нежелательно в реальных скетчах использовать delay, лучше везде вычислять время, потом сверятся с ним и делать действие только если время пришло.

leshak
Offline
Зарегистрирован: 29.09.2011

Elektro пишет:

ругается на void turnONPin(int) 

Показыавйте скетч целиком, который у вас получился. Может где-то лишнюю ; воткнули или } потеряли.

Elektro
Offline
Зарегистрирован: 10.02.2012

я заменил название пинов , т.к до этого работал так и мне немного удобнее, думаю это ведь не важно..

вот что получилось, я проверил все но не нашел лишних или не доставленых "}"

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

#define PINS_TOTAL 4 // задаем сколько у нас вообще есть управляющих пинов. Нужно менять каждый это число каждый раз как добавляем/убираем новый пин. Всегда должно совпадать с длинной массива пинов

int PINS[]={7,8,6,5}; // задаем номера пинов
unsigned long OFF_TIMES[] ={0,0,0,0,0}; //массив времен, должен быть той же длины что и массив пиновint

#define OFF_DELAY 500;// время в миллесекундах, сколько должен "гореть " пин после нажатия клавиши

//определяем константы, что-бы не нужно было помнить какой пн под каким индексом лежит в массиве. Значение константы это индекс в массиве PINS
#define HBRIDGE_1A_PIN // 7-тый пин
#define HBRIDGE_2A_PIN // 8-тый пин
#define HBRIDGE_3A_PIN  // 6-тый пин
#define HBRIDGE_4A_PIN  // 5-тый пин

//определяем константы для кодов клавиш что-бы код легче читался
#define FORWARD_KEY 0x40BF807F
#define BACK_KEY 0x40BF906F
#define LEFT_KEY 0x40BF20DF // подставте нужный код клавиши
#define RIGHT_KEY 0x40BF609F // подставте нужный код 
int RECV_PIN = 11;
int ledCounter=0;
unsigned long lastPressedKey=0;; //  тут будем запоминать последнюю нажатую клавишу, что-бы знать что делать, если пришел код повторения.
IRrecv irrecv(RECV_PIN);

decode_results results;
// функция включает pin с индексом pinIndex и инициализирует счетчик с таким же индексом
void turnONPin(int pinIndex){
   digitalWrite(PINS[pinIndex],HIGH); // включаем пин
   OFF_TIMES[pinIndex]=millis()+OFF_DELAY; // вычисляем время когда пин нужно будет "погасить"
}

// функция выключает пин с индексом pinIndex если соотвествующий ему счетчик достиг нуля, или уменьшает счетчик в противном случае
void turnOFFPinIfRequired(int pinIndex){
  if(millis()>OFF_TIMES[pinIndex]){ // если текущие время уже больше расчетного времени выключения
     digitalWrite(PINS[pinIndex],LOW);// выключаем
  }
  }
  
}
void setup()
{
  irrecv.enableIRIn(); // Start the receiver
  // всем пины в массиве PINS устанавдиваем в OUTPUT и LOW
  for( int i=0;i<PINS_TOTAL;i){ 
    pinMode(PINS[i], OUTPUT);
    digitalWrite(PINS[i],LOW);
  }
Serial.begin(9600);
}

void loop() {
  
   // Логика получения нажатий от пульта,&nbsp;тут мы фактически "регистрируем факт нажатия"
   if(irrecv.decode(&results)){ // на пульте что-то нажали
    Serial.print("results:");
    Serial.println(results.value, HEX);
    unsigned long keyCode=results.value;  // дальше будем проверять значение этой переменной, а не  results.value
       if(keyCode==REPEAT) keyCode=lastPressedKey; // пришел код ПОВТОРЕНИЕ, значит нужно сделать вид что еще раз нажали предыдущую клавишу.
       Serial.print("keycode:");
       Serial.println(keyCode, HEX);
       //  задаем соотвествие что делать на нажития кнопок пульта, тут нам и пригодятся объявленные константы
     switch (keyCode){
         case FORWARD_KEY: 
                     turnONPin(HBRIDGE_4A_PIN);
                     turnONPin(HBRIDGE_1A_PIN);
                     break;
         case BACK_KEY: 
                     turnONPin(HBRIDGE_3A_PIN);
                     turnONPin(HBRIDGE_2A_PIN);
                     break;                       
         case LEFT_KEY: 
                     turnONPin(HBRIDGE_2A_PIN);
                     turnONPin(HBRIDGE_4A_PIN);
                     break;                             
         case RIGHT_KEY: 
                    turnONPin(HBRIDGE_3A_PIN);
                    turnONPin(HBRIDGE_1A_PIN);
                     break;                             
          default:
                 // неизвестный код пульта - ничего не делаем
                 break;

     }
      if(keyCode!=REPEAT){ // сам код повторения запоминанть не нужно, предотвращаем затирание кода реальной клавиши
        lastPressedKey=keyCode; // запомнили
      }
       irrecv.resume(); // получить следующие значение
   } 
   
   // а теперь обрабатываем "зарегистрированные факты"
   for(int i=0;i<PINS_TOTAL;i++)turnOFFPinIfRequired(i);// пробегаемся во всем счетчикам и или уменьшаем их или выключаем пин    

}