|
Алгоритм для надійного зчитування показань енкодера кута повороту для ArduinoSAGE У процесі експериментів з аналогом плати Arduino Uno з'ясувалося, що немає достатньо надійного коду для читання показань механічного енкодера кута повороту, витягнутого з мишки. Представлено лише вагон і маленький візок полурабочие прикладів, які працюють вкрай нестабільно. Довелося усунути цю прикру неприємність і написати цей код. Проблема взаємодії з механічним енкодером полягає в тому, що треба ефективно вирішити проблему брязкоту контактів, яка властива цьому пристрою, так само як і кнопкку. Для кнопки досить влаштувати затримку в кілька мілісекунд. Для енкодера ж треба аналізувати його стан з високою частотою, і затримки тут відразу знизять ефективність. У прикладах досить недвозначно дають зрозуміти, що більш ефективний алгоритм дожен використовувати переривання. Чим я і скористався. Читання стану виходів енкодера здійснюється 2-мя переривань по зміні рівня. Кожна подія переривання забезпечується унікальним ідентифікатором розрядністю в 1 байт, чого цілком достатньо, якщо в основному циклі Arduino аналізувати надійшли події без додаткових затримок. Для ідентифікації використовується однобайтовое число зі знаком ( short ). Постійний інкремент його значення природно дає переповнення, але в цьому немає нічого страшного якщо знати як з такими числами правильно працювати. Зокрема, не дивлячись на переповнення, ми можемо ввести для кожного з двох чисел получающейся послідовності, якщо вони не надто віддалені один від одного, таку операцію як відстань між двома такими числами (функція EventsBetween ). Через кожну 1 мс здійснюється аналіз надійшли подій за цей період. Аналізується кількість подій (використовуємо EventsBetween ) і спеціальна сума, яка допомагає визначити, який рівень вхідного сигналу в даних подіях переважав. Будь-яка подія зниження рівня входить в суму як доданок, рівне -1 , а будь-яке подія підвищення рівня як доданок, рівне +1 . Таким чином, якщо сума вийшла негативною найімовірніше сталося зниження рівня, якщо сума позитивна - швидше за все відбулося підвищення рівня, якщо сума дорівнювала 0 , такий результат не несе ніякої певної корисної інформації про рівень (є просто шумом ) на даному вході і відкидається, а за рівень соответвуют виходу енкодера приймається попереднє значення. Тобто для розгляду подій в якості достовірного джерела інформації необхідно що-б були зафіксовані якісь події (лічильник кількості події не дорівнює 0 ) і сума за рівнями цих подій теж не дорівнювала 0 . Цей прийом ефективно вирішує проблему брязкоту контактів і не вимагає яких-небудь додаткових тимчасових затримок. Аналіз стану через кожні 1 мс показав високу ефективність. Тобто опитування енкодера йде реально з максимальною частотою з якою мікроконтролер здатний обробляти переривання, а аналіз інформації, накопиченої при обробці переривань відбувається з частотою близько 1 кГц, чого цілком достатньо. Під час налагодження алгоритму було видно, що за період 1 мс може відбуватися до 40-50 переривань і передбачені мною прийоми обробляють такий значний для мікроконтролера потік інформації досить ефективно. Схему підключення енкодера, думаю , немає сенсу тут показувати, в інтернеті такої інформації вистачає. Виходи енкодера підключені до другого і третього піну, що відповідає нульовому і першому переривань Arduino Uno . енкодер управляє яскравістю світлодіода, підключеного до дев'ятого виходу, що використовується в режимі ШІМ. // Encoder pins #define encoder0PinA 2 #define encoder0PinB 3 // LED pin #define LED_PIN 9 // Encoder inputs in high state unsigned short A_high, B_high; // Count of encoder events between two timer events unsigned short A_between = 0, B_between = 0; // Previous decission on encoder state unsigned short A_statePrev = 0, B_statePrev = 0; // Current event id for each encoder input short A_event = 0, B_event = 0; // Id of event that already accounted short A_eventPrev = 0, B_eventPrev = 0; // Timestamps for time measurements unsigned long timeCur, timePrev; // Value for estimation of dominant inputs state short A_level = 0, B_level = 0; int encoder0Pos = 127; int fadeAmount = 10; // Number of events between two event id's int EventsBetween (short iCur, short iPrev) {if ((iCur <0)&&(iPrev <0)) {return (int (iCur) + 256) - (int (iPrev) + 256); } Else if (iCur <0) {return (int (iCur) + 256) - iPrev; } Return iCur - iPrev; } // Keep value in limits int clamp (int value, int low, int high) {if (value Дата останнього оновлення: 31-5-19 07:02:17 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright © 2005-2019 SAGE. Всі права захищено. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||