PDA

Просмотр полной версии : Адаптер рулевых кнопок. Безжалостный и беспощадный.


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

Итак, поехали!
После установки руля с медиа-кнопками (http://www.pccar.ru/showthread.php?t=24005) возник естественный вопрос: «А как его «подружить» с магнитолой?» Конечно, существует великое множество всевозможных адаптеров на любой вкус и кошелёк, но это не для нас.
Поскольку моя магнитола (Kwnwood KDC-6051U) понимает только протокол NEC, была использована имеющаяся Arduino Nano (https://duino.ru/arduino-nano-v30-ch340-usb.html), немножко резисторов, стабилизатор 7812, пара кондеров и кусок монтажной платы. Всё это хозяйство было собрано на монтажке.
43556

43557

43558

43559
Для снятия кодов был использован самый обычный ИК-фотодиод (https://duino.ru/ik-priemnik-vs1838b.html), купленный с известного всем сайта (https://duino.ru), и родной пульт от магнитолы.
В скетче использовал специально заточенную под это дело библиотеку IRremote.h. На сколько я понял описание этой библиотеки, выход только D3. Его можно даже не прописывать, всё и так работает.

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

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

Рабочий скетч:
#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 (read1, INPUT);
pinMode (read2, INPUT);
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(0x9D6228D7, 32);
lastval1=val1;
}
if (val1>877&&val1<910)//Громкость -
{
Serial.println(" R. Vol -");//Контроль
irsend.sendNEC(0x9D62A857, 32);
lastval1=val1;
}
if (val1>644&&val1<745)//Выбор источника
{
Serial.println(" R. SRC");//Контроль
irsend.sendNEC(0x9D62C837, 32);
lastval1=val1;
delay (pause2);//дополительная задержка
}
if (val1>225&&val1<383)//Вправо
{
Serial.println(" R. >>");//Контроль
irsend.sendNEC(0x9D62D02F, 32);
lastval1=val1;
}
if (val1>462&&val1<592)//Влево
{
Serial.println(" R. <<");//Контроль
irsend.sendNEC(0x9D6250AF, 32);
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(0x9D6228D7, 32);
lastval2=val2;
}
if (val2>794&&val2<910)//Громкость -
{
Serial.println(" L. Vol -");//Контроль
irsend.sendNEC(0x9D62A857, 32);
lastval2=val2;
}
}
if (val2>225&&val2<383)//Вверх
{
Serial.println(" L. +");//Контроль
irsend.sendNEC(0x9D62B04F, 32);
lastval2=val2;
}
if (val2>644&&val2<745)//Вниз
{
Serial.println(" L. -");//Контроль
irsend.sendNEC(0x9D6230CF, 32);
lastval2=val2;
}
}
}


Скетч для снятия данных с кнопок на руле:
const int analogPin1 = A0;// Для левого
const int analogPin2 = A1;// Для правого
float val1 = 0;
float val2 = 0;

void setup()
{
pinMode (analogPin1, INPUT);
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, которая была вместе с библиотекой):
#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->value, HEX);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");

for (int i = 0; i < count; i++) {
if ((i % 2) == 1) {
Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
}
else {
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
}
Serial.print(" ");
}
Serial.println("");
}


void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
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
Народ, помогайте! Адаптер работает только на половину. Если на выход цепляю ИК-диод - работает. Подключаю к магнитоле - реакции 0.

Данное описание актуально для магнитол, у которых проводной вход для подключения подрулевых кнопок имеет протокол NEC (на некоторых магнитолах встречается вход, чувствительный к сопротивлению).
На ИК-диод подается модулированный сигнал частотой 38кГц (описание протокола NEC http://radiohlam.ru/teory/nec.htm ), с ИК приемника (https://duino.ru/mod-vs1838b.html) подается без несущей частоты.
На вход магнитолы необходимо подавать сигнал без несущей частоты. Для этого правил библиотеку 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
Данное описание актуально для магнитол, у которых проводной вход для подключения подрулевых кнопок имеет протокол NEC (на некоторых магнитолах встречается вход, чувствительный к сопротивлению).
На ИК-диод подается модулированный сигнал частотой 38кГц (описание протокола NEC http://radiohlam.ru/teory/nec.htm ), с ИК приемника (https://duino.ru/mod-vs1838b.html) подается без несущей частоты.
На вход магнитолы необходимо подавать сигнал без несущей частоты. Для этого правил библиотеку 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).
После такого вмешательства в библиотеку работа с ИК-диодом не возможна.

void IRsend::sendNEC(unsigned long data, int nbits)
{
pinMode(3, OUTPUT);
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
}
else {
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
}
data <<= 1;
}
digitalWrite(3, HIGH);
space(0);
Если так, то всё равно не работает.

Demon083
26.04.2016, 11:14
void IRsend::sendNEC(unsigned long data, int nbits)
{
pinMode(3, OUTPUT);
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
}
else {
digitalWrite(3, HIGH);
digitalWrite(3, LOW);
}
data <<= 1;
}
digitalWrite(3, HIGH);
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
Всё заработало, шапку обновил

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

Shurickk
13.02.2017, 00:27
Всё заработало, шапку обновил

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

ali_vlad
13.02.2017, 19:50
Управление по проводу. Для этих целей была удалена модуляция из библиотеки и инвертирован выходной сигнал.
Если использовать с ИК-диодом - нужно использовать стандартную библиотеку (с модуляцией) и с неинвертированным сигналом.

slavka70
03.11.2017, 23:23
Приветствую. Подскажите. Хотел бы повторить ваше произведение. Желательно через резистивные кнопки руля управлять головным устройством Пионер DVH-870AVBT через ИК диод. Покупал такой (https://ksize.ru/adapter-knopok-na-rule-rezistivnyy-universalnyy-obuchaemyy-infrakrasnyy-un-ir-00000006229.html?q=%D0%B0%D0%B4%D0%B0%D0%BF%D1%82% D0%B5%D1%80+%D0%BA%D0%BD%D0%BE%D0%BF%D0%BE%D0%BA+% D1%80%D1%83%D0%BB%D1%8F&p=1&nocat=0&g=) адаптер и он не копировал полностью нужные команды
1) Получится назначить на одну кнопку два действия, первое действие-короткое нажатие, второе действие-длительное нажатие.
2) Подскажите, какой arduino подойдет для этих целей из этого (https://duino.ru/category/arduino/). Спасибо.

kostet2010@mail.
11.01.2020, 14:23
тоже хочу собрать адаптер для пионера на ИК диоде. с пульта данные снял. а вот с кнопок чо-то не очень получается. после прошивки ардуино в мониторе порта постоянно идут данные .

архей
01.07.2020, 23:05
Выкладываю свою версию адаптера рулевых кнопок.

Надеюсь кому-нибудь пригодится.

пожалуйста подскажите на провод управления у кенвуда идет 3,3 или 5в ?.