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

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

 

 

  1.  В стркое 46, лишняя закрывающая скобка
  2. В строках 019-022 потеряли значиня самих констант (а вот комментарии поправильно правильно) . Индексы пинов. Нумерация с нуля.

Вместо

#define HBRIDGE_1A_PIN // 7-тый пин
#define HBRIDGE_2A_PIN // 8-тый пин
#define HBRIDGE_3A_PIN // 6-тый пин
#define HBRIDGE_4A_PIN // 5-тый пин

нужно

#define HBRIDGE_1A_PIN 0// 7-тый пин
#define HBRIDGE_2A_PIN 1// 8-тый пин
#define HBRIDGE_3A_PIN  2// 6-тый пин
#define HBRIDGE_4A_PIN  3// 5-тый пин

  Так, по крайней мере, компилируется

 

 

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

Еще одну ошибку заметил (свою). При объявлении массива OFF_TIMES нужно четыре нуля, а не пять. Столько же сколько и пинов.

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

 

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

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

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

 ну моторы работать не будут пока в Serial ничего поступать не будет. А раз в сериал ничего не поступает, значит ресивер ничего не ловит. Вывод в serial идет раньше любой нашей логики.

Добавте, после Serial.begin(9600);, что-то типа Serial.println("Arduino-Motor Device ready");

Тогда увидим что "коммуникация работает".

А-а....! Кажись увидел проблему. В setup() потерялось увелечение счетчика когда по массиву бежим

for( int i=0;i<PINS_TOTAL;i++)

Вы уж простите, просто я у меня IDE, в котором набираю, стоит на древнем ноуте да еще через терминалы через забитый эфир wifi. Поэтому нажатие клавиш передается туда с задеркой в секунду две..... Приходится набирать практически вслепую, видя слово "уже после".

 

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

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

Error inside Serial.serialEvent()
java.io.IOException: Bad file descriptor in nativeavailable
at gnu.io.RXTXPort.nativeavailable(Native Method)
at gnu.io.RXTXPort$SerialInputStream.available(RXTXPort.java:1532)
at processing.app.Serial.serialEvent(Serial.java:215)
at gnu.io.RXTXPort.sendEvent(RXTXPort.java:732)
at gnu.io.RXTXPort.eventLoop(Native Method)
at gnu.io.RXTXPort$MonitorThread.run(RXTXPort.java:1575)
 

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

Elektro пишет:

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

Error inside Serial.serialEvent()
java.io.IOException: Bad file descriptor in nativeavailable
at gnu.io.RXTXPort.nativeavailable(Native Method)
at gnu.io.RXTXPort$SerialInputStream.available(RXTXPort.java:1532)
at processing.app.Serial.serialEvent(Serial.java:215)
at gnu.io.RXTXPort.sendEvent(RXTXPort.java:732)
at gnu.io.RXTXPort.eventLoop(Native Method)
at gnu.io.RXTXPort$MonitorThread.run(RXTXPort.java:1575)
 

Все может быть. Можно поробовать использоват сторонний serial monitor. Например putty. Неудобно только что перед каждой заливкой его нужно будет отключать, а потом подключать.

Вот нагуглил подобные же жалобы http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1201489509

Там все немного "пугающе". В конечном итоге пришли что это "похоже на проблемы с питанием". Причем "либо не хватает", либо "у некоторых арудин как-то коротитися 3.3v на землю".

От чего вы питаете свои моторы? Надеюсь от внешнего блока? Питание берете, случайно, не с пина +5v? И уж, упаси боже, не питаете моторы прямо от пина?

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

Ну и еще, можете попробовать увеличить задержку. Возможно ее все-таки не хватает, просто, при использовании светодиода мы этого не замечаем из-за инерции глаза. И "моргание" все-таки есть. А мотор - замечает. 

И еще, не знаю насколько критично, то что пины, например HBRIDGE_4A и HBRIDGE_1A, влючаются/выключаются не АБСОЛЮТНО синхронно, а по очереди. С разницей в микросекунды. Если это критично (хотя думаю нет), то прийдется отказатся от использования digitalWrite и танцевать с прямой записью в порт.

Возможно еще, почему-то, переполняется буфер сериал порта. Попробуйте закоментить все serial.print посмотрите как при этом будут вести себя моторы.

 

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

Если, после того, как закоментити все Serail.print все заработает нормально, и причина именно в них, а терять "отладку" все-таки не хочется, то поробуйте выставить скорость com порта повыше. Я например, обычно ставлю 115200 а не 9600. Если USB кабель нормальный, то никаких проблемм не возникает.

В setup, меняем Serial.begin(9600) на Serial.begin(115200) и не забываем в мониторе тоже поменять.

Возможно пульт шлет команды быстрее, чем они успевают уходить на комп, ну и скетч застряет на всех Serial.print 

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

leshak пишет:

От чего вы питаете свои моторы? Надеюсь от внешнего блока? Питание берете, случайно, не с пина +5v? И уж, упаси боже, не питаете моторы прямо от пина?

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

Ну и еще, можете попробовать увеличить задержку. Возможно ее все-таки не хватает, просто, при использовании светодиода мы этого не замечаем из-за инерции глаза. И "моргание" все-таки есть. А мотор - замечает. 

И еще, не знаю насколько критично, то что пины, например HBRIDGE_4A и HBRIDGE_1A, влючаются/выключаются не АБСОЛЮТНО синхронно, а по очереди. С разницей в микросекунды. Если это критично (хотя думаю нет), то прийдется отказатся от использования digitalWrite и танцевать с прямой записью в порт.

Возможно еще, почему-то, переполняется буфер сериал порта. Попробуйте закоментить все serial.print посмотрите как при этом будут вести себя моторы.

 

питаю от аккумулятора + стабилизатор на 5в

думаю так и сделаю) 

хорошо поэксперементирую.

нет это не критично.

попробую.

PS отпишусь.

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

 проблема не впитание с ним все нормально.

Serial откоментировал проблема осталась, поменял скорость.

вот что мне выдает Serial.monitor:

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

это мне кажется странновато? ведь results и keycode должны быть постоянны, не так ли? 

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

 >думаю так и сделаю)

Нет-нет. "Так" делать не ну нужно. (питаться от +5v или напрямую от пина). Если у вас ардуина имеет внешний разъем питания, то на него нужно забросить 7-9v (максимум 12-ть). До 5v она понизит его своим регулятором. И это то что будет на пине +5v. Но питатся с него не желательно, так как можно перенапрячь ее встроенный регулятор питания. Есть еще пин Vin. Вот на него тупо попадает то что зашло в разъем питания (то есть +7-9v). Просто часто между ними "не видят разницы", так как, когда питание идет от USB и на том и другом имеется 5v которые дало USB. Но моторы питать с USB тоже не стоит. 500ma максимум что можно, теоретически, забрать с USB. Практически иногда раньше дым идет. 

Самое плохое - брать питание с цифрового пина. Там максимум 40ma, да и то суммарное ограничение есть (не помню точно). Вообщем если со всех пинов взять "разрешенные" 40ma, кристалу наступит карачун.

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

leshak пишет:

 >думаю так и сделаю)

Нет-нет. "Так" делать не ну нужно. (питаться от +5v или напрямую от пина). Если у вас ардуина имеет внешний разъем питания, то на него нужно забросить 7-9v (максимум 12-ть). До 5v она понизит его своим регулятором. И это то что будет на пине +5v. Но питатся с него не желательно, так как можно перенапрячь ее встроенный регулятор питания. Есть еще пин Vin. Вот на него тупо попадает то что зашло в разъем питания (то есть +7-9v). Просто часто между ними "не видят разницы", так как, когда питание идет от USB и на том и другом имеется 5v которые дало USB. Но моторы питать с USB тоже не стоит. 500ma максимум что можно, теоретически, забрать с USB. Практически иногда раньше дым идет. 

Самое плохое - брать питание с цифрового пина. Там максимум 40ma, да и то суммарное ограничение есть (не помню точно). Вообщем если со всех пинов взять "разрешенные" 40ma, кристалу наступит карачун.

я имелл в виду что заменю моторы на светодиоды.

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

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

Elektro пишет:

 проблема не впитание с ним все нормально.

Serial откоментировал проблема осталась, поменял скорость.

это мне кажется странновато? ведь results и keycode должны быть постоянны, не так ли? 

Да странно. Я бы предложил после Serial.println(keyCode, HEX); добавить строчку Serial.println("");

Просто легче будет читать вывод. result и keycode тогда сгрупируются по парам. Будет виден каждый проход.

Из того кода что вы написали, видно, что библиотека, по какой-то причине, не расшифровала полученный код. И вернула ноль.

Причина может быть:

  1.  Слишком были заняты отправкой в serialPrint и не успели, например, прочитать начало посылки кода.
  2. В пульте поддохли батарейки
  3. Все-таки "танцует" питание
  4. Плохой контакт на датчике
  5. Какая-то инфакрасная помеха. Говорят лампы энергосберегающие дают такое, но лично я, когда игрался с пультом, не замечал такого.

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

 

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

 >я имелл в виду что заменю моторы на светодиоды.

А если моторы просто отключить, в serial вот эти results:0 появляются?

results - это то что мы получили от библиотеки

keycode  - это то что мы получили от библиотеки если от нее пришел любой код, кроме REPEAT. А если пришел REPEAT, тот тут будет код запомненый на предыдущем "настоящем" нажатии. В данный момент туда попадает и 0, а "не должен".

Ну и дальше, при сравнениях используется уже keycode, а не results.

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

 Попробуйте сделать так:

 После строчки Serial.println(keyCode, HEX); добавить

Serial.print("Decode type:");Serial.println(results. decode_type);

Потом все  " unsigned long keyCode=results.value; " (включая эту строчку) и до "irrecv.resume(); // получить следующие значение" (не включая эту срочку), обернуть в if(results. decode_type!= UNKNOWN){ }

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

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

 Поправка:

 

Serial.print("Decode type:");Serial.println(results. decode_type);

добавить после

Serial.println(results.value, HEX);

а не  Serial.println(keyCode, HEX);

ну и потом покажите что "нам serial говорит".

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

Если Decode type: UNKNOWN будет приходить в serial слишком часто, то можно, еще поигратся с дефайном TOLERANCE в файле IRemoteInt.h в библиотеке. Любой пульт выдает импульсы "немного не четко". Этим дефаном задается, в процентах, насколько импульсы/паузы могут плавать от заложенного в протоколе.

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

Этот скетч выкидывает в сериал максимально возможно количество инфы: какой кодировкой удалось расшифроваить, и главное - длинну захваченных импульсов/пауз в сыром виде. Дальше почитав описание соотвествующего протокола, сравнив его с тем что шлет ваш пульт можно "подкрутить" соотвествующие константы в IRemoteInt.h 

Например, может оказаться что ваш пульт работает по протоколу NEC, но почему-то стартовый импульс шлет длинной 7000 микросекунд (в среднем), а не 9000, как заложенно в библиотеке. Тогда можно либо крутить TOLERANCE что-бы 7000 "пападало в погрешность", либо менять дефайн NEC_HDR_MARK

Или количество имульсов данных отличается... вообщем игратся можно долго :) А, в свое время, с пультом от томпсона, чуть-ли не больше месяца танцевал, пока разобрался. Эта библиотека его кодировку вообще не поддерживала, пришлось ее "дописывать", уж больно внешний дизайн пульта нравился, по сравнению с остальными. А потом оказалось что скетч не влазит в камень Atmega8.... тоже пришлось "выкручиватся", делать возможность "отключать" не нужные протоколы.

 

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

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

results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1

 

может быть нужно искать проблему в turnONPin?

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

Elektro пишет:

 слачайно кое что обнаружил:

А зачем случайно, нужно было специально. Я же писал "А если моторы просто отключить, в serial вот эти results:0 появляются?"

>results:0
>Decode type:-1

это значит "не смогли расшифровать код".

>если отключить от выходных пинов нагрузку дд или даже светодиод

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

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

>может быть нужно искать проблему в turnONPin?

Нет. Во первых "там искать негде". Во вторых, по хорошему, скетч не знает есть нагрузка или нет. Только в случае если нагрузка дает какие-то помехи или скачки по питанию. А втретих, раз вы добавили этот if, то turnOnPin вообще не вызывается когда Decode type:-1

Но это можно "не гадать", а проверить. Закоментить все в внутри turnOnPin и посмотреть "есть ли Decode type:-1". Если исчезло, то добавить в setup включение всех пинов (не раскоменчивая содержимое turnOnPin). Там где мы их, в цикле ставим в low, сделать hight. Если при этом проблема появится - значит сам факт включение пинов и нагрузки приводит к проблеме и turnOnPin - не причем. Ну и незабыть "вернуть все взад" после завершения эксперимента.

Что-бы я проверил дальше:

  1. Потыкал осцилографом (если есть) или, на крайняк тестером в пин +5v. Посморел что на нем происходит под нагрузкой.
  2. Банально проверил все контакты. Может "кто-то где-то гуляет".
  3. Проверил что IR датчик подключен с конденсатором (он должен сглаживать небольшие помехи).

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

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

 >>Я правильно понял что даже когда нагрузкой является только светодиод, проблема присутсвует, или она проявляется только когда нагрузкой является "мотор"?

да даже если подключить светодиод то в сериал фигня идет.

плата Orduino nano atmega168

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

 Вот, смотрите кусочек файла IRemoteInt.h

#if defined(__AVR_ATmega1280__)
  //#define IR_USE_TIMER1   // tx = pin 11
  #define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  //#define IR_USE_TIMER5   // tx = pin 46 
....

Из этого видно, что девятый пин нельзя ничем занимать, ни нагрузками, ни датчиком.

Попробуйте найти аналогичный код для вашей платы. Полазте по библиотеке (у меня очень старая ее версия), посмотрите может быть она внутри использует другие библиотеки для работы с таймерами. Например http://arduino.cc/playground/Code/Timer1, тогда нельзя использовать 9 и 10 пины. Сделайте вывод в serial какие имеено IR_USE_TIMER[XXX] у вас определеный. Что-бы знать что именно у вас используется.

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

 Можете попробовать вкурить в эту диаграмку, попробовать понять на каком же пине, какой у вас таймер arduino.cc/en/Hacking/PinMapping168

Ну или банально "методом научного тыка". Отключаем нагрузку от всех пинов. Убеждаемся что "проблемы нема". Подключаем нагрузку к одному из пинов. Если проблема "появилась" - переносим его на другой пин (кроме PIN0, PIN1 на них RX,TX уже висит). Не забываем в скетче сменить номер пина (массив PINS, константы вида HBRIDGE_1A_PIN при этом "трогать" не нужно).

В первую очередь я проверил-бы восьмой пин.

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

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

ошибки как были так и лезут все о которых говорили раньше.

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

 Ну значит при светодидах ошибок меньше. Они теперь "просто игнорируются". Если пришло 10 команд, и которых 9 ошибка, и одна нормальная - все отработает как нужно. И вы ничего не заметите, так как это "меньше чем за пол секунды", а вот когда 10 из 10-ти вернули UNKNOWN вы уже "видите".

На данный момент, ничего кроме того, что я уже советовал проверить, я посоветовать не могу:

  1. Закоментить все в turnPinOut и включить все пины в setup(), и посмотреть какие команды приходят с пульта
  2. Проверить что же в действительности у нас на +5v
  3. Проверить контакты и способ подключения датчика
  4. Попробовать другие пины.
Elektro
Offline
Зарегистрирован: 10.02.2012

>>>Но это можно "не гадать", а проверить. Закоментить все в внутри turnOnPin и посмотреть "есть ли Decode type:-1". Если исчезло, то добавить в setup включение всех пинов (не раскоменчивая содержимое turnOnPin). Там где мы их, в цикле ставим в low, сделать hight. Если при этом проблема появится - значит сам факт включение пинов и нагрузки приводит к проблеме и turnOnPin - не причем. Ну и незабыть "вернуть все взад" после завершения эксперимента. 

закоментил

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

вот что выдал Serial:

results:FFFFFFFF
Decode type:1
keycode:40BF807F

results:FFFFFFFF
Decode type:1
keycode:40BF807F

results:FFFFFFFF
Decode type:1
keycode:40BF807F
 

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

 Ну так теперь едем дейтсвуйте дальше. Реализуйте "Если исчезло, то добавить в setup включение всех пинов (не раскоменчивая содержимое turnOnPin). "

Есчезло, теперь включайте все пины в setup ( digitalWrite(PINS[i], HIGH); а  не LOW  ). Вешайте на них нагрузку и смотрите, есть по прежнему ли все "хорошо" (Decode type:1)?

 

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

 при( digitalWrite(PINS[i], HIGH); а не LOW ) вот что выдает Serial:

results:40BF807F
Decode type:1
keycode:40BF807F

results:FFFFFFFF
Decode type:1
keycode:40BF807F

results:FFFFFFFF
Decode type:1
keycode:40BF807F
 

не понял вашу мысль? << есть по прежнему ли все "хорошо" (Decode type:1)?>>

тоесть Decode type:1 это то что мы и должны получать? 

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

 >тоесть Decode type:1 это то что мы и должны получать?

Ну да. Смотрите в файл IRremote.h там описанно что означает эта цифра 1.

#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define DISH 5
#define SHARP 6
#define THOMSON 7
#define UNKNOWN -1 

То есть "1"  означает: "Все хорошо, полученный сигнал удалось раскодировать. Сигнал был в NEC кодировке. Это был код поторения FFFFFFFF ".  И, как видите, keycode тоже имеет нормальное значение. Это значит что перед этим кодом повторения был нажата нормальная клавиша (просто видимо проскролилось и вы не увидели этого).

Когда же тип "-1", это значит "Сигнал получен, но расшифровать его не смогли. Кодировка UNKNOWN (НЕИЗВЕСТНАЯ)". Ну и results.value при этом, естественно лежит не код клавиши (который неизвестен) а ноль.

 

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

 спасибо теперь понял) 

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

> при( digitalWrite(PINS[i], HIGH); а не LOW ) вот что выдает Serial: Decode type:1

А нагрузка при этом подключена? Моторы крутятся?

Если да, то это... грустно. Значит предстоит еще  "много эротики".

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

 А нагрузка при этом подключена? Моторы крутятся?

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

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

 а-ааа, блин горелый...

в turnOffPinIfRequired тоже нужно все закоментить. Толку что мы их влючили все пины в setup, если в конце первого же loop  turnOffPinIfRequires их все выключит (turnOffTimes-то изначально-то все нули).

Ну или закоментить, в конеце loop цикл вызова этих turnOffPinIfRequired

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

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

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

 Хреново. Надеялся что в serial будет шлак.

Ладно, тогда есть две версии.

  1. Функция времени millis() как-то "сбивает" таймеры внутри IR библиотеки.
  2. Помехи создает не просто нагрузка, а "пульсирующая нагрузка".

Первое проверить легче, давайте с этого начнем.

Добавте в конце loop строчку:

unsigned long someTime=millis();

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

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

 да после добовления unsigned long someTime=millis(); и подключние нагрузки (моторов) в Serial летит один "шлак":

Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
Decode type:-1
results:0
 

 

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

 Блин... погуглил. Куча примеров использования этой библиотеки и везде спокойно используется эта millis(). Даже в примерах которые идут с самой библиотекой и то есть ее использование. Хотя тут ответом может быть то, что под разные камни она по разному использует таймеры. И под другой камень этой проблемы может не быть.

Да и у нас-то она работает без нагрузки. Что вообще не понятно.Если она ломает таймеры, то это не должно зависить от нагрузки. Что опять нас подводвит к вопросу "а не проседает ли у нас питание". Или мы, таки, используем какой-то пин который "низзя". (millis использует timer0).

Сейчас у нас есть два варианта:

  1. Вернутся к использованию counter и "не трогать" функцию millis() - плохой вариант. Более менее серьезная логика все равно, рано или позно ее потребует.
  2. Разбиратся "что с ней не так".

Если идти по второму варианту, то можно попрбовать три вещи (но по отдельности, не одновременно).

1. "Черная магия" - перед вызовом millis() добавить строчку "cli(); // запрещаем прерывания", а после нее добавить строчку " sei(); // разрешаем прерывания"

2. "Грязная магия" - убираем cli() и sei(), и после нее пишем "delay(50);// надеемся что проблемма не в вызове millis(), а в слишком частом ее вызове"

3. Убираем delay(). Отключаем от всех пинов нагрузку. И подключаем "по одному" (жмакая пульт), надемся найти "проблемный".

 

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

Функция millis() не может негативно влиять на что-либо. Ее реализация до безобразия проста (и безопасна):

unsigned long millis()
{
	unsigned long m;
	uint8_t oldSREG = SREG;

	// disable interrupts while we read timer0_millis or we might get an
	// inconsistent value (e.g. in the middle of a write to timer0_millis)
	cli();
	m = timer0_millis;
	SREG = oldSREG;

	return m;
}

 

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

А вот с delay() надо быть поосторожнее - эти вызовы могут сбить любую с трудом построенную в программе синхронизацию.

Еще на что я бы посмотрел - это как реализовано чтение фронтов в библиотеке, поддерживающей ИК. Если использован какой-либо из таймеров 1 или 2, то некоторые каналы  ШИМ нарушаются (если на разрушаются вовсе). Не следил за дискуссией, но глаз все же зацепился за слово "моторы". Они с помощью ШИМ управляются? Тогда надо пробовать управлять ими с помощью других ШИМ-выводов. В этом деле может помочь табличка соответствия между таймерами (каждый из них имеет по два PWM-канала - A и B) и ШИМ-выводами Arduino.

 

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

 >Функция millis() не может негативно влиять на что-либо

Я тоже так думал, но вы же видите. Как только добавили в loop вызов этой функции, IR-ра начал приходить джанк. Причем только если пины под нагрузкой (я вообще не могу этого понять, почему нужно именно сочетание millis() и нагрузки).

А то если посмотреть на код функции который вы привели, то можно предположить что "таки мешает", есть "запретить прерывание", значит останавливаются таймеры (не уверен), а вдруг в этот момент пришел импульс от IR-a? Внешнее же прерывание не сработает и импульс "потеряется". Если ее дергать "очень быстро", то получается и "импульсы будут постоянно терятся" (но опять всплывает вопрос "а причем тут нагрузка на пины?")

Опять-таки в этой реализации я вижу "запретить прерывания", но не вижу "разрешить"? Разве после ее каждого вызова нужно делать  sei(); ? Но.... причем тут, тогда, наличие/отсутвие нагрузки???? :(

Если дело "в нагрузке", то почему она не мешает когда millis() не вызывается? Взрыв мозга....

 

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

leshak пишет:

 

Опять-таки в этой реализации я вижу "запретить прерывания", но не вижу "разрешить"? Разве после ее каждого вызова нужно делать  sei(); ? Но.... причем тут, тогда, наличие/отсутвие нагрузки???? :(

Флаг установки/запрета прерываний - седьмой (самый старший) бит региста SREG. sei() в данном случае - избыточная операция. состояние флага восстановится после выполнения инструкции SREG=oldSREG.

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

 Спасибо за разъяснения. Ну тогда пункт "Черная магия" можно не проверять. Он фактически дублируется внутри millis(), причем более корректным образом.

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

step962 пишет:

А вот с delay() надо быть поосторожнее - эти вызовы могут сбить любую с трудом построенную в программе синхронизацию.

Знаю. Это от отчаяния. Мы вообщем-то на millis() и перешли что-бы нигде не использовать delay(). Тут я его предложил сугубо в отладочных целях. Проверить не является ли проблеммой слишком ЧАСТЫЙ вызов millis().

step962 пишет:

Еще на что я бы посмотрел - это как реализовано чтение фронтов в библиотеке, поддерживающей ИК. Если использован какой-либо из таймеров 1 или 2, то некоторые каналы  ШИМ нарушаются (если на разрушаются вовсе).

Нет. Шимы не используются. Только digitalWrite. Просто "включаем/выключаем пины".  Если на пинах нет никакой реальной нагрузки, то вся логика вообще работает "нормально" (судя по логу в Serial). Все команды с IR-библиотеки приходят расшифрованными. Если же к пинам подключается "нагрузка" в виде мотора или даже просто светодиод - от IR-на начинают приходить "не смогли распознать результат". Причем если нагрузка "моторы" то чаще, если "диоды" то реже.

Если включить все пины "руками" (в setup). Закоментить везде вызов millis() - с IR-а все приходит нормально, вне зависимости от нагрузки, если же в loop() начать вызывать millis() (просто вызывать, даже не использую нигде результат), начинаем с IR получать "Unknown".

 

 

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

 Elektro, приведите тут наверное текущие состояние скетча. Которое получилось после "добавления unsigned long someTime=millis();"

Может кто-то посмотреть "свежим взглядом" и увидит очевидное? Да и нам референсится дальше проще будет.

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

Блин... погуглил<< 

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

 

вот скетч


#include <IRremote.h>

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

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

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

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


//определяем константы для кодов клавиш что-бы код легче читался
#define FORWARD_KEY 0x40BF807F
#define BACK_KEY 0x40BF906F
#define LEFT_KEY 0x40BF20DF // подставте нужный код клавиши
#define RIGHT_KEY 0x40BF609F // подставте нужный код 
int RECV_PIN = 11;

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],HIGH);
  }
  Serial.begin(115200);
  Serial.println("Arduino-Motor Device ready");
}

void loop() {

  // Логика получения нажатий от пульта,&nbsp;тут мы фактически "регистрируем факт нажатия"
  if(irrecv.decode(&results)){ // на пульте что-то нажали
    Serial.print("results:");
    Serial.println(results.value, HEX);
    Serial.print("Decode type:");
    Serial.println(results. decode_type);
    if(results. decode_type!= UNKNOWN){ 
      unsigned long keyCode=results.value;  // дальше будем проверять значение этой переменной, а не  results.value
      if(keyCode==REPEAT) keyCode=lastPressedKey; // пришел код ПОВТОРЕНИЕ, значит нужно сделать вид что еще раз нажали предыдущую клавишу.
      Serial.print("keycode:");
      Serial.println(keyCode, HEX);
      Serial.println("");
      //  задаем соотвествие что делать на нажития кнопок пульта, тут нам и пригодятся объявленные константы
      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);// пробегаемся во всем счетчикам и или уменьшаем их или выключаем пин    
  unsigned long someTime=millis();
}    

 

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

 Попробуйте, 

пункты 2,3 после слов "Если идти по второму варианту, то можно попрбовать три вещи" из сообщения #85. С первым пунктом уже помог step962

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

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

 Может быть повтор - но лень читать всю ветку.

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

ЗЫ: наискосок просмотрел IRremote.cpp. Вся логика отслеживания принимаемого ИК-сигнала основана на регулярном опросе состояния входной линии, т.е. точность определения ширины импульсов/пауз 2 такта таймера (а может быть и поболе). Тут бы лучше прерывания INT0/INT1 использовать, но - что есть, то есть. Если есть возможность, следует попытаться увеличить допуски на попадание в "правильные" длительности. Предлагает библтотека что-то подобное?

ЗЗЫ: Было бы очень полезно взглянуть, что записывается в массив irparams.rawbuf при отключенной и подключенной нагрузке и нажатии одной и той же клавиши на пульте. Если длительности (именно они записываются в этот массив) будут равномерно увеличены/уменьшены при подключении нагрузки по сравнению с "ненагруженным состоянием", то, значит тактовый генератор микроконтроллера при подключении нагрузки начинает идти быстрее/медленнее - т.е. нестабильность генератора.

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

 Как тактируется мк, насколько стабильно? От внешнего (кварц, керамика?) или от внутреннего осциллятора? М.б. подключение нагрузки просаживает тактовую частоту?  <<<

плата покупная orduino nano v1.1 на ней стоит кварц на 16мГц какой точно не знаю, не написано.

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

 при #define OFF_DELAY 150;  ошибка вылазит не сразу и не так часто.

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

 > при #define OFF_DELAY 150; ошибка вылазит не сразу и не так часто.

А вот это уже точно "оптический обман слуха". Она используется в единственном месте - функции turnONPin, причем в данный момент это использования закоменчено. То есть на данный момент оно вообще нигде не используется. Более того, так как это define, а не переменная в скомпилированную прошивку эта цифра не попадает даже в виде "неиспользуемого значения".

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

>подключение нагрузки просаживает тактовую частоту

Правдоподобно. Но опять-таки "причем тут вызов millis()?", разве что это тоже "просто совпало", как с  OFF_DELAY и millis() действительно не причем.

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

Предлагает. Я уже рассказывал про возможность поигратся с дефайном TOLERANCE, но не знаю было-ли это сделано.

>Было бы очень полезно взглянуть, что записывается в массив irparams.rawbuf

2Elektro: "как это сделать" можно подсмотреть в в примере IRecvDump, конец функции dump(), ну или вообще ее "скопировать ее целиком" к себе в скетч и вызывать вместо строк 061-064

Думаю стоит это сделать. Возможно даже это первое что нужно сделать (вывод дополнительной дебаговой инфы).

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

 http://www.e-shore.com.my/homepage/all-projects/193-ir-remote-control-mobile-robot.html нашел статью, почитал и посмотрел видео, в статье описано как раз то что мне нужно, даже приведен действующий код, пульт у меня примерно такойже, так же и NEC кодировка. на видео видно что у него все работает идеально. у меня два вопроса почему у меня не работает этот же код? и почему в коде не прописано повторение но у него, как я понима, оно работает!??!?

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

Elektro пишет:

у меня два вопроса почему у меня не работает этот же код? и почему в коде не прописано повторение но у него, как я понима, оно работает!??!?

Я не знаю, рассматривался ли этот вариант, но может быть "Дело было не в бобине..."?

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

Какая плата Arduino используется?

Какой именно ИК-приемник используется?

Есть ли обвязка у ИК-приемника? Какая?

Как соединены приемник и Arduino?

Где располагается собранная схема (варианты: на столе/под столом/в коробочке/на гвоздике висит/...)?

Какой пульт используется для посылки команд (какая кодировка)?

Какое освещение в комнате (тип ламп, количество, мощность)?

От чего запитывается схема (USB/блок питания/батарейка/...)?

 

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

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

 > у меня два вопроса почему у меня не работает этот же код?

Наверное потому что код работает, а проблема в железе. У вас и наш скетч работал, пока не появилась "нагрузка", а это именно "железо".

Просадка питания или, как предположил step962 - уход тактовой частоты.

Ну и телепатически ответить "почему не работает" - тоже трудно. Сделайте вывод дебаг инфы (смотрите сообщение #97). Проверить же в "чем отличие в железе" (список вопросов которые задал step962) - это только вы можете, удаленно тут ничего не сделаешь. Разве что коственно догадываться по выводу "сырых данных" (но вы пока их не дали).

> и почему в коде не прописано повторение но у него, как я понима, оно работает

Не уверен. На 18-22 секунде видно, что что когда он нажимает вправо/влево робот делает краткий "поворот" (150 ml).и останавливается, после чего ему приходится делать пальцем быстрое повторное нажатие что-бы его "еще довернуть".

Кстати, попробуйте же, наконец, в наш скетч в конце loop добавить delay(50). Или вы решили на нашу версию плюнуть и "не дожимать ее"? Кстати, этот скетч из "статьи" вообщем супер-принципиальных отличий от нашего кода не имеет.