Проблемы с библиотекой "IRremote.h"
- Войдите на сайт для отправки комментариев
Добрый день.
Стал замечать какие-то непонятные ситуации со скетчами, использующими библиотеку "IRremote.h".
Сразу должен сказать что язык только еще изучаю и по этому прошу относиться к моим скечам некритично.
Ситуация #1.
Есть вот такой скетч:
#include "IRremote.h" #include <LiquidCrystal.h> IRrecv irrecv(8); decode_results results; LiquidCrystal lcd (7, 6, 5, 4, 3, 2); // нестандартное подключение дисплея 1602, но мне так удобней: одной фишкой почти все контакты! int pos=0, col=1; /* нарисовать свой бегунок byte cur[8] = { B11111, B11011, B11011, B00000, B00000, B11011, B11011, B11111, };*/ void setup() { // lcd.createChar(1, cur); pinMode(9, OUTPUT); // ЗАДЕЙСТВОВАТЬ 9-фй ПИН analogWrite(9, 10); // УСТАНОВИТЬ КОНТРАСТ на 9-ом пине в 10 // лень припаять переменный резистор на контраст pinMode(13, OUTPUT); // digitalWrite(13, LOW); // Потушить светодиод, который сильно бъёт в глаза lcd.begin (16, 2); // Start LCD lcd.clear(); lcd.setCursor (0,0); lcd.setCursor (0,0); lcd.write ("key: "); irrecv.enableIRIn(); } void loop() { key_a(); } //************************************************************************************ // *********************** Функция: Нарисовать бегунок //************************************************************************************ void bar(int pos, int col) { lcd.setCursor (13,0); lcd.print(" "); lcd.setCursor (13,0); lcd.print(pos+1); lcd.setCursor (pos,col); lcd.write("1"); } //************************************************************************************* // *********** Функция: Отобразить название нажатой на пульте кнопки //************************************************************************************* void key_dsp (String key) { lcd.setCursor (5,0); lcd.print (" "); lcd.setCursor (5,0); lcd.print (key); } //************************************************************************************* //*** Функция: Считать код нажатой на пульте кнопки и отобразить его *** //************************************************************************************* void key_a() { if (irrecv.decode(&results)) { // если нажатая кнопка "VolUp" и бегунок не уперся в правую часть строки: if (results.value == 9249 && pos <16) { key_dsp("VolUp"); lcd.setCursor (pos-1,col); lcd.write(" "); bar(pos, col); pos++; } } // если нажатая кнопка "VolDown" и бегунок не уперся в левую часть строки: if (results.value == 25633 && pos>-1) { key_dsp("VolDown"); lcd.setCursor (pos+1,col); lcd.write(" "); bar(pos, col); pos--; } irrecv.resume(); delay(100); }
Вот пока по экрану бегала еденичка, было всё нормально: она бегала вправо по "VolUp" и влево по "VolDown". Но как только я решил нарисовать какой-то особый бегунок, по "VolDown" бегунок стал бежать влево, независимо от того нажимаю я кнопку на пульте или уже отпустил. То есть - стоит один раз прижать "VolDown" и бегунок тут же бежит влево до упора. Причем ситуация не меняется даже если поместить всё что касается нового бегунка в комментарные скобки!
Смысл происходящего меня ставит в тупик, если честно...
Ситуация #2.
Любой скетч с использованием этой библиотеки работает только когда плата подключена к работающему компьютеру. Если просто подать питание - на пульт не реагирует. Вернее работает всё, кроме считывания импульсов.
Ситуация #3.
Пробовал стандартный скетч из примеров библиотеки "TVout.h" и тоже: как только в тело программы включается строка: "irrecv.enableIRIn();" - всё что было написано на экране до этого превращается в какие-то чёрточки. Причем кадр стоит на месте, а портятся именно выведенные до этого символы.
Что это всё может значить?
Не хватает одной фигурной скобки в конце скетча, но это потому что я корректировал текст программы и случайно удалил закрывающую скобку от самого верхнего "if" в "
void
key_a()
".Просто опечатка. Как редактировать свой пост - я не нашёл...
потому что я корректировал текст программы и случайно удалил
Нельзя корректировать текст программы! Он должен быть помещён сюда тупым копи-пастом, чтобы желающий Вам помочь видел ИМЕННО ТОТ текст, который исполняется, а не какой-то бред без скобок.
Откуда мне знать, что Вы там ещё накорректировали?
Был тут случай, сидел минут сорок, разбирался, выложил ТС описание ошибки, а он мне "да, нет, этого куска там нет, я его вставил только при публикации скетча". Угдадайте с трёх раз, что я сказал про себя и стал ли дальше заморачиваться проблемами этого человека?
Выложите нормальный скетч.
Тоже самое, Вы пишете: "Пробовал стандартный скетч из примеров библиотеки "TVout.h" и тоже: как только в тело программы включается строка: "irrecv.enableIRIn();"". Пожалуйста, скетч с включённой строкой.
И ещё раз тоже самое, Вы пишете: "Любой скетч с использованием этой библиотеки работает только когда". Любые скетчи мы не отлаживаем. Пожалуйста выложите пример как можно более короткий, который ведёт себя таким образом.
Я тоже об этом подумал, но первый пост в теме, очевидно, не корректируется. Спасибо за критику ))))
Вот полный текст первого скетча (As Is): (кстати - как тут прятать код ? Что бы можно было его развернуть и свернуть)
Вторая ситуация так же касается этого скетча. Собственно, это финальная версия двух задач: научиться работать с пультом и с помощью пульта осуществлять навигацию по экрану.
Третяя ситуация и второй скетч у меня на работе, так как только там у меня есть маленький настольный TFT телевизор и только там я пытаюсь что-то вывести на экран с помощью библиотеки ""TVout.h"". Выложу чуть позже. Сочинять что-то на скорую руку без отладки, я так понял - не солидно.
(кстати - как тут прятать код ? Что бы можно было его развернуть и свернуть)
Там флажок есть. Читайте внимательно.
Какая-то лишняя скобка обнаружилась перед строкой "
if
(results.value == 25633 && pos>-1)
" Странно. Я выложил всё как есть и компилятор на работе на нее ничего не сказал, вот буквально еще сегодня утром... Но ей там явно не место. Сейчас попробую прогнать на ошибки дома..Вообще-то я заметил отличия в работе одного и того же IDE дома(Windows 8.1 (x64)) и на работе(XP).
Проверил. Выскочило только:
Несколько библиотек найдено для "IRremote.h"
Используется: F:\!ARDUINO\arduino-nightly-windows\libraries\IRremote
Не используется: F:\!ARDUINO\arduino-nightly-windows\libraries\RobotIRremote
Больше ничего. Лишняя скобка стоит. Странно...
Когда убираешь ту скобку, выскакивет вот что:
Arduino: 1.6.8 Hourly Build 2016/02/19 10:33 (Windows 8), Плата:"Arduino/Genuino Uno"
C:\Users\Admin\Documents\Arduino\IR_Move_Bar\IR_Move_Bar.ino: In function 'void key_a()':
IR_Move_Bar:262: error: expected '}' at end of input
}
^
Несколько библиотек найдено для "IRremote.h"
Используется: F:\!ARDUINO\arduino-nightly-windows\libraries\IRremote
Не используется: F:\!ARDUINO\arduino-nightly-windows\libraries\RobotIRremote
exit status 1
expected '}' at end of input
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
Сейчас посчитаю скобки...
------------------------
Выяснилось что не хватает одной закрывающей скобки в самом низу, очевидно для последнего "void()"... Подключаю плату.
------------------------
После удаления той скобки, всё стало на свои места. Да вот как бывает... И без компьютера - тоже работает теперь. Вот интересно.
Спасибо. Буду разбираться дальше. Мне что-то алгоритм не совсем нравится. Да и навигация по меню с пульта тоже не очень удобна. Пульт посылает серии импульсов, в конце каждого ставя другой, какой-то одинаковый код и все эти ситуации приходится отлавливать.
Если использовать пульт в других целях, то вполне хватит и такого алгоритма. Надо только как-то отследить его привычку посылать серии...
Ctrl-T форматирует текст
(кстати - как тут прятать код ? Что бы можно было его развернуть и свернуть)
Там флажок есть. Читайте внимательно.
Спасибо. Но в следующий раз теперь. Уже изменить не даёт.
Ctrl-T форматирует текст
Внутри кода?
Да, всё работает нормально и с "самодельным" бегунком тоже.
Единственное что доставляет неудобства - это неустойчивая работа IR-приёмника: не реагирует на пульт пока не пошевелишь его лапки или перестаёт реагировать после загрузки нового скетча. Возможно это потому что он покдлючен, как было где-то сказано: "не по феншую" - без резистора и коненсатора. А в остальном, вроде как, по феншую: на 3.3V и на 8-й пин.
Спасибо. Но в следующий раз теперь. Уже изменить не даёт.
Ctrl-T форматирует текст
Внутри кода?
В IDE. Форматирует текст (Ctrl-T) к более читабельному виду, твой код читать - глаза сломать. На вкус и цвет товарищей нет, но всё-таки лучше придерживаться каких либо общепринятых стандартов (единого, увы нет), вылезая и своей норы, тогда и помощь будет более весомой.
Используя форматирование также поможет избежать наличие/отсутствие скобок. Совсем не исправит, но будет легче.
Спасибо. Но в следующий раз теперь. Уже изменить не даёт.
Ctrl-T форматирует текст
Внутри кода?
В IDE. Форматирует текст (Ctrl-T) к более читабельному виду, твой код читать - глаза сломать. На вкус и цвет товарищей нет, но всё-таки лучше придерживаться каких либо общепринятых стандартов (единого, увы нет), вылезая и своей норы, тогда и помощь будет более весомой.
Используя форматирование также поможет избежать наличие/отсутствие скобок. Совсем не исправит, но будет легче.
А, ну да. В чужой монастырь, типа....
Я до этого последний раз писал на PL/1 и еще с тех времен притащил этот стиль.
Сейчас посмотрим обо что теперь народ глаза ломает...
----------
Нажал Ctrl-T - всё прибило к левому краю да и всё. Как по мне - не читабельно: все строки начинаются почти с первого столбца и не видно уровней вложенности операторов...
А хотя - нет. Форматирование-таки сдвигает вправо вложенные if-ы, но очень уж экономно.
Но тут надо признать что потерять скобку уже не удастся, что и произошло в вышеописанном примере.
Да. Наверно буду начинать привыкать к IDE-шному форматированию, а то его компилятор следит только за четностью скобок, а где и почему они стоят - его уже не интересует.
А теперь, буду благодарен если кто-то раскритикует мой скетч с точки зрения оптимизации и вообще, с любой точки зрения.
Например вот я уже заметил что совсем не использовал директиву "#define", хотя можно было бы забить туда все возвращаемые пультом коды, освободив тем самым немного памяти. Только как потом это использовать в программе - понятия не имею...
А, ну да. В чужой монастырь, типа....
Я до этого последний раз писал на PL/1 и еще с тех времен притащил этот стиль.
Сейчас посмотрим обо что теперь народ глаза ломает...
----------
Нажал Ctrl-T - всё прибило к левому краю да и всё. Как по мне - не читабельно: все строки начинаются почти с первого столбца и не видно уровней вложенности операторов...
А хотя - нет. Форматирование-таки сдвигает вправо вложенные if-ы, но очень уж экономно.
Но тут надо признать что потерять скобку уже не удастся, что и произошло в вышеописанном примере.
Да. Наверно буду начинать привыкать к IDE-шному форматированию, а то его компилятор следит только за четностью скобок, а где и почему они стоят - его уже не интересует.
Да, всё верно про чужой монастырь, не я придумал, сам понимаешь.
Если уж так хочется, сделай Ctrl-T, Ctrl-A, Ctrl-C, потом Ctrl-Z (даже не отпуская клавишу Ctrl, нажми последовательно 4 клавиши TACZ) и продолжай любоваться своими кривыми скобками. После этого в клипбоарде будет лежать отформатированный исходник.
"где и почему они стоят - его уже не интересует" собственно и не дОлжно компилятору знать, где стоят скобки, иначе он тебя и меня загнал бы в жесткие рамки, а оно надо? Лично мне - нет. Prolog не юзал, да и не было нужды/желания.
На счет форматирования, найди файл: Arduino/lib/formatter.conf исправь строчку
В строках 172 - 256 у Вас огромная куча if'ов, при этом если какой-то из них дал истину, очевидно, что уже никакой другой истины не даст, а Вы зачем-то продолжаете отрабатывать все сравнения. Зачем?
Если уж так хочется, сделай Ctrl-T, Ctrl-A, Ctrl-C, потом Ctrl-Z (даже не отпуская клавишу Ctrl, нажми последовательно 4 клавиши TACZ) и продолжай любоваться своими кривыми скобками. После этого в клипбоарде будет лежать отформатированный исходник.
"где и почему они стоят - его уже не интересует" собственно и не дОлжно компилятору знать, где стоят скобки, иначе он тебя и меня загнал бы в жесткие рамки, а оно надо? Лично мне - нет. Prolog не юзал, да и не было нужды/желания.
На счет форматирования, найди файл: Arduino/lib/formatter.conf исправь строчку
В строках 172 - 256 у Вас огромная куча if'ов, при этом если какой-то из них дал истину, очевидно, что уже никакой другой истины не даст, а Вы зачем-то продолжаете отрабатывать все сравнения. Зачем?
Так я же не могу все кнопки нажать за один раз? Один раз сработает один "if", в следующий раз - другой...
А что есть какой-то другой способ отследить нажатую клавишу не перебирая все возможные? Интересно какой.
Можно еще применить "Case", но их тоже будет столько же сколько и кнопок.
И расскажите мне лучше как обращаться с директивой "#define" в этом случае. Можно же как-то?
Можно еще применить "Case", но их тоже будет столько же сколько и кнопок.
Не можно, а нужно. "case" для таких случаев и создан. И не важно, сколько там условий, главное, что не будет перебора по всему списку, даже если совпадение будет первым.
И расскажите мне лучше как обращаться с директивой "#define" в этом случае. Можно же как-то?
Что может быть проще - компилятор ищет одну комбинацию символов и заменяет ее другой.
Например, в процессе программирования решили вы, что какой-то условно скажем светодиод будет висеть на пине D13, но в процессе разводки печатной платы обнаружили, что к D13 провести дорожку не совсем просто, зато совсем рядом оказался свободный пин D7. Вспоминать, где у вас по всему скетчу используется тринадцатый пин и менять его на седьмой неблагодарное занятие. Зато можете написать #define LED_PIN 13 и везде, где в коде встретится LED_PIN (например, digitalWrite(LED_PIN, LOW)), компилятор поменяет его на 13 и это будет равнозначно digitalWrite(13, LOW). А при необходимости использовать другой пин, достаточно его будет поменять только в одном месте - #define LED_PIN 7.
Так же и у вас, решили вы поменять пульт, а у него оказывается другая кодировка кнопок. Или кто-то еще решил повторить вашу конструкцию. Хорошо еще, если эти коды используются единожды и в одном месте, а если несколько раз и в разных местах?
Поэтому проще в начале программы определить эти коды через #define, например:
а в программе прописать:
Этим использование #define не ограничивается. В него, например, также очень удобно заворачивать относительно громоздкие конструкции, которые и в функцию нет смысла выделять, и затрудняют чтение кода.
В ардуино многие функции определены через #define, например, bitRead() прописана не иначе как
А HIGH и LOW всего лишь
В общем, не так страшен черт...
А что есть какой-то другой способ отследить нажатую клавишу не перебирая все возможные? Интересно какой.
Можно еще применить "Case", но их тоже будет столько же сколько и кнопок.
Вы же говорили, что программировали на PL/1!?!
Если использовать switch или хотя бы if с else, строк то будет столько же, но она не буде проверять ВСЕ условия, а только до первого выполнившегося. У Вас же всегда проверяются ВСЕ условяи, даже если выполнилось первое и остальные уже никак выполниться не могут.
Можно еще применить "Case", но их тоже будет столько же сколько и кнопок.
Не можно, а нужно. "case" для таких случаев и создан. И не важно, сколько там условий, главное, что не будет перебора по всему списку, даже если совпадение будет первым.
И расскажите мне лучше как обращаться с директивой "#define" в этом случае. Можно же как-то?
Что может быть проще - компилятор ищет одну комбинацию символов и заменяет ее другой.
Например, в процессе программирования решили вы, что какой-то условно скажем светодиод будет висеть на пине D13, но в процессе разводки печатной платы обнаружили, что к D13 провести дорожку не совсем просто, зато совсем рядом оказался свободный пин D7. Вспоминать, где у вас по всему скетчу используется тринадцатый пин и менять его на седьмой неблагодарное занятие. Зато можете написать #define LED_PIN 13 и везде, где в коде встретится LED_PIN (например, digitalWrite(LED_PIN, LOW)), компилятор поменяет его на 13 и это будет равнозначно digitalWrite(13, LOW). А при необходимости использовать другой пин, достаточно его будет поменять только в одном месте - #define LED_PIN 7.
Так же и у вас, решили вы поменять пульт, а у него оказывается другая кодировка кнопок. Или кто-то еще решил повторить вашу конструкцию. Хорошо еще, если эти коды используются единожды и в одном месте, а если несколько раз и в разных местах?
Поэтому проще в начале программы определить эти коды через #define, например:
а в программе прописать:
Этим использование #define не ограничивается. В него, например, также очень удобно заворачивать относительно громоздкие конструкции, которые и в функцию нет смысла выделять, и затрудняют чтение кода.
В ардуино многие функции определены через #define, например, bitRead() прописана не иначе как
А HIGH и LOW всего лишь
В общем, не так страшен черт...
По ощущениям - Вы мне разжевали, как могли, именно то чего мне не доставало и тут сокрыта бОльшая, если не вся часть всей возможной оптимизации моего скетча. Однако сказать что я так сразу и всё понял - было бы неправдой.
Большое спасибо - буду разбираться прямо сейчас...
Дело в том, что Си-подобные языки обладают, несомненно, большим функционалом, который, в свое время, был недоступен и тут у меня громадный пробел.
Это что касается среды IDE.
Что же касается самого С++ - я вообще молчу, начиная с его возможности работать с окнами, о которых во времена DOS 3.0 и МВМ (Монитор Виртуальных Машин, на ЕС-1035, ЕС-1046), никто и не мечтал!
Так что мне еще предстоит "поднять" конкретную целину в этой области...
Так же хотелось бы "победить" структурное программирование, которое широко использовалось в те времена и, признаться, было очень удобно: каждая частоиспользуемая процедура писалась отдельным файлом и при необходимости, ею могли пользоваться все программисты, которым она была нужна. Подключались такие процедуры, кажись, по тому же "INCLUDE" или просто вызывались из тела других процедур или из главной программы (Procedure Options (main)).
Теперь, я догадываюсь, структурное программирование реализовано отчасти подключением библиотек или же, как Вы указали, диретивой #define.
Еще один непонятный для меня момент в Си это - классы.
А что есть какой-то другой способ отследить нажатую клавишу не перебирая все возможные? Интересно какой.
Можно еще применить "Case", но их тоже будет столько же сколько и кнопок.
Вы же говорили, что программировали на PL/1!?!
Если использовать switch или хотя бы if с else, строк то будет столько же, но она не буде проверять ВСЕ условия, а только до первого выполнившегося. У Вас же всегда проверяются ВСЕ условяи, даже если выполнилось первое и остальные уже никак выполниться не могут.
Дело в том, что PL/1 я осваивал сам, хоть и работал проектном институте. Однако же моих наставников вполне устраивал и такой перебор по "if". Скажу даже больше - именно они мне его и подсунули тогда. А так как документация по программированию была доступна лишь на техническом английском, то, понятное дело, никто не листал эти огромные талмуды, распечатанные на перфорированных листах формата А3.
Всё что мне было доступно тогда - это распечатки чужих программ, которые я таскал домой и перелистывал лёжа в постели, силясь понять чем отличается аргумент от функции, а операнд - от оператора. Слава Богу правилом хорошего тона тогда считалось оставлять комментарии на русском языке почти по каждому шагу.
Так что каждое сказанное здесь слово в пользу оптимизации - на вес золота. Темболее что, всё что доступно, это 32кб.
Ну вот, "подправил" скетч учитывая советы бывалых:
Сэкономил 1% памяти.
Получил отображаемое на дисплее значение в переменной "pos" 17 (хотя в скетче с "if"-ами отображалось, как положено - 16).
Плюс ко всему - какие-то задержки при считывании. Тоесть при заливке старого варианта, дисплей моментально откликается на нажатую клавишу. Теперь же это происходит далеко не моментально, а другой раз и вообще не происходит.
Если убрать последний "delay()" - вообще перестаёт реагировать на пульт.
Условия по "if" не менял.
Где я допустил ошибку?
Как будет время - загляните сюда пожалуста.
Вы это мне? Или кому-то другому?
Вы это мне? Или кому-то другому?
Это я всем, кто соизволит.
Для начала:
irrecv.resume перемести выше в строку между 203 и 204 (между строками с фигурными скобками), тогда delay не так будет влиять на прием сигнала с ИК. В противном случае (если убрать delay), IRremote постоянно будет сбрасывать прием сигнала и не сможет успеть его принять.
Далее:
У тебя глобальная переменная pos, параметр pos, дело хозяйское, когда наступишь на грабли, поймешь.
pos у тебя может принимать значения от 0 до 16 включительно. Но при отображении оно отображается как (pos + 1), это так, для акцента, а не как "критика".
Мелочи:
Если уменьшить громкость до 0, а потом увеличить на шаг, то выполнится "lcd.setCursor (pos - 1, col)". Аналогично если увелчить до максимум, а потом уменьшить на шаг. Возможно это пофиг и не будет видно, но это говорит об авторе, что он на мелочи особо внимания не обращает.
Я бы заменил сравнение if (pos > -1) на if (pos >= 0), что более логично, хотя чисто математически одинаково. Сравнение с 0 более предпочтительно, потому что для этого сравнения МК достаточно проверить всего один флаг, а для сравнения с -1, придется сравнивать с константой, можешь посмотреть ассемблерный код, чтобы было понятней. Это всё мелочи, но если хочешь, используй это.
Не совсем понятно, зачем тебе три знакоместа для pos (отрицательные значения будут?). Это я про функцию bar. Хотя на время отладки, возможно это будет лучше оставить как есть.
Еще, это не обязательно, но иногда можно использовать. Я считываю код из irrecv в переменную и делаю примерно так:
Это позволит irrecv подготовиться к приему следующего кода быстрее, независимо от задержек, которые происходят дальше по коду. Например, как у тебя сейчас, пока выведешь данные на экран, irrecv у тебя не готов принимать следующий код. Минус этого приема, нельзя использовать другие члены структуры results, потому что они могут измениться в любое время. Из плюсов - не забудешь вызвать resume().
Я смотрю библиотечку IRremote (v2.0.1) подшаманили, надо будет заглянуть в исходники на досуге.
Для начала:
irrecv.resume перемести выше в строку между 203 и 204 (между строками с фигурными скобками), тогда delay не так будет влиять на прием сигнала с ИК. В противном случае (если убрать delay), IRremote постоянно будет сбрасывать прием сигнала и не сможет успеть его принять.
Это очень интересный момент, потому что я тут сейчас, как-раз, пытаюсь "заменить" в одном скетче аналоговые кнопки на управление с пульта и у меня ничего не получается! Расскажу чуть позже...
Далее:
У тебя глобальная переменная pos, параметр pos, дело хозяйское, когда наступишь на грабли, поймешь.
С этого места вкратце, но поподробнее если можно, а то я еще не готов наступать на грабли. Я так понимаю, что глобальные переменные резервируют место в памяти? Эта переменная pos стала глобальной только на период отладки.
pos у тебя может принимать значения от 0 до 16 включительно. Но при отображении оно отображается как (pos + 1), это так, для акцента, а не как "критика".
Отчего же: критика это хороший повод чему-нибудь научиться. Я просто пытаюсь восстановить давно утраченные навыки компилирования программ в голове, потому что компилятор следит только за синтаксисом, а что реально мне нужно - это уже зависит от качества поставленой задачи. Вот этим я сейчас и занимаюсь: вспоминаю, а в большинстве случаев учусь заново, как с помощью доступных средств языка, достичь цели. В общем я понял что с позицией и с отображением переменной pos не всё впорядке...
Мелочи:
Если уменьшить громкость до 0, а потом увеличить на шаг, то выполнится "lcd.setCursor (pos - 1, col)". Аналогично если увелчить до максимум, а потом уменьшить на шаг. Возможно это пофиг и не будет видно, но это говорит об авторе, что он на мелочи особо внимания не обращает.
Я бы заменил сравнение if (pos > -1) на if (pos >= 0), что более логично, хотя чисто математически одинаково. Сравнение с 0 более предпочтительно, потому что для этого сравнения МК достаточно проверить всего один флаг, а для сравнения с -1, придется сравнивать с константой, можешь посмотреть ассемблерный код, чтобы было понятней. Это всё мелочи, но если хочешь, используй это.
Интересно почему выполняется "lcd.setCursor (pos - 1, col)" в тот момент, когда я нажимаю уже совсем другую кнопку?... Напортачил с условием? При изменении кнопки все равно сначала еще раз выполняется последнее действие. Пока что я не могу понять почему. Я ставил if (pos >= 0), но потом меня сбило с толку то, что отображается все равно -1 и я вернул как было. Не думаю что ассемблер мне сейчас будет более поняте чем Си, за который я взялся первый раз в жизни, но поверю наслово.
Не совсем понятно, зачем тебе три знакоместа для pos (отрицательные значения будут?). Это я про функцию bar. Хотя на время отладки, возможно это будет лучше оставить как есть.
Да вот именно потому, что выскакивают отрицательные значения в позиции и почему это происходит - пока что загадка.
Еще, это не обязательно, но иногда можно использовать. Я считываю код из irrecv в переменную и делаю примерно так:
Это позволит irrecv подготовиться к приему следующего кода быстрее, независимо от задержек, которые происходят дальше по коду. Например, как у тебя сейчас, пока выведешь данные на экран, irrecv у тебя не готов принимать следующий код. Минус этого приема, нельзя использовать другие члены структуры results, потому что они могут измениться в любое время. Из плюсов - не забудешь вызвать resume().
На самом деле это очень важно, особенно если учитывать тайминг цикла и время срабатывания IR-приемника. С моей стороны было абсолютно неграмотно не учесть этот момент: после использования конструкции "switch-case" очевидно что програмка начала себя более свободно чувствовать и irrecv просто не успевал сделать то, что он там делает. "results" я больше нигде не планирую использовать, кроме как в считывании кодов, так что этот минус меня не коснется.
Я смотрю библиотечку IRremote (v2.0.1) подшаманили, надо будет заглянуть в исходники на досуге.
Да, они там "шаманят" так бодро, что меняют даже названия структур и файлов, ни слова не говоря об этом в комментраных скобках.
Спасибо за столь развернутый ответ и ценные советы! Сейчас буду пытаться исправить свои ошибки.
Далее:
У тебя глобальная переменная pos, параметр pos, дело хозяйское, когда наступишь на грабли, поймешь.
С этого места вкратце, но поподробнее если можно, а то я еще не готов наступать на грабли. Я так понимаю, что глобальные переменные резервируют место в памяти? Эта переменная pos стала глобальной только на период отладки.
Одинаковое название глобальной переменной и параметра функции (у тебя здесь это pos). Можно с горяча перепутать и подумать, что изменится глобальная переменная, ан нет, изменится только локальный параметр функции. Хотя никто не запрещает написать для глобальной переменной "::pos = 15;". На именование переменных, параметров нет общего стандарта, потому кто-то добавляет префиксы, кто-то еще как-то.
pos у тебя может принимать значения от 0 до 16 включительно. Но при отображении оно отображается как (pos + 1), это так, для акцента, а не как "критика".
Отчего же: критика это хороший повод чему-нибудь научиться. Я просто пытаюсь восстановить давно утраченные навыки компилирования программ в голове, потому что компилятор следит только за синтаксисом, а что реально мне нужно - это уже зависит от качества поставленой задачи. Вот этим я сейчас и занимаюсь: вспоминаю, а в большинстве случаев учусь заново, как с помощью доступных средств языка, достичь цели. В общем я понял что с позицией и с отображением переменной pos не всё впорядке...
Это я про то, что отображаться 17 может вполне.
Мелочи:
Если уменьшить громкость до 0, а потом увеличить на шаг, то выполнится "lcd.setCursor (pos - 1, col)". Аналогично если увелчить до максимум, а потом уменьшить на шаг. Возможно это пофиг и не будет видно, но это говорит об авторе, что он на мелочи особо внимания не обращает.
Я бы заменил сравнение if (pos > -1) на if (pos >= 0), что более логично, хотя чисто математически одинаково. Сравнение с 0 более предпочтительно, потому что для этого сравнения МК достаточно проверить всего один флаг, а для сравнения с -1, придется сравнивать с константой, можешь посмотреть ассемблерный код, чтобы было понятней. Это всё мелочи, но если хочешь, используй это.
Интересно почему выполняется "lcd.setCursor (pos - 1, col)" в тот момент, когда я нажимаю уже совсем другую кнопку?... Напортачил с условием? При изменении кнопки все равно сначала еще раз выполняется последнее действие. Пока что я не могу понять почему. Я ставил if (pos >= 0), но потом меня сбило с толку то, что отображается все равно -1 и я вернул как было. Не думаю что ассемблер мне сейчас будет более поняте чем Си, за который я взялся первый раз в жизни, но поверю наслово.
Про "lcd.setCursor (pos - 1, col)" не совсем понял. Это по моему объяснению? Так это по алгоритму так запрограммировано. Снизили громкость, pos = 0, затем нажали VolumeUp и выполнился другой кусок с "lcd.setCursor (pos - 1, col)". Для этой строки нужно добавить проверку, что если pos == 0, то чистить нечего. Аналогично и для "lcd.setCursor (pos + 1, col)".
Еще, это не обязательно, но иногда можно использовать. Я считываю код из irrecv в переменную и делаю примерно так:
Это позволит irrecv подготовиться к приему следующего кода быстрее, независимо от задержек, которые происходят дальше по коду. Например, как у тебя сейчас, пока выведешь данные на экран, irrecv у тебя не готов принимать следующий код. Минус этого приема, нельзя использовать другие члены структуры results, потому что они могут измениться в любое время. Из плюсов - не забудешь вызвать resume().
На самом деле это очень важно, особенно если учитывать тайминг цикла и время срабатывания IR-приемника. С моей стороны было абсолютно неграмотно не учесть этот момент: после использования конструкции "switch-case" очевидно что програмка начала себя более свободно чувствовать и irrecv просто не успевал сделать то, что он там делает. "results" я больше нигде не планирую использовать, кроме как в считывании кодов, так что этот минус меня не коснется.
На счет "неграмотно" - это совсем не обязательно, тут очень много факторов. Для короткого периода между анализом results.value и irrecv.resume() можно не париться, а если подольше, тогда может и стоит задуматься. Зависит от обстоятельств.
120
case
VolUp:
121
key_dsp(
"VolUp"
);
122
lcd.setCursor (pos - 1, col);
123
lcd.write(
" "
);
124
bar(pos, col);
125
if
(pos <16) {pos++;}
126
break
;
МОжет я ошибаюсь, но строка 125 должна идти после 121. Ход мысли такой - если нажата кнопка то следует изменить pos , а затем уже отобразить результат новой позиции бегунка на экране.
Ну да. Так и должно было быть. Только не песле 121, а после 124. Функция "
key_dsp
" только отображает название нажатой клавиши, а вот "bar(pos, col);
" - как раз и двигает бегунок на новую позицию... Странно, почему я этого не заметил... А вот еще вопрос: можно ли в "case" указывать несколько условий? Ну вот мне надо бы еще туда как-то нижний "if" приделать.Одинаковое название глобальной переменной и параметра функции (у тебя здесь это pos). Можно с горяча перепутать и подумать, что изменится глобальная переменная, ан нет, изменится только локальный параметр функции. Хотя никто не запрещает написать для глобальной переменной "::pos = 15;". На именование переменных, параметров нет общего стандарта, потому кто-то добавляет префиксы, кто-то еще как-то.
Так дело в том, что значение "pos" нужно мне и для передвижения бегунка и для отображения в целях отладки. Ну и, естественно, я хотел бы там видеть тоже что и есть на самом деле.
А оно так и делает. Ниже нуля не идет, но 17 - показывает. Хотя в первом варианте скетча с "if"-ами было всё нормально. В смысле: 17 не отображалось, а в остальном - такой же бардак и был.
Про "lcd.setCursor (pos - 1, col)" не совсем понял. Это по моему объяснению? Так это по алгоритму так запрограммировано. Снизили громкость, pos = 0, затем нажали VolumeUp и выполнился другой кусок с "lcd.setCursor (pos - 1, col)". Для этой строки нужно добавить проверку, что если pos == 0, то чистить нечего. Аналогично и для "lcd.setCursor (pos + 1, col)".
На счет "неграмотно" - это совсем не обязательно, тут очень много факторов. Для короткого периода между анализом results.value и irrecv.resume() можно не париться, а если подольше, тогда может и стоит задуматься. Зависит от обстоятельств.
Ничего не понял, но тут еще есть над чем подумать...
Если я Вас правильно понял то несколько условий можно описать так ... switch (Color){ case Red: case Orange: case Yellow: // Теплая гамма; break; case Green: case Blue: case Guan: case Magenta: // Холодная гамма; break; default: // Цвет не из радуги }
код взят из книги по с++
Наверно как так....
Если я Вас правильно понял то несколько условий можно описать так ... switch (Color){ case Red: case Orange: case Yellow: // Теплая гамма; break; case Green: case Blue: case Guan: case Magenta: // Холодная гамма; break; default: // Цвет не из радуги }
код взят из книги по с++
Спасибо. Буду пробовать...
case VolUp:
key_dsp("VolUp");
if (pos <16) {
pos++;
lcd.setCursor (pos - 1, col);
lcd.write(" ");
bar(pos, col);
}
break;
Наверно как так....
Да, только меня тут разнесли за "if" и я попробую сейчас оба варианта и с "case" и с "if" ...
Наверно как так....
Вот при таком варианте происходит следующее: дёргание в обратную сторону бегунка пропало, но добавилась проблема с кнопокой "VolUp" - бегунок убегает за край экрана как и раньше, но теперь после 17 "pos" затирается, то есть - не отображается. Тоже самое происходит и с "VоlDown", с той разницей что только затирается всё, что меньше нуля. Но бегунок остаётся на первой позиции (на первой на дисплее, адрес ее в скетче - 0).
Вот этот участок, где я только что менял:
Странное дело... Если по "VolUp" в "if" поставить вот так:
, то бегунок продолжает улетать за правую область дисплея, но позиция теперь бывает еще и 18, перед тем как затереться...
081
void
bar(
int
pos,
int
col)
082
{
083
084
lcd.setCursor (13, 0);
085
lcd.print(
" "
);
086
lcd.setCursor (13, 0);
087
lcd.print(pos + 1);
088
089
lcd.setCursor (pos, col);
090
lcd.write(
"\1"
);
091
092
093
}
Прежде следует исправить строку 087 на - lcd.print(pos);
это уберет значение 17.
13
case
VolDown:
14
key_dsp(
"VolDown"
);
15
if
(pos>=0 ) {
16
pos--;
17
lcd.setCursor (pos+1, col);
18
lcd.write(
" "
);
19
bar(pos, col);
20
}
21
break
;
22
тут в 15 строке условие if (pos>0) {
так позиция не будет меньше 0
В целях отладки я спрятал всё под "if", что бы отображалась реальная позиция:
Теперь у меня "pos" пишет и -1 и 17 и не затирается, но бегунок улетает вправо с дисплея совсем....
Вот видео как ведет себя arduino с текущим кодом : Ссылка
не затирается потому, что процедура key_dsp() теперь в рамках if. т.к. эта процедура только отображает нажатую кнопку то, как раз в целях отладки нужно держать за скобками if. что бы не было -1 и 17 нужно убрать в строчках 120 и 130 знак '='
не затирается потому, что процедура key_dsp() теперь в рамках if. т.к. эта процедура только отображает нажатую кнопку то, как раз в целях отладки нужно держать за скобками if. что бы не было -1 и 17 нужно убрать в строчках 120 и 130 знак '='
Вынес перед "if", убрал знаки равно.
Затирается теперь последнее значение, которое больше 16, но бегунок все равно удирает с экрана. Раньше, до вынесения за "if" предельные значения 0 и 17 не затирались. Больше - ничего не изменилось.
Вроде бы и все правильно, но бегунок все равно убегает на позицию 17.
Такое впечатление что условие не срабатывает.
----------------------- небольшое отступление -----------------------
Дело в том, что пульт, в конце каждой серии кода, посылает еще один код, очевидно комманду завершения передачи, на которую "case" тоже почему-то реагирует! И поэтому иногда получаются двойные скачки бегунка. И конечно же это сказывается в крайних положениях, когда позиция принимает значения, не входящие в диапазон допустимых: между 0 и 16.
Я думаю проблема тут.
А может проблема в том, что нет 16 позиции, первая позиция на жки равна 0 а крайняя справа 15. Попробуйте исправить на следующее ...
А может проблема в том, что нет 16 позиции, первая позиция на жки равна 0 а крайняя справа 15. Попробуйте исправить на следующее ...
Если поставить до 15, то как раз всё как нужно. Только 0 и 15 затираются, что тоже не совпадает с конечной целью. Надо вынести ту фунцчию за "if" опять.
Однако мне не даёт покоя комманда завершения передачи. Надо ее либо отловить и исключить или поменять пульт. Причем если внести ее код в исключение по "!=" в любой "if" - это ничего не даёт. Хотя если раскомментить отладочный принт - пишется определенное число, которое потом никак не помогает.
Странно это всё...
Сейчас начало функции с "case" выглядит так:
Кстати еще одна странность: как видно из текста скетча, я там проверяю на все клавиши, но действия выполняются только за первыми двумя. Так вот интересно что происходит: если нажимать "VolUp", который двигает бегунок вправо, бросить кнопку и нажать любую из незадействованных, то отображается название кнопки и бегунок прыгает на 1 позицию вправо. Если до этого нажимать влево, то прыгает влево. Получается что где-то проскакивает наращивание переменной "pos", и вполне возможно что именно потому что она глобальная.
У меня не хватает таланта обойтись без ее "глобализации"...
------------------------------------------
Хватило таланта и я отвязал переменную "pos", заменив ее на "_pos" в "#define". Это ничего не дало.
Такое впечатление что переменная наращивается 1 раз после события в "if (irrecv.decode(&results))". Это я уже сам не решу.
Последняя редакция скетча:
если это действительно команда завершения передачи, о её нужно ждать и только после этого обрабатывать нажатую кнопку.
следовательно код будет примерно таким -
но наверно понадобится еще одна переменная которая будет хранить код кнопки пока не поступит код завершения.
что бы не сомневаться в ом, кака переменная используется - они должны отличаться в имени.
Например так.
081
void bar(int _pos, int col)
082
{
083
084
lcd.setCursor (13, 0);
085
lcd.print(
" "
);
086
lcd.setCursor (13, 0);
087
lcd.print(_pos);
088
lcd.setCursor (_pos, col);
089
lcd.write(
"\1"
);
090
091
092
}
093
если это действительно команда завершения передачи, о её нужно ждать и только после этого обрабатывать нажатую кнопку.
следовательно код будет примерно таким -
но наверно понадобится еще одна переменная которая будет хранить код кнопки пока не поступит код завершения.
Как показали исследования, код завершения, почему-то не посылается в конце серий именно этих кнопок. Однако же выяснилось другая, не менее неприятная ситуация, описанная выше.
что бы не сомневаться в ом, кака переменная используется - они должны отличаться в имени.
Например так.
Я точно так и сделал. Еще и "col" на всякий случай развязал. См код выше.
С кодом завершения я даже не знаю что делать. Дело не в нём. "case" один раз реагирует на любую кнопку.
Вот как ведет себя бегунок на текущий момент: Видео
Вот тут, думаю, может быть проблемка..
114
int rv = results.value;
115
if
(irrecv.decode(&results))
// Если данные пришли
116
{
117
// lcd.setCursor (0, 1);
118
// lcd.print (results.value);
119
строка 114 должна быть после 116 т.к. если данные не пришли то и загружать в rv нечего.
Вот тут, думаю, может быть проблемка..
строка 114 должна быть после 116 т.к. если данные не пришли то и загружать в rv нечего.
Переменная "
rv
" получит значение и до "if
(irrecv.decode(&results))
", хотя я могу и ошибаться. Я ее раньше и ставил внутри этого "if". Но видимых изменений не обнаружил. Сейчас попробую перенести опять. Все остальные проблемы если и не ушли, то стали не так заметны...Да, после переноса той строки внутрь - перестало дёргать бегунок после нажатия других кнопок.Однако осталась теперь, явно заметная, проблема: бегунок может не двигаться на двойное и даже тройное нажатие кнопки (все равно какой - "VolUp" или "VolDown"), но потом перескакивает сразу на количество позиций равное числу нажатий. Даже не перескакивает, а быстро перебегает. Как буд-то клавиатура подвисла и потом буквы одна за другой спешат занять свои места.
Вот что еще, вызывает подозрение тип results.value; - Unsigned long используется для хранения положительных целых чисел в диапазоне от 0 до 4,294,967,295 и занимает 32 бита (4 байта) в памяти, а тип rv - int целое число, занимает 2 байта памяти, и может хранить числа от -32 768 до 32 767. может стоит преобразовывать так int rv = Int(results.value);
Вот что еще, вызывает подозрение тип results.value; - Unsigned long используется для хранения положительных целых чисел в диапазоне от 0 до 4,294,967,295 и занимает 32 бита (4 байта) в памяти, а тип rv - int целое число, занимает 2 байта памяти, и может хранить числа от -32 768 до 32 767. может стоит преобразовывать так int rv = Int(results.value);
Сейчас попробую, хотя не совсем понимаю что это даст.
-------------------------
Никаких изменений не произошло. Но в общем и целом, конструкцию, на данном этапе, можно считать рабочей.
Дело в том, что я предполагал кнопками от пульта управлять кучей меню на более большем дисплее. Однако в силу специфики работы этой "схемы", затея оказалась нежизнеспособной...
Хотя я видел как-то в инете - парень делал игру с управлением от пульта. Надо будет повнимательней изучить его скетч с учётом проделанной нами работы :) .
Спасибо за помощь! Пойду тот скетч поищу.
Посмотрел видео - кажется работает нормально, только былонесколько проскоков, но думаю может быстро были нажаты кнопки.
Посмотрел видео - кажется работает нормально, только былонесколько проскоков, но думаю может быстро были нажаты кнопки.
Дребезг кнопок вполне возможен. Тем более что это кнопки громкости, а они всегда страдают больше остальных. Надо попробовать поуправлять другими кнопками. Например цифровыми - их вообще никто никогда не трогает.
-----------------------
Ничего не дало, хотя кнопки работают более точно. Зато стал явно бросаться в глаза такой момент: при кратковременном нажатии на кнопку, бегунок каждый раз проскаивает сразу на 2 позиции.