простой IR декодер для автомобильной магнитолы в KEY1

vanderverken
Offline
Зарегистрирован: 13.01.2020

Задача - прикорячить ИК пультик с али что бы управлял магнитолой одним проводом KEY1, т.е. при нажатии кнопки пин  ардуины падает на землю и таким образом на подключенных к этим пинам резюки формируют итоговое сопротивление для магнитолы. Резисторы такие: 330 Ом, 560 Ом, 910 Ом, 1.5 кОм, 2.0 кОм, 2.4 кОм, 3.0 кОм, 3.6 кОм, 3.9 кОм, 4.7 кОм, 5.2 кОм. Как то особо номиналами резюков не заморачивался, просто взял то что было из стандартного набора. 

С одиночными нажатиями все нормально, но никак не получается добавить обработку удержания кнопки... При одиночном нажатии кнопки все работает, а вот при удержании кнопки пультик сначала передает первым код нажатой кнопки и потом до отпускания гонит байт 0xFF. Напрашивается решение флаги присваивать на первый принятый байт кнопки? И проверять при активном флаге наличие следующего принятого байта ==0xFF? 

Набросал вот такой простенький скетчик, он работает, но только на одиночные нажатия... Комменты пишу для себя, что бы по прошествии времени не забыть кто есть ху... Задержка в loop () нужна не менее 55 мсек, иначе майфун не успевает задетектить кнопку. В этом примере delay(100) что бы однозначно узнавал нажатие... Используется библиотека ИК отсюда https://github.com/NicoHood/IRLremote
 
#include "IRLremote.h"
CNec IRLremote;

void setup()
{
  IRLremote.begin(2); //включаем ИК приемник
  for (int i = 3; i <= 13; i++) //здесь назначаем пины как OUTPUT и переводим в HIGH, т.к. активный уровень LOW
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }
}

void loop()
{
  if (IRLremote.available()) //если что то принято по ИК
  {
    auto data = IRLremote.read(); //прочитали принятый байт и ниже сравниваем с кодом кнопки
    if (data.command == 0x41) digitalWrite(3, LOW); //MUTE
    if (data.command == 0x4F) digitalWrite(4, LOW); //VolumeUP
    if (data.command == 0x51) digitalWrite(5, LOW); //GreenPhone
    if (data.command == 0x53) digitalWrite(6, LOW); //Menu
    if (data.command == 0x54) digitalWrite(7, LOW); //Mod
    if (data.command == 0x55) digitalWrite(8, LOW); //VolumeDN
    if (data.command == 0x56) digitalWrite(9, LOW); //Left
    if (data.command == 0x57) digitalWrite(10, LOW); //SEL
    if (data.command == 0x59) digitalWrite(11, LOW); //Right
    if (data.command == 0x5B) digitalWrite(12, LOW); //END
    if (data.command == 0x5F) digitalWrite(13, LOW),; //RedPhone
  }
  else //если ничего по ИК не приходило все пины ставим HIGH
  {
    for (int i = 3; i <= 13; i++) digitalWrite(i, HIGH);
  }
  delay(100); //экспериментально выяснено что должно быть не менее 55 мсек
}

п.с. знаю что надо избавляться от delay() например с использованием millis(),  так же знаю что можно обойтись меньшим количеством выводов, достаточно будет всего лишь 4х выводов, просто использовать комбинации их включения, как в двоичной системе - 0001/0010 и т.п и т.д...

 

Гриша
Offline
Зарегистрирован: 27.04.2014

vanderverken пишет:

п.с. знаю что надо избавляться от delay() например с использованием millis()...

посмотрите еще такой топик... для тех, кому лень

vanderverken
Offline
Зарегистрирован: 13.01.2020

Гриша пишет:

vanderverken пишет:

п.с. знаю что надо избавляться от delay() например с использованием millis()...

посмотрите еще такой топик... для тех, кому лень

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

ВН
Offline
Зарегистрирован: 25.02.2016

между 18 и 19 строками добавьте

if (data.command == 0xFF) {delay(100); return;} через время задержки управление вернется в начало лупа, на 16 строку

и будет так циклиться, пока не придет какой-то иной код. http://arduino.ru/Reference/Return

смысла здесь менять делей на милис особого нет, т.к. ничему тут этот делей не мешает

vanderverken
Offline
Зарегистрирован: 13.01.2020

если кому то интересно, вот эта схема в SprintLayout 6 у меня сейчас работает в машине.

Резистор на 22к нужен для постоянной подтяжки входа KEY1 магнитолы на землю во избежании ложных срабатываний. Сопротивление подбиралось опытным путем. Все мы помним про параллельное включение резисторов, по этому подбором этого резюка выяснялся нижний предел сопротивлений когда уверенно срабатывали кнопки. 

Гриша
Offline
Зарегистрирован: 27.04.2014

vanderverken пишет:

 но дело то не в этом, не в задержках, а в обработке разных кодов одной и той же кнопки.

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

rkit
Offline
Зарегистрирован: 23.11.2016

После обработки первого сигнала и установки пина нужно просто запустить блокирующий цикл

1. задержка на интервал между сигналами

2. если не пришло 0xFF, то снимаем пин и выходим.

vanderverken
Offline
Зарегистрирован: 13.01.2020

Спасибо всем откликнувшимся! К сожалению Ваши советы не помогли... Танцы с бубном, и прочие шаманства выродились вот в такой скетч на костылях. Да, кривенько, не красиво, но оно работает. По всей видимости какая то особенность библиотеки ИК-приемника, но я не вижу другого объяснения, почему если задержка меньше 100 или больше 110 - удержание перестает работать как именно удержание, т.е. выходной пин не удерживается в нуле, хотя при этом на выводе соответствующем удерживаемой кнопки идут импульсы. В целом меня устраивает и такой вариант, поставленную задачу выполняет.

#include "IRLremote.h"
CNec IRLremote;

int wait = 105; //так просто удобнее баловаться с задержками
byte LastCommand = 0xEE;

void setup()
{
  IRLremote.begin(2);
  for (int i = 3; i <= 13; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }
}

void loop()
{
  if (IRLremote.available())
  {
    auto data = IRLremote.read();
    if (data.command == 0xFF) //если принят код повтора 
    {
      if (LastCommand == 0x41) digitalWrite(3, LOW); //MUTE
      if (LastCommand == 0x4F) digitalWrite(4, LOW); //VolumeUP
      if (LastCommand == 0x51) digitalWrite(5, LOW); //GreenPhone
      if (LastCommand == 0x53) digitalWrite(6, LOW); //Menu
      if (LastCommand == 0x54) digitalWrite(7, LOW); //Mod
      if (LastCommand == 0x55) digitalWrite(8, LOW); //VolumeDN
      if (LastCommand == 0x56) digitalWrite(9, LOW); //Left
      if (LastCommand == 0x57) digitalWrite(10, LOW); //SEL
      if (LastCommand == 0x59) digitalWrite(11, LOW); //Right
      if (LastCommand == 0x5B) digitalWrite(12, LOW); //END
      if (LastCommand == 0x5F) digitalWrite(13, LOW); //RedPhone
      delay(wait);
      return;
    }
    else
    {
      LastCommand = data.command; //запомнили нажатую кнопку
      if (data.command == 0x41) digitalWrite(3, LOW); //MUTE
      if (data.command == 0x4F) digitalWrite(4, LOW); //VolumeUP
      if (data.command == 0x51) digitalWrite(5, LOW); //GreenPhone
      if (data.command == 0x53) digitalWrite(6, LOW); //Menu
      if (data.command == 0x54) digitalWrite(7, LOW); //Mod
      if (data.command == 0x55) digitalWrite(8, LOW); //VolumeDN
      if (data.command == 0x56) digitalWrite(9, LOW); //Left
      if (data.command == 0x57) digitalWrite(10, LOW); //SEL
      if (data.command == 0x59) digitalWrite(11, LOW); //Right
      if (data.command == 0x5B) digitalWrite(12, LOW); //END
      if (data.command == 0x5F) digitalWrite(13, LOW); //RedPhone           
    }  
    delay(wait);   
  }
  else
  {
    for (int i = 3; i <= 13; i++) digitalWrite(i, HIGH);
  }  
}