Ну вот спрашивается, какого фига? Где обещанная стабильность?
Прямое чтение из порта - та же картина. Более того даже если я буду делать digitalRead(PIN_A) - и нули и единицы в вводе. Несмотря на то что RISING при аттаче. И прямое чтение из порта - тоже не помогает.
На один щелчек выскакивает 1 (или ноль), потом, через три секунды A, потом, иногда(!) опять 1 (или 0). Хотя к тому времени даже рука с энкодера убрана и спрятана за спину. То есть ни о каком "восходящем фронте" не может быть речи. Вообще не может быть сработки.
Как будто при attachInterrupt оно вспомнило о фронте которые были во время детача.
То есть сделать там "ругулятор громкости" - можно, а вот ловить команды типа "сделали 3 щелчка" - уже нет :( Задача "когда нам каждый тик и мил и дорог" - пока не решена :(
Пишу в 3-й раз :( Что-то фокс сбрасывает, пишу из оперы...
От "подшумливания" так и не смог избавиться. Пытался вставить задержку в начало прерывания на _delay_ns() - она без прерываний, но не помогло. Вот только не пробовал бороться "железными" методами. Может 2 конденсатора по 0.1 мкФ спасут отца русской демократии? Под рукой не оказалось - непроверил.
А тем, кому нужно ловить каждый шаг, все равно "контактные" энкодеры не помогут, им нужны безконтактные, а там дребезга не будет. Там другие подводные камни.
Вот что еще интересно, у меня энкодер заявлен как 24 шага на оборот, по механике дает 24 "щелчка", а считает при этом до 96... Может имеет смысл считать целыми сигнатурами (а-ля синхронизация по началу сигнатуры) или четверть-шагами? Или у меня уже крыша рассинхронизировалась?
Вот только не пробовал бороться "железными" методами. Может 2 конденсатора по 0.1 мкФ спасут отца русской демократии? Под рукой не оказалось - непроверил.
Та же история. "Железно" - религия не позволяет (по идее то что делает железо должно и програмно быть возможно) и "нет под рукой.
AlexFisher пишет:
А тем, кому нужно ловить каждый шаг, все равно "контактные" энкодеры не помогут, им нужны безконтактные, а там дребезга не будет. Там другие подводные камни.
Не хочется в это верить. Бесконтактные - стоят кучеряво. Если для "разово" это еще покатит, то для "серии" это уже ОЧЕНЬ ОЩУТИМО. Поэтому и хочется научится стабильно работать с самыми дешевыми.
Да и фиг с ним дребезгом при смене. Но ведь, по идее, когда идет фронт A, при этом B должен "стоять как влитой". Уже закончить все свои "трепыхания" к тому времени. Получает он дребезжит вообще при любом механическом действии, а не только когда собрался менятся?
AlexFisher пишет:
Вот что еще интересно, у меня энкодер заявлен как 24 шага на оборот, по механике дает 24 "щелчка", а считает при этом до 96...
Да нет. Это как раз и есть "самый обычный энкодер". На один шаг выдает 4-ре импульса (можно еще и "полущелчок ловить").
Вообщем-то и было в мыслях, следующих шагом смотреть на вот эту серии из 4-рех. Смотреть "кого из них больше". Ну и считать их все "одним счелчком". Правда нужно, опя-ть таки из за шума, не всегда на получается "счелчек 4-ре". Так что нужно,опять-таки, как-то по времени разделять "на серии", но при быстром вращении, не уверен что "это получится".
Та же история. "Железно" - религия не позволяет (по идее то что делает железо должно и програмно быть возможно) и "нет под рукой.
Мне как раз религия позволяет - я больше электронщик, чем программист, мне не позволяет лень :) Завтра обязательно попробую. Если не забуду кондерчиков из дома прихватить :)
Да и фиг с ним дребезгом при смене. Но ведь, по идее, когда идет фронт A, при этом B должен "стоять как влитой". Уже закончить все свои "трепыхания" к тому времени. Получает он дребезжит вообще при любом механическом действии, а не только когда собрался менятся?
Вот так выглядит механический энкодер изнутри (стырено с robocraft'a):
скольжение пружинных контактов (левая половинка) по металлическим секторам (правая половинка) с определенной долей вероятности приводит к потере контакта из-за шероховатости поверхностей. Отсюда и шум.
Осцил дома... ардуина на работе... попробую в кучу собрать :)
Ну достаточно познакомить энкодер и осцил. Дуина - не обязательно.
Да и вообще "не обязательно", ваша картинка уже дала ответ.
Хотя вообщем-то, после всех мук, я уже в голове себе именно такую картину и нарисовал. Другого объяснения "как такое может быть" - я не видел. Хотел подтверждения. Вроде получил.
Значит, таки нужно либо ставить кондеры, либо изображать их програмно. Причем на обоих пинах.
Только наверное не через
> _delay_ns()
Что-то я не уверен что она "без прерываний". Неужели эна "тупо крутит цикл"? Точно на счетчики времени не смотрит?
К тому же "тупой делей" скорее всего не поможет. Он предпологает что "пошумело и успокоилось". А у нас "шумит все время".
_delay_ns() тупо крутит цикл. Количество интерраций расчитывает компиллятор по тактовой процессора. Именно поэтому аргументом функции может быть только константа. _delay_ms() уже вызывает в цикле _delay_ns().
По поводу механики энкодера - я с ней знаком. "плохой контакт" ползунков лечится 2-мя способами:
Больший ток за счет внешней подтяжки (ом эдак 100-200)
RC-фильтр (в "минимальном" варианте - просто конденсатор параллельно энкодеру).
Хотя вообще не факт что "не шумят". В районе своего нуля (когда сопротивление 0) вполне могут и шуметь так же.
Да и банално, в потенциометре площадь контакта может быть на порядок больше.
Еще как шумят!!! Особенно, когда крутишь ручку! Особенно советсткие! Два раза особенно китайские!!!. Для качественного усилка приходится покупать регуляторы (переменные резистроры) фирмы Alps за 50$
PS Извините, но давайте про резисторы не будем, оффтоп, все же. Итак уходили в программирование сильно...
В "теории", на прерываниях вообще все очень просто.
Повесили канал A, на пин 2. Сделали attachInterupt(0,pinAHandler,RISING);
Красные стрелки это момент когда вызовется функция pinAHandler, в зависимости от того в какую сторону крутим ручку.
В самом функции pinAHandler прочитали пин на который подсоеденан канал B. Если там 1 - значит щелкнули против часовой, если 0 - значит по часовой (ну или наоборот, смотря как подключили A,B).
Ну в теории "все просто", на практике - сложней (но тоже просто когда знаешь где собака зарыта:)
Купить осцил - жаба давить. У знакомых - через пол города ехать.
В итоге собрал на дуинке простейшик Logic Analizer и "посмотрел че-там".
Ожидал увидеть шум на обоих каналах просто в момент любого движения.
Но все оказалось проще.
Шум позникает только в момент переключения состояния канала. Когда он "установился" - стоит как влитой.
То есть при смене канала A - все-таки можно уверенно смотреть на B. К тому моменту у него никакого дребезга нет и в помине.
"Собака" была, все-таки в определении смены канала А. Неправильно выбран момент когда определяется "он поменялся".
Так как у нас есть шум "при смене", то вот на этой картинке красные стерочки, наш триггер на FRONT может сработать на любой из этих красных стрелок, вне зависимости от того куда мы крутим. Как повезет. Не будет шума при "падении в ноль" - поймаем RISING в правильный момент (и правильно поймем направление глядя на B, четко в соотвествии теории), "зашумит"" при переходе канала в ноль - все, мы ошиблись в направлении. Глядим на B в неправильное время.
Вот и получается, что "по теории" - без раницы на что вешать обработчик, на RISING или FALLING, а в реальности - нужно на FALLING :) Первое же падение A в ноль - четко означет "щелчок", а последующие - это шум.
Вот мой скетч из #55. Отличие только RISING->FALLING
#define PIN_A 2
#define PIN_B 3
volatile unsigned long enabledA_time=0;
volatile bool fl=false; // флаг что нужно вывести
volatile bool value_b=0;
void setup(){
Serial.begin(57600);
digitalWrite(PIN_A,HIGH);
digitalWrite(PIN_B,HIGH);
attachInterrupt(0,handler_a,FALLING); // одно слово разницы, а сколько крови попортило :)
Serial.println("Ready");
}
void handler_a(){
if(enabledA_time<millis()){
value_b=digitalRead(PIN_B);
fl=true;
enabledA_time=millis()+500;// уж включили антидребезг так включили
}
}
void loop(){
if(fl){
Serial.print(value_b);
Serial.print(" ");
fl=false;
}
}
Но, в резульатате. При неспешных щелчках (дебоунс-то 500 милисекунд) - в одном направлении ошибок вообще 0, в другом 2-3% (думаю и это задавлю). При уменьшении дебоунса - ошибки начинают "появлятся", но теперь есть идеи "как это победить" :) И снизить время дебоунса до юзабельных значений.
P.S. Вообщем смотреть нужно когда красная стелочка "вниз", а не "вверх" как на картинке.
Фух. Я опять чуствую себя полноценным девелопером. :)
Победил!!!
Четко ловится каждый "щелчек". Без ошибок направления, без пропусков (даже если "крутить" достаточно быстры).
Общий подход такой
1. На нисходящем фронте A, смотрим состояние B и запоминаем его. А так же время "когда это произошло" (падение A)
2. На восходящем фронте A, смотрим сколько времени прошло с пукнта 1. Если меньше определенного значения (5 msec опытно подобрал) - игнорируем, если больше - меняем счетчик энкодра. Направление определяем по состоянию канала B, запомненного на пункте 1.
#define PIN_A 2
#define PIN_B 3
#define PULSE_PIN_LEN 5 // минимальная длинна импульса в миллесекундах на которую мы обращаем внимание
volatile unsigned long failingTime=0;
volatile bool fl=false; // флаг что нужно вывести
volatile bool value_b=0;
volatile byte prevA=0;
volatile int encValue=0;
volatile unsigned long pulseLen=0;
void setup(){
Serial.begin(57600);
digitalWrite(PIN_A,HIGH);
digitalWrite(PIN_B,HIGH);
attachInterrupt(0,handler_a,CHANGE);
Serial.println("Ready");
}
void handler_a(){
// byte portValue=PINE ; // для меги
// byte A= (portValue & B10000)>0 ;// digitalRead(PIN_A); PE4
byte A=digitalRead(PIN_A);
if(!fl){ // пока не отчитались ничего больше не делаем
if(prevA && !A){ // фронт упал
//value_b=(portValue & B100000)>0; // digitalRead(PIN_B); PE5 // определили направление, но пока только "запомнили его"
value_b=digitalRead(PIN_B); // определили направление, но пока только "запомнили его"
failingTime=millis(); // и запомнили когда мы "упали в ноль", начали отсчет длины импульса
}
if(!prevA && A && failingTime){ // восходящий фронт и мы в режиме "отсчет времени импульса
pulseLen=millis()-failingTime;
if( pulseLen>PULSE_PIN_LEN){ // импульс бы достаточно длинный что-бы поверить тому что мы прочитали в его начале
if(value_b)encValue++; else encValue--;
fl=true; // включаем пометку что нужно отчитатся в Serial
}
failingTime=0; // больше не ведем осчет времени импульса
}
}
prevA=A;
}
void loop(){
if(fl){
Serial.print("Enc=");Serial.print(encValue);
Serial.print(",Dir="); Serial.print(value_b?"R":"L"); // выводим направление
Serial.print(",PulseLen=");Serial.println(pulseLen); // выводим длину импульса (удобно для первоначальной настройки)
fl=false;
}
}
Выдает (сделал 10-ть щелчков по часовой и 10-ть против):
Подход интересен хотя бы тем, что используется только одно прерывание (вторая нога может висеть где угодно). В перспективе - легко подключить 2 энкодера. Сохраню себе - потом помучаю (интересно, как оно будет работать без ожидания вывода в сериал... и подумаю, как на этом принципе повесить 3 энкодера :)
"совпадает с тем, что чувствует рука"... не гуд, очень хочется ловить все 96 состояний, а не 24.
Хочу собрать тестовую установку из шаговика и энкодера :) Потетсить разные подходы :) Где бы время взять...
Подход интересен хотя бы тем, что используется только одно прерывание (вторая нога может висеть где угодно). В перспективе - легко подключить 2 энкодера.
Да. В принципе вообще ничто не мешает не расходовать дефицитное внешние прерывание. Взять Pin Change interrupts. Один черт front/down определяем програмно.
А можно, все-таки от таймера. Просто регулярно смотреть на пины. Я когда мерял-смотрел что там происходит, то на частоте опроса ниже 10 килогерц - никаких шумов уже не видно было вообще. Сигналы "чистые и пушистые". Тогда можно будет еще больше упростить логику. И "на каких пинах" - вообще не важно станет (правда таймер займем и кусочек процессорного времени)
AlexFisher пишет:
"совпадает с тем, что чувствует рука"... не гуд, очень хочется ловить все 96 состояний, а не 24.
Ну у меня цель была именно "ручная крутилка". Как устройство ввода "ввести нужное количество тиков". А "сколько состояний" - ну это уже от энкодера зависит :) Или вы "полу-щелчки" ловить хотите? Все-таки длина самих импульсов намного меньше чем интервалы между ними. Там "дребезг" уже трудней будет отфильтровать.
Но возможно это сильно зависит от энкодера. У меня "щелчковый", а "без щелчковый" может быть и более "равномерную картину дает". Тогда там и половинные состояния и имеет смысл и легче ловить.
AlexFisher пишет:
Хочу собрать тестовую установку из шаговика и энкодера :) Потетсить разные подходы :) Где бы время взять...
Как тестовая - да. Как "следить за мотором" - механический быстро сотрется. Тут явно оптический нужен. А с ним и танцев этих, с дребезгом, не будет. Так что IMHO все-таки "чувствует рука" - это гуд. Так как именно только для руки и имеет смысл это использовать.
Как тестовая - да. Как "следить за мотором" - механический быстро сотрется. Тут явно оптический нужен. А с ним и танцев этих, с дребезгом, не будет. Так что IMHO все-таки "чувствует рука" - это гуд. Так как именно только для руки и имеет смысл это использовать.
Согласен. Но установку все равно сделаю - со сменным энкодером - с оптическими тоже нужно поэкспериментировать (я имею ввиду самодельные энкодеры).
Я конечно не дорос до AlexFisher и leshak, т.к. потестил последний код leshak-а то он всеже не стабилен, в одну сторону считает нормально, а в обратную проскакивают ошибки (вместо вычитания еденицы проскакивает прибавление) к томуже в одну сторону считает на один меньше чем в другую, вот мой вариант без millis:
плюсы: работает без привязки ко времени(все зависит теперь от скорости работы МК и кода), в обе стороны считает одинаково, можнонавернобез внутренней подтяжки,
этот подход родил когда мучился с длительным нажатием (жмакнули кнопку, переменная приравнялась к millis, если в заданном промежутке времени кнопку отпустили то сбрасываем вход в длительное нажатие, в противном случае можно последовательно нажимать копку и это прокатит за длительное нажатие)
не комментировал, думаю все просто и понятно, просто сбрасываем все проверочные состояния когда оба пина в лоу, кому нужно и прерывания прикрутит.
Также хочу задать вопрос(офтоп), как стоит строить код если в проекте есть енкодер и графический экран, суть такая, правильно ли я сделал, что запихал энкодер в while с условием выхода: изменение переменной которое изменяется энкодером, а в конце кода после отрисовки на экране и прочим делам, приравниваю это значение к предыдущее запомненному которое входит в условие выхода из while, и через break выхожу из while при нажатии других кнопок... если коротко, то если енкодер изменил переменную на еденицу то выходим из цикла (как бы софтовое прерывание, сори не шарю в программировании, возможно есть внятное название) правилен ли такой подход, т.к. прерывания тут приводили к артефактам на экране?
пока реализован скетч по управлению яркостью светодиода
int brightness = 0; // яркость LED, начинаем с половины
int fadeAmount = 5; // шаг изменения яркости LED
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 11; // pin 12
const int pin_B = 10; // pin 11
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
void setup() { // declare pin 9 to be an output:
pinMode(9, OUTPUT); // устанавливаем pin 9 как выход
pinMode(pin_A, INPUT);
pinMode(pin_B, INPUT);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
currentTime = millis();
loopTime = currentTime; }
void loop() {
currentTime = millis();
if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера
encoder_B = digitalRead(pin_B); // считываем состояние выхода А энкодера
if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю
if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке
// увеличиваем яркость, не более чем до 255
if(brightness + fadeAmount <= 255) brightness += fadeAmount; }
else { // выход В в 0 сост., значит вращение против часовой стрелки
// уменьшаем яркость, но не ниже 0
if(brightness - fadeAmount >= 0) brightness -= fadeAmount; }
}
encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла
analogWrite(9, brightness); // устанавливаем яркость на 9 ножку
loopTime = currentTime; }
}
а вот примеры уважемых форумчан, которые приведены выше в теме не заработали, вернее в сериал идет вывод..Redy и все больше ничего не выводится...Ready и все...больше ничего не выводит...
Подход интересен хотя бы тем, что используется только одно прерывание (вторая нога может висеть где угодно). В перспективе - легко подключить 2 энкодера.
В порядке бреда: а если повесить выходы B трех энкодеров на одно прерывание и по срабатыванию срочно смотреть какое состояние из трех А изменилось? Думаю, одновременное использование нескольких энкодеров явление редкое и можно это не учитывать в обработке.
В последнее время не брезгую пользоваться штатной библиотекой. Там можно легко подключать 2 энкодера. Но лучше всего 1 - оба канала на прерывания. А если нужно много энкодеров, то дорога лежит в освоение прерывания по изменению любой ноги одного порта (есть такое в AVR). Прерывание там одно. При возникновении нужно сначала прочитать весь порт и посмотреть, где изменился бит. Новый SoftSerial как раз использует такое прерывание (из-за него есть ограничение, на какие ноги нельзя программировать RX).
Не бред, конечно, по большому счету... Но представте, что каналы "В" запараллелены на прерывание, тогда, скажем, на первом энкодере этот канал "упал" в 0 - посмотрели, сосчитали первый энкодер (все хорошо, только мы не знаем, что именно от первого энкодера прило прерывание, потому что при этом "А" не изменился, потому что каналы меняются по очереди, потому что это код Грея), потом "В" осталось в "0" - и хоть закрутись остальными энкодерами, прерывания не будет больше, пока первый линию не отпустит.
Ну или разводить все линии энкодеров на разные входы и городить серьезную логику, чтобы фронты выделяла и на прерывание подавала...
енкодеры с кодом Грея и инкрементальные енкодеры разные вещи
на счет прерываний по фронту/спаду/изменению... берите старшие меги, у них почти все выводы такую фишку имеют.
Да и чо мудрить,есть готовые библиотеки с поддрежкой софт/хард. опроса енкодера, с выбором количества тактов и .т.п.
Энкодеры с кодом Грея - это разновидность инкрементальных энкодеров.
Библиотеки есть, я уже писал, что такой пользуюсь. Смысл в том, что на ногах без прерываний библиотекой пользоваться очень неудобно - нужно "ручками" опрашивать энкодер часто-часто... Вот и получается, что 2-мя энкодерами худо-бедно можно пользоваться на Arduino UNO, 4-мя на Leonardo и 6-ю на MEGA - по количеству внешних прерываний.
Энкодеры с кодом Грея - это разновидность инкрементальных энкодеров.
Библиотеки есть, я уже писал, что такой пользуюсь. Смысл в том, что на ногах без прерываний библиотекой пользоваться очень неудобно - нужно "ручками" опрашивать энкодер часто-часто... Вот и получается, что 2-мя энкодерами худо-бедно можно пользоваться на Arduino UNO, 4-мя на Leonardo и 6-ю на MEGA - по количеству внешних прерываний.
у Leonardo выведены наружу 2 прерывания ?
уточните пожалуйста - можно пользоваться четырьмя выводами энкодера или 4-мя (4 шт) энкодерами ?
Внешнее прерывание: 2 и 3. Данные выводы могут быть сконфигурированы на вызов прерывания либо на младшем значении, либо на переднем или заднем фронте, или при изменении значения. Подробная информация ...
там единственный ньюанс при считывании значения энкодера и записи переменной в енкодер нужно делить и умножать на 4 - так понимаю, что от аппаратной реализации энкодера зависит:
Я отдельно тупил над этим вопросом, и дарю не очень элегантное решение для квадратичного энкодера (есть ещё суммирующие и прочие):
int FA,FB;
int Counter, Arrow;
attachInterrupt(3, interrupt3, CHANGE); // привязываем pin20 к функции interrupt0()
attachInterrupt(2, interrupt2, CHANGE); // привязываем pin21 к функции interrupt1()
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
Всё правильно! Это алгоритм 4-кратный. Его писал на прибор с 200 импульсов/оборот, что было мало.
Для получения 1 импульса необходимо установить флаг HА по фронту импульса А, установить флаг HB по фронту импульса B, и по спаду импульса A будет событие счёта, соответствено все флаги сбрасываются и цикл повторяется. Спад B игнорируется
Это сделано для повышения надежности счёта. Нарушение последовательности сразу сообщают контрольному устройству неисправность энкодера.
не знаю получится ли одновременно использовать
attachInterrupt(3, interrupt3, HIGH);
attachInterrupt(3, interrupt4, LOW);
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
кратность четырём обусловлена аппаратной реализацией энкодера - четыре раза он ногами дёргает при проворачивании на один механический щелчок. попробуй медленно вращать шток, игнорируя механическую фиксацию - заметишь, что таки четыре шага оно делает.
для активации работы по прерываниям в коде скетча нужно указать режим работы энкодера и ноги, соответвенно подключить.
#define ENCODER_USE_INTERRUPTS // одна нога на прерывании.
#define ENCODER_OPTIMIZE_INTERRUPTS// обе ноги на прерываниях.
#define ENCODER_DO_NOT_USE_INTERRUPTS // без обработки прерываний, подключено к любой ноге.
в сомпорт пуляем изменённое значение переменной энкодера, а не сырые данные - откуда там возьмутся повторы, если читаем изменение состояния?
авторы библиотеки аппаратно проверили максимальную производительность - 127 кГц.
сам пользую библиотеку без прерываний для руления меню LCD и ввода параметров более чем достаточно.
иначе, #define ENCODER_OPTIMIZE_INTERRUPTS
пример использования:
#define ENCODER_DO_NOT_USE_INTERRUPTS // енкодер не использует прерывания.
#include <Encoder.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
int n; // переменная, хранящая значение энкодера.
Encoder Enc_00(18, 19); // объявляем, куда подключен энкодер Enc_00.
void setup() {
lcd.begin(16, 2);
n = 0; // начало отсчёта энкодера.
Enc_00.write(n*4);
}
void loop() {
int nn = Enc_00.read()/4;
if (nn != n) {
n = nn;
lcd.clear(); lcd.setCursor(0, 0); lcd.print(n);
}
}
Имеется энкодер с кнопкой. Подскажите, пожалуйста, что нужно добавить в предыдущем коде (на основе библиотеки td_libs_Encoder), чтобы изменялся шаг изменения переменной. Например при отжатой кнопке и вращении энкодера шаг изменения 1 (единица), а при нажатой и вращении - шаг 10 (десять).
/*
** Энкодер
**
*/
const int A=4 ; // порт А
const int B=5; // порт В
int val = 0; // начало отсчета с нуля
int fadeAmount = 1; // шаг изменения
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
void setup() {
Serial.begin(9600);
pinMode(A,INPUT);
pinMode(B,INPUT);
}
void loop()
{
encoder_A = digitalRead(A); // считываем состояние выхода А энкодера
encoder_B = digitalRead(B); // считываем состояние выхода B энкодера
if ((!encoder_A) && (encoder_A_prev)) // если состояние изменилось с положительное к нулю
{
if (encoder_B)
{
// выход В в полож. сост., значит вращение по часовой стрелке
// увеличиваем число, до 60
if (val + fadeAmount <= 60) val += fadeAmount;
}
else
{
// выход В в 0 сост., значит вращение против часовой стрелки
// уменьшаем число, но не ниже 0
if(val - fadeAmount >= 0) val -= fadeAmount;
}
}
encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла
Serial.println (val); // устанавливаем значения
delay(5);
}
Как то вот так я переделал скейтч под себя половино лишнее удалил. подумал что оно не нужное и все работает)))
отстал от Ваших опытов :( .....
а спросить вот что хотел :
- в теле процедуры обработки прерывания первым же оператором отключить прерывание
получится программный RS-триггер, по каналу А этим устраняется весь дребезг
на канале В дребезга в этот момент не может быть (каналы сдвинуты на 180 гр.)
- анализ канала В, вычисления
- разрешить прерывание
?
отстал от Ваших опытов :( .....
на канале В дребезга в этот момент не может быть (каналы сдвинуты на 180 гр.)
Ага. Я тоже так думал. На прошлой странице расписывал эту логику. С картинками. Реальность оказалось суровей.
К сожалению скетч не сохранил. Жду выходных. Повторю - выложу лог. Может вы сообразите как такая порнография выходит.
отстал от Ваших опытов :( .....
Ну опыты с экнодером плавно перетекли в жонглирование байтами. Но это тоже весело и захватывающе ;)
пойду-ка на антресоли залезу - за своим любимым С1-77.... будем посмотреть.... даааааа, захватывает :)
пойду-ка на антресоли залезу - за своим любимым С1-77.... будем посмотреть.... даааааа, захватывает :)
SU-27 и "лезть на андресоли"? Выбиваетесь из образа :)
Вообщем реанимировал я свой гиморой
Кручу вправо (паузу между щелчками деалю секунду, две):
Кручу влево
Другой энкодер (другая модель):
Право "0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 "
Лево "1 0 0 1 1 0 0 1 0 0 0 0 0 1"
Ну вот спрашивается, какого фига? Где обещанная стабильность?
Прямое чтение из порта - та же картина. Более того даже если я буду делать digitalRead(PIN_A) - и нули и единицы в вводе. Несмотря на то что RISING при аттаче. И прямое чтение из порта - тоже не помогает.
Полный бред.
Сделал антидребезг через детач.
Кручу в одну сторону "A 0 A 1 A 1 A "
На один щелчек выскакивает 1 (или ноль), потом, через три секунды A, потом, иногда(!) опять 1 (или 0). Хотя к тому времени даже рука с энкодера убрана и спрятана за спину. То есть ни о каком "восходящем фронте" не может быть речи. Вообще не может быть сработки.
Как будто при attachInterrupt оно вспомнило о фронте которые были во время детача.
Вообщем если кто-то еще "боится библиотек", я вот вариант скетча AlexFisher на состояниях.
Выкинул из него LCD, вывожу в Serial. Добавил поддержку MEGA платы и чуток даунгруйднул что-бы не только с последней версией ArduinoIDE работало.
Вообщем "условно работает". Подшумливает правда.
То есть сделать там "ругулятор громкости" - можно, а вот ловить команды типа "сделали 3 щелчка" - уже нет :( Задача "когда нам каждый тик и мил и дорог" - пока не решена :(
Пишу в 3-й раз :( Что-то фокс сбрасывает, пишу из оперы...
От "подшумливания" так и не смог избавиться. Пытался вставить задержку в начало прерывания на _delay_ns() - она без прерываний, но не помогло. Вот только не пробовал бороться "железными" методами. Может 2 конденсатора по 0.1 мкФ спасут отца русской демократии? Под рукой не оказалось - непроверил.
А тем, кому нужно ловить каждый шаг, все равно "контактные" энкодеры не помогут, им нужны безконтактные, а там дребезга не будет. Там другие подводные камни.
Вот что еще интересно, у меня энкодер заявлен как 24 шага на оборот, по механике дает 24 "щелчка", а считает при этом до 96... Может имеет смысл считать целыми сигнатурами (а-ля синхронизация по началу сигнатуры) или четверть-шагами? Или у меня уже крыша рассинхронизировалась?
Вот только не пробовал бороться "железными" методами. Может 2 конденсатора по 0.1 мкФ спасут отца русской демократии? Под рукой не оказалось - непроверил.
Та же история. "Железно" - религия не позволяет (по идее то что делает железо должно и програмно быть возможно) и "нет под рукой.
А тем, кому нужно ловить каждый шаг, все равно "контактные" энкодеры не помогут, им нужны безконтактные, а там дребезга не будет. Там другие подводные камни.
Не хочется в это верить. Бесконтактные - стоят кучеряво. Если для "разово" это еще покатит, то для "серии" это уже ОЧЕНЬ ОЩУТИМО. Поэтому и хочется научится стабильно работать с самыми дешевыми.
Да и фиг с ним дребезгом при смене. Но ведь, по идее, когда идет фронт A, при этом B должен "стоять как влитой". Уже закончить все свои "трепыхания" к тому времени. Получает он дребезжит вообще при любом механическом действии, а не только когда собрался менятся?
Вот что еще интересно, у меня энкодер заявлен как 24 шага на оборот, по механике дает 24 "щелчка", а считает при этом до 96...
Да нет. Это как раз и есть "самый обычный энкодер". На один шаг выдает 4-ре импульса (можно еще и "полущелчок ловить").
Вообщем-то и было в мыслях, следующих шагом смотреть на вот эту серии из 4-рех. Смотреть "кого из них больше". Ну и считать их все "одним счелчком". Правда нужно, опя-ть таки из за шума, не всегда на получается "счелчек 4-ре". Так что нужно,опять-таки, как-то по времени разделять "на серии", но при быстром вращении, не уверен что "это получится".
Та же история. "Железно" - религия не позволяет (по идее то что делает железо должно и програмно быть возможно) и "нет под рукой.
Мне как раз религия позволяет - я больше электронщик, чем программист, мне не позволяет лень :) Завтра обязательно попробую. Если не забуду кондерчиков из дома прихватить :)
Мне как раз религия позволяет - я больше электронщик, чем программист
Может тогда у вас осцил есть? Можете посмотреть что там на B происходит в момент смены A?
Осцил дома... ардуина на работе... попробую в кучу собрать :)
Да и фиг с ним дребезгом при смене. Но ведь, по идее, когда идет фронт A, при этом B должен "стоять как влитой". Уже закончить все свои "трепыхания" к тому времени. Получает он дребезжит вообще при любом механическом действии, а не только когда собрался менятся?
Вот так выглядит механический энкодер изнутри (стырено с robocraft'a):
скольжение пружинных контактов (левая половинка) по металлическим секторам (правая половинка) с определенной долей вероятности приводит к потере контакта из-за шероховатости поверхностей. Отсюда и шум.
Осцил дома... ардуина на работе... попробую в кучу собрать :)
Ну достаточно познакомить энкодер и осцил. Дуина - не обязательно.
Да и вообще "не обязательно", ваша картинка уже дала ответ.
Хотя вообщем-то, после всех мук, я уже в голове себе именно такую картину и нарисовал. Другого объяснения "как такое может быть" - я не видел. Хотел подтверждения. Вроде получил.
Значит, таки нужно либо ставить кондеры, либо изображать их програмно. Причем на обоих пинах.
Только наверное не через
> _delay_ns()
Что-то я не уверен что она "без прерываний". Неужели эна "тупо крутит цикл"? Точно на счетчики времени не смотрит?
К тому же "тупой делей" скорее всего не поможет. Он предпологает что "пошумело и успокоилось". А у нас "шумит все время".
_delay_ns() тупо крутит цикл. Количество интерраций расчитывает компиллятор по тактовой процессора. Именно поэтому аргументом функции может быть только константа. _delay_ms() уже вызывает в цикле _delay_ns().
По поводу механики энкодера - я с ней знаком. "плохой контакт" ползунков лечится 2-мя способами:
А почему тогда потенциометры не шумят? Там такие же контакты....
А почему тогда потенциометры не шумят? Там такие же контакты....
Наверное потому что они уже немного изображают из себя RC-цепочу. R - сам потенциометр. C- какое-то паразитное имеется.
Хотя вообще не факт что "не шумят". В районе своего нуля (когда сопротивление 0) вполне могут и шуметь так же.
Да и банално, в потенциометре площадь контакта может быть на порядок больше.
Хотя вообще не факт что "не шумят". В районе своего нуля (когда сопротивление 0) вполне могут и шуметь так же.
Да и банално, в потенциометре площадь контакта может быть на порядок больше.
Еще как шумят!!! Особенно, когда крутишь ручку! Особенно советсткие! Два раза особенно китайские!!!. Для качественного усилка приходится покупать регуляторы (переменные резистроры) фирмы Alps за 50$
PS Извините, но давайте про резисторы не будем, оффтоп, все же. Итак уходили в программирование сильно...
В "теории", на прерываниях вообще все очень просто.
Повесили канал A, на пин 2. Сделали attachInterupt(0,pinAHandler,RISING);
Красные стрелки это момент когда вызовется функция pinAHandler, в зависимости от того в какую сторону крутим ручку.
В самом функции pinAHandler прочитали пин на который подсоеденан канал B. Если там 1 - значит щелкнули против часовой, если 0 - значит по часовой (ну или наоборот, смотря как подключили A,B).
Ну в теории "все просто", на практике - сложней (но тоже просто когда знаешь где собака зарыта:)
Купить осцил - жаба давить. У знакомых - через пол города ехать.
В итоге собрал на дуинке простейшик Logic Analizer и "посмотрел че-там".
Ожидал увидеть шум на обоих каналах просто в момент любого движения.
Но все оказалось проще.
Шум позникает только в момент переключения состояния канала. Когда он "установился" - стоит как влитой.
То есть при смене канала A - все-таки можно уверенно смотреть на B. К тому моменту у него никакого дребезга нет и в помине.
"Собака" была, все-таки в определении смены канала А. Неправильно выбран момент когда определяется "он поменялся".
Так как у нас есть шум "при смене", то вот на этой картинке красные стерочки, наш триггер на FRONT может сработать на любой из этих красных стрелок, вне зависимости от того куда мы крутим. Как повезет. Не будет шума при "падении в ноль" - поймаем RISING в правильный момент (и правильно поймем направление глядя на B, четко в соотвествии теории), "зашумит"" при переходе канала в ноль - все, мы ошиблись в направлении. Глядим на B в неправильное время.
Вот и получается, что "по теории" - без раницы на что вешать обработчик, на RISING или FALLING, а в реальности - нужно на FALLING :) Первое же падение A в ноль - четко означет "щелчок", а последующие - это шум.
Вот мой скетч из #55. Отличие только RISING->FALLING
Но, в резульатате. При неспешных щелчках (дебоунс-то 500 милисекунд) - в одном направлении ошибок вообще 0, в другом 2-3% (думаю и это задавлю). При уменьшении дебоунса - ошибки начинают "появлятся", но теперь есть идеи "как это победить" :) И снизить время дебоунса до юзабельных значений.
P.S. Вообщем смотреть нужно когда красная стелочка "вниз", а не "вверх" как на картинке.
Фух. Я опять чуствую себя полноценным девелопером. :)
Победил!!!
Четко ловится каждый "щелчек". Без ошибок направления, без пропусков (даже если "крутить" достаточно быстры).
Общий подход такой
1. На нисходящем фронте A, смотрим состояние B и запоминаем его. А так же время "когда это произошло" (падение A)
2. На восходящем фронте A, смотрим сколько времени прошло с пукнта 1. Если меньше определенного значения (5 msec опытно подобрал) - игнорируем, если больше - меняем счетчик энкодра. Направление определяем по состоянию канала B, запомненного на пункте 1.
Выдает (сделал 10-ть щелчков по часовой и 10-ть против):
Количество щелчков четко совпадет с тем что "чувствуется рукой". Крутил в темпе "что-бы самому успевать считать щелчки".
Подход интересен хотя бы тем, что используется только одно прерывание (вторая нога может висеть где угодно). В перспективе - легко подключить 2 энкодера. Сохраню себе - потом помучаю (интересно, как оно будет работать без ожидания вывода в сериал... и подумаю, как на этом принципе повесить 3 энкодера :)
"совпадает с тем, что чувствует рука"... не гуд, очень хочется ловить все 96 состояний, а не 24.
Хочу собрать тестовую установку из шаговика и энкодера :) Потетсить разные подходы :) Где бы время взять...
Подход интересен хотя бы тем, что используется только одно прерывание (вторая нога может висеть где угодно). В перспективе - легко подключить 2 энкодера.
Да. В принципе вообще ничто не мешает не расходовать дефицитное внешние прерывание. Взять Pin Change interrupts. Один черт front/down определяем програмно.
А можно, все-таки от таймера. Просто регулярно смотреть на пины. Я когда мерял-смотрел что там происходит, то на частоте опроса ниже 10 килогерц - никаких шумов уже не видно было вообще. Сигналы "чистые и пушистые". Тогда можно будет еще больше упростить логику. И "на каких пинах" - вообще не важно станет (правда таймер займем и кусочек процессорного времени)
"совпадает с тем, что чувствует рука"... не гуд, очень хочется ловить все 96 состояний, а не 24.
Ну у меня цель была именно "ручная крутилка". Как устройство ввода "ввести нужное количество тиков". А "сколько состояний" - ну это уже от энкодера зависит :) Или вы "полу-щелчки" ловить хотите? Все-таки длина самих импульсов намного меньше чем интервалы между ними. Там "дребезг" уже трудней будет отфильтровать.
Но возможно это сильно зависит от энкодера. У меня "щелчковый", а "без щелчковый" может быть и более "равномерную картину дает". Тогда там и половинные состояния и имеет смысл и легче ловить.
Хочу собрать тестовую установку из шаговика и энкодера :) Потетсить разные подходы :) Где бы время взять...
Как тестовая - да. Как "следить за мотором" - механический быстро сотрется. Тут явно оптический нужен. А с ним и танцев этих, с дребезгом, не будет. Так что IMHO все-таки "чувствует рука" - это гуд. Так как именно только для руки и имеет смысл это использовать.
Как тестовая - да. Как "следить за мотором" - механический быстро сотрется. Тут явно оптический нужен. А с ним и танцев этих, с дребезгом, не будет. Так что IMHO все-таки "чувствует рука" - это гуд. Так как именно только для руки и имеет смысл это использовать.
Согласен. Но установку все равно сделаю - со сменным энкодером - с оптическими тоже нужно поэкспериментировать (я имею ввиду самодельные энкодеры).
Я конечно не дорос до AlexFisher и leshak, т.к. потестил последний код leshak-а то он всеже не стабилен, в одну сторону считает нормально, а в обратную проскакивают ошибки (вместо вычитания еденицы проскакивает прибавление) к томуже в одну сторону считает на один меньше чем в другую, вот мой вариант без millis:
плюсы: работает без привязки ко времени(все зависит теперь от скорости работы МК и кода), в обе стороны считает одинаково, можно наверно без внутренней подтяжки,
этот подход родил когда мучился с длительным нажатием (жмакнули кнопку, переменная приравнялась к millis, если в заданном промежутке времени кнопку отпустили то сбрасываем вход в длительное нажатие, в противном случае можно последовательно нажимать копку и это прокатит за длительное нажатие)
не комментировал, думаю все просто и понятно, просто сбрасываем все проверочные состояния когда оба пина в лоу, кому нужно и прерывания прикрутит.
Также хочу задать вопрос(офтоп), как стоит строить код если в проекте есть енкодер и графический экран, суть такая, правильно ли я сделал, что запихал энкодер в while с условием выхода: изменение переменной которое изменяется энкодером, а в конце кода после отрисовки на экране и прочим делам, приравниваю это значение к предыдущее запомненному которое входит в условие выхода из while, и через break выхожу из while при нажатии других кнопок... если коротко, то если енкодер изменил переменную на еденицу то выходим из цикла (как бы софтовое прерывание, сори не шарю в программировании, возможно есть внятное название) правилен ли такой подход, т.к. прерывания тут приводили к артефактам на экране?
тоже начал пробовать освоить энкодер
пока реализован скетч по управлению яркостью светодиода
а вот примеры уважемых форумчан, которые приведены выше в теме не заработали, вернее в сериал идет вывод
..Redy и все больше ничего не выводится...
Ready и все...больше ничего не выводит...В порядке бреда: а если повесить выходы B трех энкодеров на одно прерывание и по срабатыванию срочно смотреть какое состояние из трех А изменилось? Думаю, одновременное использование нескольких энкодеров явление редкое и можно это не учитывать в обработке.
не получится, будут "считать" все енкодеры сразу, причем 2 точно бред покажут
почему 2 остальных бред покажут?
Произошло прерывание, сравниваем B1 и A1, B2 и A2, B3 и A3 (B2 == B1, B3 == B1).
А1тек != A1пред
А2тек == A2пред
А3тек == A3пред
Следовательно, произошло изменение состояния энкодера 1.
Или это слишком поверхностно?
Бред - не то слово!
В последнее время не брезгую пользоваться штатной библиотекой. Там можно легко подключать 2 энкодера. Но лучше всего 1 - оба канала на прерывания. А если нужно много энкодеров, то дорога лежит в освоение прерывания по изменению любой ноги одного порта (есть такое в AVR). Прерывание там одно. При возникновении нужно сначала прочитать весь порт и посмотреть, где изменился бит. Новый SoftSerial как раз использует такое прерывание (из-за него есть ограничение, на какие ноги нельзя программировать RX).
почему 2 остальных бред покажут?
Не бред, конечно, по большому счету... Но представте, что каналы "В" запараллелены на прерывание, тогда, скажем, на первом энкодере этот канал "упал" в 0 - посмотрели, сосчитали первый энкодер (все хорошо, только мы не знаем, что именно от первого энкодера прило прерывание, потому что при этом "А" не изменился, потому что каналы меняются по очереди, потому что это код Грея), потом "В" осталось в "0" - и хоть закрутись остальными энкодерами, прерывания не будет больше, пока первый линию не отпустит.
Ну или разводить все линии энкодеров на разные входы и городить серьезную логику, чтобы фронты выделяла и на прерывание подавала...
посмотрите что получается с формой сигнала с енкодера при изменении скорости вращения....
если один датчик будет стоять, а другие вращаться
енкодеры с кодом Грея и инкрементальные енкодеры разные вещи
на счет прерываний по фронту/спаду/изменению... берите старшие меги, у них почти все выводы такую фишку имеют.
Да и чо мудрить,есть готовые библиотеки с поддрежкой софт/хард. опроса енкодера, с выбором количества тактов и .т.п.
енкодеры с кодом Грея и инкрементальные енкодеры разные вещи
на счет прерываний по фронту/спаду/изменению... берите старшие меги, у них почти все выводы такую фишку имеют.
Да и чо мудрить,есть готовые библиотеки с поддрежкой софт/хард. опроса енкодера, с выбором количества тактов и .т.п.
Энкодеры с кодом Грея - это разновидность инкрементальных энкодеров.
Библиотеки есть, я уже писал, что такой пользуюсь. Смысл в том, что на ногах без прерываний библиотекой пользоваться очень неудобно - нужно "ручками" опрашивать энкодер часто-часто... Вот и получается, что 2-мя энкодерами худо-бедно можно пользоваться на Arduino UNO, 4-мя на Leonardo и 6-ю на MEGA - по количеству внешних прерываний.
В моей долгой и не всегда праведной жизни били такие железные правила:
1. Всегда ставить демпферный диод на индуктивную нагрузку.
2. Разделять силовые и сигнальные землю и питание.
3. Ставить хоть маленький кондёр на входе прерывания.
Вот еще один из вариантов, вроде у нас не упоминался: http://avrhobby.ru/index.php?option=com_content&view=article&id=100:2011-10-16-08-23-54&catid=34:projectsmk&Itemid=71
Энкодеры с кодом Грея - это разновидность инкрементальных энкодеров.
Библиотеки есть, я уже писал, что такой пользуюсь. Смысл в том, что на ногах без прерываний библиотекой пользоваться очень неудобно - нужно "ручками" опрашивать энкодер часто-часто... Вот и получается, что 2-мя энкодерами худо-бедно можно пользоваться на Arduino UNO, 4-мя на Leonardo и 6-ю на MEGA - по количеству внешних прерываний.
у Leonardo выведены наружу 2 прерывания ?
уточните пожалуйста - можно пользоваться четырьмя выводами энкодера или 4-мя (4 шт) энкодерами ?
http://arduino.ru/Hardware/ArduinoBoardLeonardo
Внешнее прерывание: 2 и 3. Данные выводы могут быть сконфигурированы на вызов прерывания либо на младшем значении, либо на переднем или заднем фронте, или при изменении значения. Подробная информация ...
не... это как считывать инфу с датчика, по 1 каналу, по 2, по фронту, по фронту+спаду и т.п., использовать прерывания или программно слушать датчик
пытаюсь совместить код Jacks_d и вывод на ЖК-дисплей, однако после десятка успешных поворотов ручки ардуинка виснет.
В чем может быть причина? Вроде библиотеки LCD прерывания не используют.
В чем может быть причина?
Если вынести обработчик из loop, то вобще пропускает 70% щелчков:
народ, есть же нормальная библиотека - хоть с прерываниями или без, хоть с одним или двумя, скорость максимальную авторы озвучивают.
ну надо же понять как оно изнутри работает.
А что за библиотека?
забыл ссылку воткнуть http://www.pjrc.com/teensy/td_libs_Encoder.html
там единственный ньюанс при считывании значения энкодера и записи переменной в енкодер нужно делить и умножать на 4 - так понимаю, что от аппаратной реализации энкодера зависит:
n = Enc.read()/4;
Enc.write(n*4);
Я отдельно тупил над этим вопросом, и дарю не очень элегантное решение для квадратичного энкодера (есть ещё суммирующие и прочие):
int FA,FB;
int Counter, Arrow;
attachInterrupt(3, interrupt3, CHANGE); // привязываем pin20 к функции interrupt0()
attachInterrupt(2, interrupt2, CHANGE); // привязываем pin21 к функции interrupt1()
void interrupt2() { CounterAB(); }
void interrupt3() { CounterAB(); }
void CounterAB()
{
int A;
int B;
A=digitalRead(PinA);
B=digitalRead(PinB);
Arrow=0;
if (((FA==HIGH)&&(A==LOW)&&(FB==HIGH)&&(B==HIGH))||((FA==LOW)&&(A==LOW)&&(FB==HIGH)&&(B==LOW))||((FA==LOW)&&(A==HIGH)&&(FB==LOW)&&(B==LOW))||((FA==HIGH)&&(A==HIGH)&&(FB==LOW)&&(B==HIGH)))
{ Counter++; Arrow=1; }
if (((FA==LOW)&&(A==HIGH)&&(FB==HIGH)&&(B==HIGH))||((FA==HIGH)&&(A==HIGH)&&(FB==HIGH)&&(B==LOW))||((FA==HIGH)&&(A==LOW)&&(FB==LOW)&&(B==LOW))||((FA==LOW)&&(A==LOW)&&(FB==LOW)&&(B==HIGH)))
{ Counter--; Arrow=-1; }
FA=A;FB=B; // запомнить состояние
}
Это позволяет реагировать на каждое изменение импульсов
P.S.
не пытайтесь понять логику условий - это опасно для мозга 8=)
Если уж сжимать, так по полной, заодно никто не разберется, да и память сэкономим :)
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
Всё правильно! Это алгоритм 4-кратный. Его писал на прибор с 200 импульсов/оборот, что было мало.
Для получения 1 импульса необходимо установить флаг HА по фронту импульса А, установить флаг HB по фронту импульса B, и по спаду импульса A будет событие счёта, соответствено все флаги сбрасываются и цикл повторяется. Спад B игнорируется
Это сделано для повышения надежности счёта. Нарушение последовательности сразу сообщают контрольному устройству неисправность энкодера.
не знаю получится ли одновременно использовать
attachInterrupt(3, interrupt3, HIGH);
attachInterrupt(3, interrupt4, LOW);
Проблема в том, что с моим экондером что этот код, что код с библиотекой td_libs_Encoder - оба срабатывают четырежды при каждом щелчке энкодера. А если делить на 4, то получаем 4 одинаковых значения подряд.
P.S. и опять виснем при быстром вращении энкодера (рукой!)
кратность четырём обусловлена аппаратной реализацией энкодера - четыре раза он ногами дёргает при проворачивании на один механический щелчок. попробуй медленно вращать шток, игнорируя механическую фиксацию - заметишь, что таки четыре шага оно делает.
для активации работы по прерываниям в коде скетча нужно указать режим работы энкодера и ноги, соответвенно подключить.
в сомпорт пуляем изменённое значение переменной энкодера, а не сырые данные - откуда там возьмутся повторы, если читаем изменение состояния?
авторы библиотеки аппаратно проверили максимальную производительность - 127 кГц.
сам пользую библиотеку без прерываний для руления меню LCD и ввода параметров более чем достаточно.
иначе, #define ENCODER_OPTIMIZE_INTERRUPTS
пример использования:
Здравствуйте!
Имеется энкодер с кнопкой. Подскажите, пожалуйста, что нужно добавить в предыдущем коде (на основе библиотеки td_libs_Encoder), чтобы изменялся шаг изменения переменной. Например при отжатой кнопке и вращении энкодера шаг изменения 1 (единица), а при нажатой и вращении - шаг 10 (десять).
Спасибо.
Если медленно вращать, стабильно отрабатывает или проскакивает?