snaut

Простая И Сложная Штука Инкрементальный Энкодер

82 сообщения в этой теме

NebsteR    743

Проанализировал твой алгоритм, пришлось затратить полстакана кофе, два бутерброда с колбасой и сигарету :)

Да, он местами рабочий, но у тебя таки есть ошибка, фундаментальная :yes:

Всего возможных состояний - 4 бита (2 входных и 2 выходных), итого 16 состояний, а не 8 бит, которые дают 256 состояний... Именно из-за этого твой алгоритм будет учитывать только 4 последовательных переключения энкодера в конкретную сторону, если же после одного "щелчка" его повернуть в обратную сторону - алгоритм это вообще отфильтрует...

Так что этот алгоритм имеет в себе делитель на 4 и работоспособен только для контроля двигателей, которые физически не могут мгновенно изменять направление... И твое очищение reg раз в N секунд по сути ничего не дает - остается необходимость за 4 сдвига заполнить регистр для определения направления сдвигов, и то, только если первый сдвиг после сброса установит 11 на фазах...

Ну и еще один момент - подобный антидребезг не годится... Если новый отсчет придется на середину дребезга, он либо сработает нормально (такое тоже возможно :) ), либо увеличит время отсчета в 2 раза (если состояния будут неизменными), либо даст конкретный сбой, если изменены будут состояния обеих фаз, а из-за дребезга оно будет прочитано неверно... В таком случае корректно сработает только антидребезг на основе ожидания после фиксирования факта изменения, за 5мс (время дребезга из ДШ * 2) гарантированно установится стойкий контакт площадок даже при изменении состояний обеих фаз...

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

Простейший алгоритм определения направления сдвига фаз, блин :)

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

Изменено пользователем NebsteR

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

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

А описание "2 входных и 2 выходных" не совсем понятно.

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

По сути для определения направления достаточно два изменения состояний линий, по часовой (условно принял): (11,01); (01,00); (00,10); (10,11) и против: (01,11); (10,00); (00,01); (01,11). Реализовать в моем алгоритме это не составит труда.

Насчет антидребезга, тут не кретично, можено поставить и 3мС и 5 и десять, зависит от конкретного устройства и конкретного энкодера. У китайских энкодеров, чуточку поработав, дребезг может длится до 15мС.

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

С эти согласен.

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743
Чтобы определить направление вращения нужно считать 4 изменения состояний линий энкодера, что в алгоритме и сделано.
Одно :)

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

Алгоритм я прекрасно понял,

По сути для определения направления достаточно два изменения состояний линий, по часовой (условно принял)
Опять ошибка - 4, за одно изменение состояний сдвиг на 2 бита, для заполнения всего регистра надо 4 сдвига в одном направлении... Для примера инкремента - 11010010 повторяется каждые 4 сдвига энкодера...

Обновил график фаз в сообщении 26, продублирую сюда:

Отметил все состояния покоя энкодера... При смене положения из любой позиции на соседнюю следует уникальная смена фаз. Все еще будут возражения на то, что считать направление вращение можно за 1 сдвиг?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
UTSource

Найдите миллионы труднодоступных

электронных компонентов

korsaj    34

Нет не ошибка, я писал не о своем алгоритме, а об изменениях линий энкодера.

Одно это только после первого ))

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

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

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

ЗЫ:

с заведомо известной последовательностью
Таких последовательностей - 16 для 4 бит, о чем я и пытаюсь сказать уже который пост...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

В конце концов сложно прочесть полностью то что я писал "... по часовой (условно принял): (11,01); (01,00); (00,10); (10,11) и против: (01,11); (10,00); (00,01); (01,11).." ???

Таких последовательностей 8 для 4 бит

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

Ну блин... :)

Хорошо, энкодер в позиции 10 (AB)... Я его повернул на 1 позицию вперед, стало 11... Повернул на две позиции назад - прошло опять через 10 и стало 00... Мой алгоритм даст 3 события - событие CW, событие CCW, событие CCW... Как поведет себя этот алгоритм? В конкретно этой ситуации?

На практике - осциллограф с энкодерными ручкам.. Пусть вертикальный масштаб стоит на 10в/дел. Одним сдвигом по часовой я ставлю 5в/дел, потом возвращаю на 20в/дел двумя сдвигами против...

Какие нафиг 4 сдвига для определения направления?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

Я же сказал исправить алгоритм! Останется оди сдвиг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743
Одно это только после первого ))
Тогда я, видимо, неправильно понял эту фразу? :blink:

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743
Насчет антидребезга, тут не кретично, можено поставить и 3мС и 5 и десять, зависит от конкретного устройства и конкретного энкодера. У китайских энкодеров, чуточку поработав, дребезг может длится до 15мС.
Это неважно, момент считывания может легко попасть на сам дребезг, нужно ожидание затухания после факта изменения и уже реальное сравнение по окончанию этого ожидания... Для одной фазы (кнопка) - не важно, любой факт изменения - уже событие, надо только выждать, чтоб оно не повторилось из-за дребезга, для двух - необходимо сравнивать уже после затухания дребезга...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

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

Вот исправленный алгоритм, два сдвига оставлено потому что мы в регистр Reg заносим значение линии А (1 бит регистра Reg) и линии В (0 бит регистра Reg). Ну и конечно же надо не забывать очищать флаги прерываний перед их включением.

post-139865-0-91730100-1356527237_thumb.png

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snaut    8

Уважаемый NebsteR, не могу разобраться с Вашим алгоритмом в начале. Прошу поясняющих комментариев. Что значит ветвление „Это ожидание цикла”, далее „Счетчик -1” и еще одно ветвление „Счетчик 0”. Для чего они нужны?

И еще: а что, если с дребезгом бороться с помощью конденсаторов? Думаю, что в этом ничего плохого нет. Только я не знаю, кокой емкости нужны конденсаторы

Изменено пользователем snaut

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

Пропуск циклов при ожидании затухания дребезга...

Счетчик - переменная 1 байт, флаг - переменная 1 бит, либо 1 байт, если невозможен атомарный доступ легким путем в компиляторе...

//начало обработчика
if (flag==1) //Это цикл ожидания?
{ //если это цикл ожидания
--counter; // счетчик -1
if (counter==0) //счетчик =0?
goto start_comp; //если равен, переход к началу сравнения
//если неравен, то перейдет к концу обработчика, пропустит цикл
} else
{ //если это не цикл ожидания
start_comp:; //метка перехода
... //здесь идут подвложения, начиная с "Есть изменения А или B?"
};
//конец обработчика

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snaut    8

Не нашь метод — согласен:) Сложности нет, но быстродействие, хоть и не значительное

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
NebsteR    743

При 1MIPS это даст нагрузку в <0.1%, меньше 10 инструкций каждую миллисекунду... Быстродействие, говоришь? :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

Ну вот я реализовал свой алгоритм на прерываниях в Си, проверил в протеусе.

Написано под Atmega8, тактовая 8МГц.

#include <stdlib.h>
#include <avr/interrupt.h> // îáðàáîòêà ïðåðûâàíèé
#include <avr/iom8.h>

#define En_A PD2
#define En_B PD3
//------------------------------------------------------------------------------
unsigned char RegEncod, Counter;
//------------------------------------------------------------------------------
const unsigned char m5S = 100;
//------------------------------------------------------------------------------
ISR(INT0_vect){
GICR &= ~(1<<INT1 | 1<<INT0); //Çàïðåøàåì ïðåðûâàíèÿ îò êíîïîê
TIMSK |= 1<<TOIE0; //Ðàçðåøàåì ïðåðûâàíèÿ îò òàéìåðà
TIFR |= 1<<TOV0; //Ñáðàñûâàåì ôëàã ïåðåïîëíåíèÿ òàéìåðà
TCNT0 = m5S;
}

//------------------------------------------------------------------------------
ISR(INT1_vect){
GICR &= ~(1<<INT1 | 1<<INT0); //Çàïðåøàåì ïðåðûâàíèÿ îò êíîïîê
TIMSK |= 1<<TOIE0; //Ðàçðåøàåì ïðåðûâàíèÿ îò òàéìåðà
TIFR |= 1<<TOV0; //Ñáðàñûâàåì ôëàã ïåðåïîëíåíèÿ òàéìåðà
TCNT0 = m5S;
}

//------------------------------------------------------------------------------
ISR(TIMER0_OVF_vect){
GICR |= 1<<INT1 | 1<<INT0; //Ðàçðåøàåì ïðåðûâàíèÿ îò êíîïîê
TIMSK &= ~1<<TOIE0; //Çàïðåøàåì ïðåðûâàíèÿ îò òàéìåðà
GIFR |= 1<<INTF1 | 1<<INTF0; //Îáíóëÿåì ôëàãè ïðåðûâàíèé
if ((bit_is_set(RegEncod,0) != bit_is_set(PIND,En_A)) | (bit_is_set(RegEncod,1) != bit_is_set(PIND,En_)) {
RegEncod = RegEncod<<2;
if bit_is_set(PIND,En_A){
RegEncod |= 1<<0;
}
if bit_is_set(PIND,En_{
RegEncod |= 1<<1;
}
RegEncod &= 0b00001111;
if ((RegEncod == 0b00000010) || (RegEncod == 0b00001011)){
Counter++;
}
if ((RegEncod == 0b00001101) || (RegEncod == 0b00000100)){
Counter++;
}
if ((RegEncod == 0b00000001) || (RegEncod == 0b00000111)){
Counter--;
}
if ((RegEncod == 0b00001110) || (RegEncod == 0b00001000)){
Counter--;
}
}
}

//------------------------------------------------------------------------------
// èíèöèàëèçàöèÿ
void Init()
{
cli(); //Çàïðåùàåì ïðåðûâàíèÿ

DDRB = 0;
DDRC = 0;
DDRD = ~(1<<En_A | 1<<En_; //Ëèíèÿ À è Â íà âõîä
PORTD = 1<<En_A | 1<<En_B; //Ïîäòÿãèâàþùèå ê ëèíèÿì À è Â íà âõîä

TCCR0 = 0b00000100; //Ïðåääåëèòåëü 256

MCUCR = 0B00000101;
GICR = 1<<INT1 | 1<<INT0; //Ðàçðåøàåì ïðåðûâàíèÿ îò êíîïîê

GIFR = 1<<INTF1 | 1<<INTF0; //Îáíóëÿåì ôëàãè ïðåðûâàíèé

sei(); //Ðàçðåøàåì ïðåðûâàíèÿ
}

//------------------------------------------------------------------------------
int main ()
{
Init();

while (1){ // áåñêîíå÷íûé öèêë

}
}
//------------------------------------------------------------------------------

PS. Чет мне не нравится GCC, глючный он какойто, и как-то многовато 464 байта памяти для реализации данного алгоритма. Может я чего не так написал? Подскажите, поправте.

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snaut    8

А я отладочную только два дня собирал. Глючит почему-то. Где-то коротит. Решил отключить кнопку, снял все подтяги - пускай внутренние будут. С экспериментами спалил portb :thank_you2: . Пересмотрел кучу алгоритмов, но так ничего и не понял. думаю дальше. И все таки сложная это штука - энкодер. В языке си я не понимаю, пишу на асме. Вот пытаюсь придерживаться описанного на сайте алгоритма. Гляньте пожалуйста — правильно описан алгоритм?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

Вот тоже самое на ассемблере. Используется 174 байта памяти программ, 2 ячейки ОЗУ и 2 регистра общего назначения.

Enc.txt

Изменено пользователем korsaj

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
korsaj    34

Вот пытаюсь придерживаться описанного на сайте алгоритма. Гляньте пожалуйста — правильно описан алгоритм?

Алгоритм такой же как и в моем посте #23. Увеличивается/уменьшается по полному совпадению последовательности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snaut    8

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

Изменено пользователем snaut

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сообщения

    • Я собрал на 10А, мне нужен был, как раз для "толчка" разных акб (литий от шурика в начале заряда берет 7-8А). выход осликом на шумы не проверял  (нет толкового ослика). По конструкции- выходной дроссель делал из 2-х склеенных  комповых желтых колец d 32мм кажись ну и провод 1.5мм в 2 жилы. Дороги силовые делал пошире и усилял еще напайкой сверху медным проводом (в общем все что касалось силовой низковольтной схемы делал с увеличенным сечением- перемычки с ферритовыми бусинами на "горячей стороне" делал проводом 1мм или чуть больше). Выходные конденсаторы ставил набором , Транзисторы ставил те же что и на схеме IRF740 или IRF840,  При настройке найди пост где Falanger по моей просьбе разъяснил порядок настройки обратной связи. (за что ему огромное спасибо) далее лм7809 для питания лм358 ставь в 220 корпусе + конденсаторы 0.1мкФ для защиты от импульсов. Микросхемы ставь на панельки, при настройке однозначно что нибудь спалишь- потом проще менять будет. Дежурку и схему питания вентилятора можешь сделать отдельно. Но самсиловой блок разбивать на отдельные модули не рекомендуется. только если выходную часть (поставить второй дроссель и выходные конденсаторы) barri по моему  "боролся" с быстродействием ОС посмотри его посты. Ну вроде все. А еще я ставил многооборотные резисторы на схему управления оч удобно.
    • Посоветуйте защиту из имеющихся на Алиэкспресс , конструктором или просто платку , есть у меня одна защита как на фотке но не вызывает доверие.
    • В теории и с некоторыми уточнениями-дополнениями - да.  На практике - лучше не приближаться к предельным значениям по питанию ... как минимум вдвое. По нагрузке и вовсе - делить на 5.  Резистор между стабилитроном и входом питания - выбрать помощнее... И, номинал рассчитывать исходя из величины питающего напряжения. 
    • Вот ещё что мне приволокли - это с какого-то Кинапа два трансформатора, на одном написано ТР-223 а на другом ничего - но конструктивно и расположение выводов и внешне одинаковы... попробую погуглить шо оно такое, может кто их узнает - подскажите   Вот шо выяснилось - Тр 223 - силовой тр-р от кинаповского усилителя 90У-2. Питание - сеть 110В. Железо Ш22 набор 56мм, толщ. листа 0,35мм. Сетевая обм. - 240вит ПЭЛ 0,74; анодная - 890+890 ПЭЛ 0,23; накальные - 12 и 9вит ПЭВ 1,0. Есть ещё обмотка 23витПЭЛ 0,74, Экран - 70 вит. ПЭЛ 0,41.   То есть можно их последовательно первичками соединить и делать раздельное питание по вторичке
    • Покупал сдесь https://www.ebay.com/itm/1pcs-ALPS-RK40-50KA-Black-Beauty-Audio-Potentiometer-Half-Shaft-for-McIntosh/151560677534?hash=item2349b8689e:g:vKAAAOSwzrxUv3C3,только был подешевле. Остальные детали все брал на маузере,плату у автора,корпус делал на заводе из алюминия.
    • Ага, заказанный на али за 1000р)