LCD + энкодер
- Войдите на сайт для отправки комментариев
Пнд, 20/10/2014 - 08:51
Приветствую всех. Возникла проблема.
Подключаю энкодер (KY-040) и экранчик 20*4. По отдельности все отлично работает. Экран все показывает, энкодер крутится и значения меняются. Но как только я объединяю два устройства в одном скетче - проблема. Энкодер начинает пропускать шаги, причем прилично. Понимаю, что как-то связано с прерываниями, но что сделать - не понимаю. Подскажите, пожалуйста.
Вот код:
//#include <OneWire.h> // Библиотека для Dallas 1-wire //#include <DallasTemperature.h> // Библиотека для DS18B20 #include <Wire.h> // Библиотека для I2C #include <LiquidCrystal_I2C.h> // Библиотека для LCD LiquidCrystal_I2C lcd(0x27,2,4); // Адрес модуля LCD //#define ONE_WIRE_BUS 10 //OneWire oneWire(ONE_WIRE_BUS); //DallasTemperature sensors(&oneWire); // Используем энкодер с кнопкой enum PinAssignments { encoderPinA = 2, // Вращение вправо encoderPinB = 3, // Вращение влево clearButton = 8 // Кнопка }; volatile unsigned int encoderPos = 0; // Счетчик для энкодера unsigned int lastReportedPos = 1; // Предыдущее значение энкодера для сравнения static boolean rotating=false; // Антидребезг // Переменные направления вращения boolean A_set = false; boolean B_set = false; void setup() { pinMode(encoderPinA, INPUT_PULLUP); // Режим порта pinMode(encoderPinB, INPUT_PULLUP); pinMode(clearButton, INPUT_PULLUP); // Прерывания attachInterrupt(0, doEncoderA, CHANGE); attachInterrupt(1, doEncoderB, CHANGE); // Инициализируем LCD lcd.init(); lcd.backlight(); lcd.home (); Serial.begin(9600); // Монитор порта } // Основной цикл void loop() { rotating = true; // Инициализируем "антидребезг" // Сравниваем состояние энкодера с предыдущим и если есть изменение - печатаем его if (lastReportedPos != encoderPos) { Serial.print("Index:"); Serial.println(encoderPos, DEC); lastReportedPos = encoderPos; } // Обнуляем значение переменной по нажатию кнопки if (digitalRead(clearButton) == LOW ) { encoderPos = 0; } // Выводим значение переменной на LCD lcd.setCursor ( 0, 0 ); lcd.print ("Index: "); lcd.print (encoderPos); } // Прерывание 1 void doEncoderA(){ // Включаем "антидребезг" if ( rotating ) delay (10); // Проверяем значение порта if( digitalRead(encoderPinA) != A_set ) { // debounce once more A_set = !A_set; // Узнаем направление вращения if ( A_set && !B_set ) encoderPos += 1; rotating = false; // выключаем "антидребезг" } } // Все то же самое для прерывания 2 void doEncoderB(){ if ( rotating ) delay (1); if( digitalRead(encoderPinB) != B_set ) { B_set = !B_set; if( B_set && !A_set ) encoderPos -= 1; rotating = false; } }
Заранее спасибо.
Попробуй CyberLib использовать, чтобы от медленной digitalRead избавиться.
дело не в скорости работы digitalRead. Дело скорее в delay(10)... ИМХО, лучше аппаратно антидребезг для энкодера сделать...
https://www.pjrc.com/teensy/td_libs_Encoder.html - посмотрите, там очень неплохая библиотечка была.
А как именно у вас пропуски происходят ? быстро крутите, а знечение не меняется ?
Аппаратный пока нет возможности сделать, но про данный метод в курсе, спасибо.
А пропуски: Кручу на один "щелчок", а значение меняется на 5.. или на 3.. или на -2..
Вообще, если вставить вывод на экран внутрь проверки изменения сигнала, то все отлично. Но мне еще температуру постоянно мониторить, поэтому не совсем поможет.
К сожалению не знаю точно, какая у вас задача, но если вам необходимо на 1 шелчек энкодера изменять значение на 1 еденицу, то:
1) прерывание на переход из 0 в 1 для выхода А
2) в прерывании делайте антидребезг, после этого читайте выход Б (Б можно уже без антидребезга, так как он 100% уже стабилен). Если Б = 1 то увеличте переменную энкодера, если Б = 0 то уменьшите.
Задача банальна. Меню с использованием энкодера с кнопкой и 4-х строчного LCD
Упростите код как я писал, должно взлететь...
В общем я провери код. У ТС не срабатывает антидребезг.
Рабочий упрощенный код (протестировано). Я понимаю, что delay() в прерывании не очень желателен, однако это самый простой способ. главное прарывание на момент delay() отключить.
Не работает этот код, к сожалению. Так и проскакивает значения. 0-2-4-6-7-9-11-13-15 и т.д. Я думаю проблема именно в том, что вывод на экран тоже использует прерывания.
код точно рабочий, что ваш что мой. Только у меня дисплей напрямую подключен.
в I2C прерывания точно используются. Очень похоже что у вас срабатывает оба прерывания по фронту (2 и 3 нога). Попробуйте явно отключить прерывание на 2 ноге (detachInterrupt(0)), и в обработчике прерываний явно отключайте и включаете прерывания на 3 ноге. (detachInterrupt(1); и attachInterrupt(1, encoder, RISING);). Задержку до 10 поднимите.
Увы...
А может у вас энкодер 2 перехода в + на 1 клик дает ?
Вот рабочий код, только мой дисплей 16х2. Для 20х4 заменить lcd.begin (16,2); на lcd.begin (20,4);
Правда обработка значений энкодера считает по 2 значения , но я в это не лез.
А вот leshak предложил работу с энкодером - четко показывает
Вот ещё в loop() небольшое изменение - стираем на дисплее старые значения
Тогда проще через sprintf пропустить и всё время буфер выводить.
вот рабочий кусок кода опроса 2-ух энкодеров (взято из рабочего проэкта)
Ты идиот? За такой код надо пальцы ломать.
Жёстко ответил...
Ты идиот? За такой код надо пальцы ломать.
Прокоментируй, пожалуйста.
А что тут комментировать?
Оп начал делать всё асинхронно через прерывания, а этот идиот предлагает вместо этого часто опрашивать порты, авось там чего повится и авось попадем в импульс. Любой минимальный дополнительный функционал приведет к неработоспособности этого говнокода.
Экий ты кровожадный...
Ты идиот? За такой код надо пальцы ломать.
Из-за таких как ты муд_____ков, у нас вся Рооссия в жопе каждый прыщ начинает понты корячить,а твои ответы равносильно таму "Как построить самолет? Сделать крылья машине!" а потом стоять и кричать что никто ничего не умеет делать!
Вот код но есть небольшая проблема на лсд иногда путаются показания,а паралельно включеный ком порт все в идеале,
мож че посоветуете
и тысячах путаются а потом сами становятся как на ком порту.
На лсд остаются иногда последние цыфры а показывает правельно
нашол проблему надо очистить от старых показаний lcd.print(" ")
Ой! А кто это там со стороны параши тяфкает?
Да это же димсобакансемдесятвосемь!
А под чем это он? Под лсд конечно! Да он код научился писать! Только грамоте разучился при этом. Какая незадача! А еще этот говнокодер в полите разбирается!
Только код у него всё равно говно, хотя воняет уже меньше.
Сдаётся мне, джентльмены, это был комплимент...
Ты бы вафлю свою прикрыл, а то кишочки простудиш. Я больше чем уверен ты в жизни ни кто,и зовут тебя ни как.
Ты домашний,подьюбешный,саплежуй.
В реальной жизни такие как ты прыщавые хуесосы которые дрожат на остановках'
Слив защитан. Следущий.
Radjah ты то чего до грубости дошел?
И еще вопросик нужно ли делать подтяжку к земле на энкодерах оптических?
Шо за взаимные оскорбления. Знает-не знает, умеет-не умеет - не причина паскудить форум.
Согласен.он сам зацепил
Ну если кто то и нахамил - можно и не ответить. Это единственный форум из всех, где я сижу, который без мата и скотства. Жалко будет, если и он опаскудится. Есть простая жизненая мудрость -БЕРЕГИ ТО ЧТО ЕСТЬ. ПОТЕРЯТЬ МОЖНО - ВЕРНУТЬ - НЕТ! Это касается и женщин и общения.
Прошу у всех извинения!