Отговори на тема  [ 27 мнения ]  Отиди на страница 1, 2  Следваща
Ротационен енкодер. Как да чета движението му? 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение Ротационен енкодер. Как да чета движението му?
Този път реших да си задам въпроса в раздел Академия, защото ми изглежда доста тъп :)
Става дума за нормален механичен (не оптичен) ротационен енкодер. По-точно ето този, а документацията е тук.
Та ето по-конкретно какъв ми е проблема. Правя си експерименти с подръчни материали. Опитвам се да направя програма за PIC18F452 на МСС18, с чиято помощ процесорът да чете посоката на завъртане на енкодера и на един LCD да изписва число, което се увеличава при завъртане надясно и да се намалява при завъртане наляво. Всичко работи отлично с изключение на четенето на енкодера. Намерих един кратък код някъде из форума, но и с него не се получи. В едната посока беше перфектно, но в другата или подскачаше напред-назад стойността или се увеличаваше вместо да намалява.

ето кода, който намерих във форума:
int8 Read_Encoder()
{ If (!PINA)
for (i=0;i<200;i++)
{ If (!PINB) {Return Left;break}
}
If (!PINB)
for (i=0;i<200;i++)
{ If (!PINA) {Return Right;break}
}
}

преобразувах го до нещо по-подходящо за моя случай :
unsigned char rot_dir(void)
{
unsigned int dc;
if (!pinA)
for (dc=0;dc<10000;dc++) // това е около 2мс при 20MHz
{
if (!pinB)
{
return 'R';
break;
}
}
if (!pinB)
for (dc=0;dc<10000;dc++) // това е около 2мс при 20MHz
{
if (!pinA)
{
return 'L';
break;
}
}
}

Използвайки pull-up на порт В не се наложи да се слагат външни резистори. В този случай на изходите би трябвало да се получи нещо като това на картинката най-долу в поста ми. Естествено доста идеализирано. Вероятно има проблеми с шумовете при превключване. Пробвах какви ли не алгоритми да измисля, но все нещо не беше в ред.
Чудно ми е защо при прещракването на механиката трябва да се генерират два дефазирани импулса и то прилично кратки вместо да има постоянни нива и това прещракване да служи само за задържане на оста в определени положения, за да не застават контактите между проводима и непроводима повърхност. Би било доста по-лесно за обработка според мен.

Ако някой може да помогне с работещ код ще съм му благодарен. Трябва ми само фрагмент с разпознаването на посоката на въртене. Няма значение на какъв език е писано, стига да не е асемблерен и да може да се приложи за PIC чип.


Прикачени файлове:
rotenc.GIF
rotenc.GIF [ 1.16 KiB | Прегледано 3796 пъти ]
Чет Авг 23, 2007 9:33 am
Профил WWW
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Съб Сеп 17, 2005 5:07 pm
Мнения: 813
Местоположение: Сливен
Мнение 
Само да вметна .... не пиша на PICC18 ама ..... това:

iunsigned int dc; не трябва ли да е unsigned long int dc;
защото :
for (dc=0;dc<10000;dc++)
и променливата ако е int и никога няма да достигне условието на цикъла ......


Чет Авг 23, 2007 9:58 am
Профил ICQ
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение 
Това PICC18 не знам дали е същото. Аз ползвам на Майкрочип компилатора на С за MPLAB.
Това което прочетох в документацията на компилатора беше, че unsigned int може да приема целочислени стойности от 0 до 65535. Тоест 16 битова променлива. При един от опитите да измисля подходящ код вместо да чака да врътна енкодера, програмата започна сама да си брои. Променливата, съдържаща числото, което увеличавам или намалявам е от същия тип. Без проблем си броеше в споменатия обхват. Изчаках я специално, за да видя как ще се държи. Освен това в проекта, в който ще ползвам евентуално енкодера, той ще брои в диапазона 0 до 30 най-много 60.

_________________
"Има само две безкрайни неща, Вселената и човешката глупост. За първото не съм съвсем сигурен."
Алберт Айнщайн


Чет Авг 23, 2007 10:07 am
Профил WWW
Ранг: Новодошъл
Ранг: Новодошъл
Аватар

Регистриран на: Вто Ное 16, 2004 3:29 pm
Мнения: 108
Местоположение: София
Мнение 
Мисля че тук има точно това което те интересува:
http://www.mcmanis.com/chuck/robotics/p ... atrak.html

На асемблер е но има основната идея и мился че лесно може да си я прехвърлиш на C.


Чет Авг 23, 2007 10:59 am
Профил WWW
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение 
Нещо подобно опитах вече. В главната ми програма се прави непрекъсната проверка за натиснат бутон и завъртян енкодер. Бях написал функция, която при повикване взима текущото състояние на изводите на енкодера и чака за промяната му, за да стане ясно в коя посока е завъртян. Смятам, че проблема е в шумовете от превключването. Тоест когато функцията вземе състояниета на изводите например АВ = 10 може да се окаже, че всъщност е било 11 или 00 или 01, но засичането е станало в периода на установяване на състоянието. Следователно при отчитане на посоката става грешка. Може би трябва да опитам да активирам прекъсването по ниво на порт В и само при промяна в нивото да правя проверка за посоката. Така ще е ясно къде започва всичко. В документацията на енкодера е дадено, че установяването на състояние трае до 2мс (от 1 към 0 или обратно) и импулса също трае 2мс. Тъй като в момента на проверката на нивото на пиновете не е ясно в коя част от цикъла се намира енкодера стават и проблемите според мен.
Друг вариант е опит да се филтрират шумовете с кондензатори. Смятам да опитам и това.

На асемблер имам кода от книгите на Млад Конструктор за PIC чиповете.
Из Интернет също намирах интересни решения. Най-хубавото беше да се четат два пъти състоянията на пиновете и да се запомнят в променливи. След това се прави операция XOR (изключващо ИЛИ) на пинА в старото састояние и пинВ в новото, като ако резултата е 1, то имаме завъртане наляво, а ако е 0 - надясно (може и да бъркам посоките, но идеята е ясна). Направих го на С и пак не стана заради шумовете. Явно не съм уцелил най-добрата бройка на енкодера :)

П.П.
Като гледам писанията из форума май този тип ротационни енкодери създават главоболия не само на мен като начинаещ бъдещ гений 8) , но и на хора, които знаят какво правят.

_________________
"Има само две безкрайни неща, Вселената и човешката глупост. За първото не съм съвсем сигурен."
Алберт Айнщайн


Чет Авг 23, 2007 11:25 am
Профил WWW
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Съб Сеп 17, 2005 5:07 pm
Мнения: 813
Местоположение: Сливен
Мнение 
Като гледам ползваш 18ф452 ... е ми защо не му ползваш 2 от трите външни външни прекъсвяания ??? така винаги ще знаеш кога имаш А и кога Б прекъсване от там нататък си обработваш нещата , пък и ще си спестиш If-owete


Чет Авг 23, 2007 11:39 am
Профил ICQ
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение 
Явно накрая така ще да стане или ще мина на конвенционални грозни бутони :)
Не ми се искаше да ползвам прекъсване, защото ще има и часовник с външен генератор на 1 сек и исках само той да прави прекъсвания. Благодаря за съветите ви.

_________________
"Има само две безкрайни неща, Вселената и човешката глупост. За първото не съм съвсем сигурен."
Алберт Айнщайн


Чет Авг 23, 2007 1:50 pm
Профил WWW
Ранг: Новодошъл
Ранг: Новодошъл

Регистриран на: Чет Окт 06, 2005 2:06 pm
Мнения: 194
Местоположение: Sofia
Мнение 
Щом не искаш да имаш прекъсване, значи четеш постоянно входовете XOR ваш със старо състояние за да откриеш промяна.След това отиваш в друг цикъл и четеш няколко пъти до получаване на едно и също състояние (повече от 2MS), това е вече установеното ново състояние, анализираш го и се връщаш в основния цикъл да чакаш промяна.


Чет Авг 23, 2007 2:04 pm
Профил
Ранг: Почетен член
Ранг: Почетен член

Регистриран на: Съб Май 27, 2006 12:37 pm
Мнения: 647
Местоположение: с. Згалево
Мнение 
Това с този енкодер е просто! Ето ти кода:

volatile unsigned char encoder_event; // Променлива в която след завършване на проверката е резултата от четенето на енкодера

void ReadRotationEncoder(void) // След изпълнение
{
unsigned char debounced;
static unsigned char prev_debounced;


// Четене на самия енкодер
debounced = PORTА; // предполага се че енкодера е вързан на PORTA - RA0 и RA1
debounced = ~debounced;

if((debounced & 0x01) && !(prev_debounced & 0x01)){
if (debounced & 0x02) encoder_event = ENC_UP;
else encoder_event = ENC_DOWN;
}

prev_debounced = debounced;
}

Тази функция ти записва в променливата encoder_event състоянието на енкодера и си го обработваш в основната програма. Аз я викам в прекъсване на около 1мс, ама работи добре и на 2 и дори 4мс.
Става въпрос за абсолютно същия енкодер и многократно пробвано.
Успех...
:D


Чет Авг 23, 2007 7:51 pm
Профил WWW
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение 
Тъкмо пуснах поялника да добавя бутони на платката вместо тоя енкодер. Ще го пробвам преди да се откажа от него :). После ще пиша какво е станало. Дано се получи, защото е доста по-готино от обикновени бутони.

==========================

Ето и резултати.

Префасонирах малко твоя код, за да пасне на моята схема.

unsigned char rot_dir(void)
{
unsigned char debounced;
static unsigned char prev_debounced;
debounced = PORTB; // ползвам порт В пинове RB7 и RB6
debounced = ~debounced;

if((debounced & 0b10000000) && !(prev_debounced & 0b10000000))
{
if (debounced & 0b01000000)
{
return 'L';
}
else
{
return 'R';
}
}

prev_debounced = debounced;

delay_ms(1); // тук чакам 1мс както ти каза, защото се вика иначе твърде често функцията (нямам прекъсване за момента)
}


Отново работи, но не добре. Независимо от времето на изчакване (респективно честотата на проверка) при въртенето се разпознава посоката (в повечето случаи, но не винаги), но при едно щракване на механизма на дисплея ми излиза число с около 5-10 по-голямо/малко от предното. Сигурен съм, че няма грешка в броенето, тъй като функцията която брои и изписва на дисплея съм я свързвал с бутон и тогава всичко е точно.


След поредния неуспех вързвам и бутони на същите изводи. Ако случайно измисля нещо, с което да заработи ОК. Ако не остава с бутони. Дали пак не се е проявил кофти късмета ми и да съм попаднал на кофти енкодер, който не работи нормално?!

_________________
"Има само две безкрайни неща, Вселената и човешката глупост. За първото не съм съвсем сигурен."
Алберт Айнщайн


Пет Авг 24, 2007 9:06 am
Профил WWW
Ранг: Почетен член
Ранг: Почетен член

Регистриран на: Съб Май 27, 2006 12:37 pm
Мнения: 647
Местоположение: с. Згалево
Мнение 
Предполагам проблема е във времето на четене на енкодера. То не е номера да чакаш 1 мс след това, щото едва ли процесора ти прави само това и докато отново се върне да проверява енкодера - то вече е минало сигурно повече. Тоя код е малко опростен и е напасван за викане в прекъсване на около 1-2мс. Работи идеално. И аз съм се опитвал да направя тоя номер с енкодера - да го врътна много бързо или нещо такова, да му обърна посоката и той да не разбере - ама не става. Никакви магарии не минават - работи бетон. При теб що да неще. Центъра на енкодера е вързан към маса, а към процесора има пулл-уп резистори по 10к към захранването. Другото е какво правиш с променливата дето връща функцията. Аз правя така: Та имам си ГЛОБАЛНА променлива, която отразява състоянието на енкодера. Ако няма нищо е 0. Та прекъсването си гледа енкодера на 1мс. Ако има нещо станало с енкодера, функцията за четене на енкодера пише в променливата каквото е прихванала и толкоз. После в цикъла на главната програма си проверявам когато ми е удобно какво пише в тая променлива и ако намеря там да пише нещо - обработвам го и чак тогава нулирвам променливата. Така със сигурност не изпускам никакво движение. Що не си пуснеш едно прекъсване - голям кеф е и не е никак сложно - особенно пък на PICC-18. Ето как изглежда функцията на прекъсването - само за пример де:

void interrupt low_priority tc_int(void)
{
if((TMR0IE)&&(TMR0IF)){ //***** Timer 0 Code **** - prekyswane na 1.024ms
ReadRotationEncoder(); // Чете ротационния енкодер
TMR1IF=0; // Изчиства флага на прекъсването
}
}

Това "low_priority" определя това прекъсването да е с нисък приоритет, така че и то да може да бъде прекъснато от друго прекъсване - с по-важна функция и висок приоритет. То при тия 18-ки нали има приоритети. Сега се загледах че и аз точно за 18ф452 имам програма която ползва същия код, така че ако неще-поогледай и инициализирането на ПИК-а, може от там да е.

Айде успех!

Малко да добавя. Сега като се замисля - може при мен да работи добре заради логиката на обработка - с глобалната променлива. Щото като помислих малко, даже и 5 пъти - тоест 5 поредни прекъсвания функцията за четене на енкодера да е писала в променливата примерно посока +, то и 100 пъти да пише - все тая. Докато аз не си обработя променливата в главната програма и не нулирам променливата - ама чак след обработката - за мене си се води само 1 път посока +, Та може и заради това да се държи добре - ама то нали това е важнто в крайна сметка..

Айде наново успех...


Пет Авг 24, 2007 12:49 pm
Профил WWW
Ранг: Професионалист
Ранг: Професионалист
Аватар

Регистриран на: Сря Май 11, 2005 3:47 pm
Мнения: 534
Мнение 
steve: Сложи си един D-тригер, на входа D пускаш единия сигнал, а на CLK другия сигнал, на изхода получаваш сигнал за посоката. Четеш единия сигнал от енкодера само за скороста, а другия от изхода на тригера за посоката.


Пет Авг 24, 2007 1:22 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пон Юни 05, 2006 1:48 pm
Мнения: 4906
Местоположение: където небето среща земята, ракията е Jameson, а бирата Guinness
Мнение 
steve,
ако си намериш едно евтино и малко CPLD :) погледни сорса на пдф-то...
не претендирам за авторски права ;)
и си подбери подходящ клок :!:
П.П. незнам защо първата страница съществува въобще :? нещо се обози пдфпринтера


Прикачени файлове:
rot_enc.pdf [17.68 KiB]
263 пъти

_________________
... ако трети ден не ти се работи... това означава, че е сряда !
Пет Авг 24, 2007 2:45 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение 
Дай е-маил да ти пратя ако искаш една схема на квадратичен декодер, използват се Д-тригери и XOR елементи в качеството си на буфери и инвертори.


Пет Авг 24, 2007 3:10 pm
Профил
Ранг: Минаващ
Ранг: Минаващ
Аватар

Регистриран на: Пон Авг 20, 2007 11:13 am
Мнения: 13
Местоположение: Варна, България
Мнение 
MYXATA благодаря ти за кода, но едва ли ще си намеря тук във Варна нещо евтино, а и не ми се прескача в нови тъмни области от науката. Миналото лято с FPGA си играх на един курс и беше доста интересно, но за сега съм се спрял на PIC като евтини и достатъчни за моите скромни проекти.

MidNighT_SpiRiT ето ти един мейл : smstudio@data.bg . Много е вероятно да пробвам твоята схема, ако не успея с прекъсванията.

juzisound за момента процесора ми е в следното положение:
20MHz такат. В главната програма дето се върти до безкрайност проверявам за натиснат един бутон (ако е натиснат пускам и спирам плавно един светодиод с PWM) и проверявам за завъртане на енкодера (ако е завъртян надясно увеличава едно число и го пише на дисплея, ако е завъртян наляво го намалява и пак го пише). Това ще рече, че доста бързо се прави проверка за завъртане и се отчитат по 10 завъртания на един път, че и повече. Вероятно е шума, който ти не хващаш точно заради прекъсването от 1мс. Сега смятам да разбера как се пишат прекъсвания в С-то и ще видим какво ще се получи после.
Иначе проекта е доста по-сериозен от промяна на 1 число. Става дума за терморегулатор с цифров термометър на Майкрочип (TCN75), с възможност за настройка на температурата с този енкодер, опция за включване в определен час и изключване в друг, пускане и спиране на подсветката на дисплея с PWM и евентуално ако всичко това заработи както трябва ще добавя и EEPROM чип, който да събира данни и после да могат да се четат по RS232 за статистика примерно. Имах идея и за дистанционно управление (IR), но има само един сериен порт процесора, а не ми се пише софтуерен контрол за връзката. За часовника съм използвал един PIC12F629 (това ми се намираше, иначе щях да взема най-малкия и евтин), който да ми генерира сигнал с период 1 сек и 50% запълване, за да не ползвам таймери, които да пълня по няколко пъти и да си създавам допълнителни проблеми в големия процесор. Така с външно прекъсване просто си броя секундите и всичко е ОК.

_________________
"Има само две безкрайни неща, Вселената и човешката глупост. За първото не съм съвсем сигурен."
Алберт Айнщайн


Пет Авг 24, 2007 5:15 pm
Профил WWW
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 27 мнения ]  Отиди на страница 1, 2  Следваща

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 3 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни