PCCar.ru - Ваш автомобильный компьютер

PCCar.ru - Ваш автомобильный компьютер (http://pccar.ru/index.php)
-   Резистивные кнопки (http://pccar.ru/forumdisplay.php?f=165)
-   -   Адаптер рулевых кнопок. Безжалостный и беспощадный. (http://pccar.ru/showthread.php?t=24126)

ali_vlad 21.04.2016 00:31

Адаптер рулевых кнопок. Безжалостный и беспощадный.
 
Вложений: 5
Выкладываю свою версию адаптера рулевых кнопок.
На данный момент устройство работает - спасибо Дмитрию (Demon083)!
Я не претендую на гениальность.
Развивать данный адаптер дальше не буду, так как это временная мера.
Адаптер изготавливался под определенный руль и определенную магнитолу, но это не исключает возможность переделки и использования для других комплектов руль-магнитола.

Итак, поехали!
После установки руля с медиа-кнопками возник естественный вопрос: «А как его «подружить» с магнитолой?» Конечно, существует великое множество всевозможных адаптеров на любой вкус и кошелёк, но это не для нас.
Поскольку моя магнитола (Kwnwood KDC-6051U) понимает только протокол NEC, была использована имеющаяся Arduino Nano, немножко резисторов, стабилизатор 7812, пара кондеров и кусок монтажной платы. Всё это хозяйство было собрано на монтажке.
Вложение 43556

Вложение 43557

Вложение 43558

Вложение 43559
Для снятия кодов был использован самый обычный ИК-фотодиод, купленный с известного всем сайта, и родной пульт от магнитолы.
В скетче использовал специально заточенную под это дело библиотеку IRremote.h. На сколько я понял описание этой библиотеки, выход только D3. Его можно даже не прописывать, всё и так работает.

Достоинства:
Дёшево, быстро.

Недостатки:
Подходит только для магнитол с импульсным управлением. Настроить можно только на месте и только с ноутбуком, Нужна модифицированная библиотека: Вложение 43584.

Рабочий скетч:
PHP код:

#include <IRremote.h>
IRsend irsend;
const 
int read1 A0;//левый блок кнопок
const int read2 A1;//правый блок кнопок
float val1=0;
float val2=0;         
float lastval1=0;
float lastval2=0;
int pause1=180;//Задержка после нажатия кнопок
int pause2=200;//Задержка после нажатия кнопrи SRC
// Коды сняты с пульта
//[Влево]       9D6250AF
//[Вправо]      9D62D02F 
//[Громкость +]    9D6228D7 
//[Громкость –]    9D62A857
//[ + ]        9D62B04F
//[ – ]        9D6230CF
//[SRC]        9D62C837

//Расположение кнопок на блоках и значения
//Громкость +  правый 843
//Громкость -  правый 894
//Следующий    правый 305
//Предыдущий   правый 540
//Источник     правый 696
//Громковсть + левый  540
//Громкость -  левый  843
//+            левый  305
//-            левый  696

void setup()
{
  
pinMode (read1INPUT);
  
pinMode (read2INPUT);
  
Serial.begin(9600);              
}
void loop()
{
  
val1 analogRead(read1);
  
val2 analogRead(read2);
  
///////////////////    Обработка правого блока кнопок     ////////////////////// 
  
if (val1>10 && val1<1000)//фильтр от помех
  
{
    if (
val1 != lastval1)//если значение изменилось
      //      Serial.print("Right ");
      //   Serial.println(val1);
    
{
      
delay (pause1);//задержку подбирал на свой вкус
      
if (val1>794&&val1<860)//Громкость +
      
{
        
Serial.println(" R. Vol +");//Контроль
        
irsend.sendNEC(0x9D6228D732);
        
lastval1=val1;
      }
      if (
val1>877&&val1<910)//Громкость -
      
{
        
Serial.println(" R. Vol -");//Контроль
        
irsend.sendNEC(0x9D62A85732);
        
lastval1=val1;
      }
      if (
val1>644&&val1<745)//Выбор источника
      
{
        
Serial.println(" R. SRC");//Контроль
        
irsend.sendNEC(0x9D62C83732);
        
lastval1=val1;
        
delay (pause2);//дополительная задержка
      
}
      if (
val1>225&&val1<383)//Вправо
      
{
        
Serial.println(" R. >>");//Контроль
        
irsend.sendNEC(0x9D62D02F32);
        
lastval1=val1;
      }
      if (
val1>462&&val1<592)//Влево
      
{
        
Serial.println(" R. <<");//Контроль
        
irsend.sendNEC(0x9D6250AF32);
        
lastval1=val1;
      }
    }
  }
  
///////////////////    Обработка левого блока кнопок     ////////////////////// 
  
if (val2>10 && val2<1000)//фильтр от помех
  
{
    if (
val2 != lastval2)//если значение изменилось
    
{
      
//      Serial.print("Left ");
      //     Serial.println(val2);
      
delay (pause1);//задержку подбирал на свой вкус
      
if (val2>462&&val2<644)//Громкость +
      
{
        
Serial.println(" L. Vol +");//Контроль
        
irsend.sendNEC(0x9D6228D732);
        
lastval2=val2;
      }
      if (
val2>794&&val2<910)//Громкость -
      
{
        
Serial.println(" L. Vol -");//Контроль
        
irsend.sendNEC(0x9D62A85732);
        
lastval2=val2;
      }
    }
    if (
val2>225&&val2<383)//Вверх
    
{
      
Serial.println(" L. +");//Контроль
      
irsend.sendNEC(0x9D62B04F32);
      
lastval2=val2;
    }
    if (
val2>644&&val2<745)//Вниз
    
{
      
Serial.println(" L. -");//Контроль
      
irsend.sendNEC(0x9D6230CF32);
      
lastval2=val2;
    }
  }


Скетч для снятия данных с кнопок на руле:
PHP код:

const int analogPin1 A0;// Для левого
const int analogPin2 A1;// Для правого
float val1 0;
float val2 0;

void setup()
{
  
pinMode (analogPin1INPUT);
  
Serial.begin(9600);
}

void loop()
{
  
val1 analogRead(analogPin1);     
  
val2 analogRead(analogPin2);     
  
delay (200);
  if (
val1<=1000
  {
    
Serial.print("Lefr "); 
    
Serial.println(val1);
  }
  if (
val2<=1000
  {
    
Serial.print("Right ");
    
Serial.println(val2);
  } 


Скетч для снятия кодов с пульта (взят из папки examples, которая была вместе с библиотекой):
PHP код:

#include <IRremote.h>

int RECV_PIN 10;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  
Serial.begin(9600);
  
irrecv.enableIRIn(); // Start the receiver
}

// 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;
  if (
results->decode_type == UNKNOWN) {
    
Serial.print("Unknown encoding: ");
  } 
  else if (
results->decode_type == NEC) {
    
Serial.print("Decoded NEC: ");
  } 
  else if (
results->decode_type == SONY) {
    
Serial.print("Decoded SONY: ");
  } 
  else if (
results->decode_type == RC5) {
    
Serial.print("Decoded RC5: ");
  } 
  else if (
results->decode_type == RC6) {
    
Serial.print("Decoded RC6: ");
  }
  else if (
results->decode_type == PANASONIC) {    
    
Serial.print("Decoded PANASONIC - Address: ");
    
Serial.print(results->panasonicAddress,HEX);
    
Serial.print(" Value: ");
  }
  else if (
results->decode_type == JVC) {
     
Serial.print("Decoded JVC: ");
  }
  
Serial.print(results->valueHEX);
  
Serial.print(" (");
  
Serial.print(results->bitsDEC);
  
Serial.println(" bits)");
  
Serial.print("Raw (");
  
Serial.print(countDEC);
  
Serial.print("): ");

  for (
int i 0counti++) {
    if ((
2) == 1) {
      
Serial.print(results->rawbuf[i]*USECPERTICKDEC);
    } 
    else {
      
Serial.print(-(int)results->rawbuf[i]*USECPERTICKDEC);
    }
    
Serial.print(" ");
  }
  
Serial.println("");
}


void loop() {
  if (
irrecv.decode(&results)) {
    
Serial.println(results.valueHEX);
    
dump(&results);
    
irrecv.resume(); // Receive the next value
  
}


При изготовлении своего адаптера рулевых кнопок мне стало интересно, почему полученные с пульта у библиотеки IRemote.h (протокол NEC) данные отличаются? Стал копать данную тему и вот что я накопал. Для примера рассмотрим адрес/команду кнопки [Vol+] стандартного пульта автомагнитолы Kenwood. В Ардуине это выглядит так: 9D6228D7, а вот в официальном описании так: адрес:46B9 команда:14. (HEX)
Нужна была программа, которая умеет конвертировать между собой, шестнадцатеричные, десятичные и двоичные числа и первая, которая пришла мне на ум была калькулятор из винды в расширенном виде и обратил внимание на двоичный код и пришло прозрение!
Возьмем наш код из ардуины 9D6228D7, где 9D62-является адресов, а 28D7-командой.
Теперь представим 9D62 в двоичном виде и получим 1101100101100010. А теперь самое интересное. Надо прочитать с конца данный двоичный код 0100011010011011 и преобразовать обратно в HEX. Получаем 469B. Это уже знакомые нам цифры, не так ли?
Теперь команда. С ней немножко сложнее. Её надо разбить на 2 части 28 и D7. Получаем
28 00101000
D7 11010111

Как видим, одно значение инверсно другому. Читаем 28 наоборот и получаем 14.

Теперь обратное преобразование
Возьмем адрес:46B9 и команду:15 [Vol-] и переведем это на язык ардуины.
46B9 -> 0100 0110 1011 1001 ->1001 1101 0110 0010 -> 9D62
15-> 0001 0101 -> 1010 1000 -> A8 (читаем наоборот)

1010 1000
0101 0111 -> 57 (инвертируем)
Складываем всё в кучу и получаем 9D62A857.
Надеюсь кому-нибудь пригодится.

Trantor 22.04.2016 18:34

Я бы границы уставок увеличил по максимуму, до "упора" в соседние, работать надежнее будет, если резисторы/контакты/напряжения поплывут.
Вот так:
if (val1>840&&val1<870)//Громкость +
if (val1>871&&val1<999)//Громкость -

ali_vlad 25.04.2016 14:23

Народ, помогайте! Адаптер работает только на половину. Если на выход цепляю ИК-диод - работает. Подключаю к магнитоле - реакции 0.

Demon083 25.04.2016 15:21

Цитата:

Сообщение от ali_vlad (Сообщение 359172)
Народ, помогайте! Адаптер работает только на половину. Если на выход цепляю ИК-диод - работает. Подключаю к магнитоле - реакции 0.

Данное описание актуально для магнитол, у которых проводной вход для подключения подрулевых кнопок имеет протокол NEC (на некоторых магнитолах встречается вход, чувствительный к сопротивлению).
На ИК-диод подается модулированный сигнал частотой 38кГц (описание протокола NEC http://radiohlam.ru/teory/nec.htm ), с ИК приемника подается без несущей частоты.
На вход магнитолы необходимо подавать сигнал без несущей частоты. Для этого правил библиотеку IRremote.cpp (в место включения и выключения ШИМ выдавал в порт логические 1, 0), в функции sendNEC в место enableIROut(38); записал pinMode(3, OUTPUT);, в функциях marc, space: в место TCCR2A… записал digitalWrite(3, HIGH) (для mark), digitalWrite(3, LOW) (для space). Вход у магнитолы может быть инверсный, тогда digitalWrite(3, LOW) (mark), digitalWrite(3, HIGH) (space).
После такого вмешательства в библиотеку работа с ИК-диодом не возможна.

ali_vlad 25.04.2016 16:03

Цитата:

Сообщение от Demon083 (Сообщение 359176)
Данное описание актуально для магнитол, у которых проводной вход для подключения подрулевых кнопок имеет протокол NEC (на некоторых магнитолах встречается вход, чувствительный к сопротивлению).
На ИК-диод подается модулированный сигнал частотой 38кГц (описание протокола NEC http://radiohlam.ru/teory/nec.htm ), с ИК приемника подается без несущей частоты.
На вход магнитолы необходимо подавать сигнал без несущей частоты. Для этого правил библиотеку IRremote.cpp (в место включения и выключения ШИМ выдавал в порт логические 1, 0), в функции sendNEC в место enableIROut(38); записал pinMode(3, OUTPUT);, в функциях marc, space: в место TCCR2A… записал digitalWrite(3, HIGH) (для mark), digitalWrite(3, LOW) (для space). Вход у магнитолы может быть инверсный, тогда digitalWrite(3, LOW) (mark), digitalWrite(3, HIGH) (space).
После такого вмешательства в библиотеку работа с ИК-диодом не возможна.

PHP код:

void IRsend::sendNEC(unsigned long dataint nbits)
{
  
pinMode(3OUTPUT);
  
digitalWrite(3HIGH);
  
digitalWrite(3LOW);
  for (
int i 0nbitsi++) {
    if (
data TOPBIT) {
      
digitalWrite(3HIGH);
      
digitalWrite(3LOW);
    } 
    else {
      
digitalWrite(3HIGH);
      
digitalWrite(3LOW);
    }
    
data <<= 1;
  }
  
digitalWrite(3HIGH);
  
space(0); 

Если так, то всё равно не работает.

Demon083 26.04.2016 11:14

Цитата:

Сообщение от ali_vlad (Сообщение 359179)
PHP код:

void IRsend::sendNEC(unsigned long dataint nbits)
{
  
pinMode(3OUTPUT);
  
digitalWrite(3HIGH);
  
digitalWrite(3LOW);
  for (
int i 0nbitsi++) {
    if (
data TOPBIT) {
      
digitalWrite(3HIGH);
      
digitalWrite(3LOW);
    } 
    else {
      
digitalWrite(3HIGH);
      
digitalWrite(3LOW);
    }
    
data <<= 1;
  }
  
digitalWrite(3HIGH);
  
space(0); 

Если так, то всё равно не работает.

Не совсем так.
В функциях MARK и SPACE кроме включения и выключения ШИМ дополнительно формируются задержки, длительность которых задается при вызове функции (NET_BIT_MARK, NET_ONE_MARK, NEC_ZERO_SPACE), поэтому digitalWrite предлагаю вставлять в место строчек TCCR2A|=_BV(COM21); в функции marc, TCCR2A&=~(_BV(COM21)); в функции space. инициализацию порта (pinMode) оставить в sendNEC

Trantor 26.04.2016 14:58

В этом не может быть дело? Сигнал возможно нужно инвертировать.
Цитата:

При приёме сигнала от пульта необходимо учитывать, что фотоприёмники зачастую имеют выходы подтянутые к питанию и при отсутствии сигнала на входе (когда пульт ничего не передаёт) у них на выходе висит высокий уровень, а при наличии импульсов на частоте несущей (когда пульт передаёт высокий уровень) у них на выходе устанавливается низкий уровень. В этом случае принятый сигнал получается инвертированным.

ali_vlad 26.04.2016 15:53

Всё заработало, шапку обновил

Nazka85 12.02.2017 17:38

Цитата:

Сообщение от ali_vlad (Сообщение 359227)
Всё заработало, шапку обновил

Привет. Дак у тебя проводное управление или через ИК фотодиод?

Shurickk 13.02.2017 00:27

Цитата:

Сообщение от ali_vlad (Сообщение 359227)
Всё заработало, шапку обновил

Огромное, человеческое спасибо ) Заработало почти сразу ) единственное, выход на магнитофон сделал напрямую с ардуины. сначала пытался сделать как по схемам встречал до этого, через полевой транзистор, но так не работало, подключил напрямую и ура )


Часовой пояс GMT +4, время: 10:43.

Работает на vBulletin® версия 3.8.4.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot