Инкрементальный энкодер представляет собой механическое устройство (датчик) преобразующее угол поворота вала (ручки) в электрические сигналы. Энкодер имеет три вывода, или пять в зависимости от наличия встроенной кнопки. Здесь я рассматриваю наиболее распространенные энкодеры, которые встраивают в бытовую аппаратуру, например, для регулировки громкости, навигации в меню и т.д. В отличие от переменного резистора, положение ручки энкодера меняется дискретно, “щелчками”, при этом происходит несколько коммутаций, последовательность которых зависит от направления вращения. На один полный оборот ручки может приходиться различное количество дискретных положений (12, 20, 24), в зависимости от модели энкодера.
На рисунке ниже представлена функциональная схема поясняющие принцип действия энкодера.
Как видно из временных диаграмм, при повороте на одно дискретное положение (на один “щелчок”), на выводах A и B формируются отрицательные импульсы (полярность импульсов зависит от схемы подключения), сдвинутые по фазе между собой. Сдвиг фаз зависит от направления вращения. Из временной диаграммы можно выделить четыре состояния, которые составляют период одного дискретного изменения (“щелчка”), длительность периода варьируется примерно от 2 мс до 4 мс.
На следующем рисунке представлена схема подключения энкодера к микроконтроллеру:
Выводы A и B энкодера необходимо подтянуть к линии питания +5В с помощью резисторов, также необходимо установить конденсаторы C1 и C2 которые уменьшают влияние дребезга контактов.
Состояние энкодера можно определить используя прерывания по изменению сигнала на выводах микроконтроллера или путем периодического опроса через равные промежутки времени, сравнивая текущее состояние с предыдущим сохраненным значением. Сначала рассмотрим вариант периодического опроса.
Ниже представлен код программы, в которой реализован периодический опрос состояния выводов энкодера. Опрос состояний выводов А и B энкодера выполняется в подпрограмме обработки прерываний, которая периодически вызывается по переполнению таймера TMR0 (см. Таймеры. Организация временной задержки). В моем варианте таймер переполняется примерно через 1 мс, то есть энкодер опрашивается каждую миллисекунду.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
#include <p16f628a .INC> LIST p=16F628A __CONFIG H'3F18' ;конфигурация микроконтроллера flag equ 20h ;перечисление регистров общего назначения flag1 equ 21h ;присвоение названий адресам регистров shet equ 22h ; shet1 equ 23h ; W_TEMP equ 7Eh ; STATUS_TEMP equ 7Fh ; #DEFINE enc1 PORTB,4 ;присвоение названий линиям ввода-вывода #DEFINE enc2 PORTB,5 ;микроконтроллера ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма обработки прерываний org 0004h ;начать выполнение подпрограммы с адреса 0004h movwf W_TEMP ;сохранение значений ключевых регистров swapf STATUS,W ; clrf STATUS ; movwf STATUS_TEMP ; btfsc enc1 ;опрос состояний выводов энкодера и сохранение bsf flag,0 ;полученных значений в регистр flag btfss enc1 ;сохранение значения вывода enc1 в 0-й бит bcf flag,0 ;сохранение значения вывода enc2 в 1-й бит btfsc enc2 ; bsf flag,1 ; btfss enc2 ; bcf flag,1 ; btfss flag,2 ;проверка предыдущего состояния выводов goto vih ;энкодера (2-й и 3-й биты регистра flag) btfss flag,3 ;если оба значения не равны 1 переходим goto vih ;на метку vih, для выхода из обработчика btfss flag1,0 ;проверка флага (0-й бит регистра flag1) goto i2 ;инкремента/декремента регистра shet incf shet1,F ;если флаг не установлен-переходим (метка i2) movlw .3 ;на проверку факта поворота ручки энкодера xorwf shet1,W ;при установленном флаге инкрементируем btfss STATUS,Z ;регистр shet1, проверяем на равенство goto vih ;числу 3, если не равно-переходим на метку bcf flag1,0 ;vih, для выхода из обработчика clrf shet1 ;если shet1 равен 3-очищаем регистр и ;сбрасываем флаг инкремента/декремента ;регистра shet i2 btfsc flag,0 ;определение направления вращения ручки goto i1 ;энкодера, если enc1=1 переходим на метку i1 btfss flag,1 ;если enc1=0 и enc2=1 произошел поворот goto vih ;в положительную сторону (условно) ;соответственно далее по ходу кода производим ;инкремент регистра shet ;состояние enc1=0 и enc2=0 игнорируется- ;переходом на метку выхода vih incf shet,F ;инкемент регистра shet, максимальное значение movlw .0 ;ограничивается на уровне 255 xorwf shet,W ; btfss STATUS,Z ; goto vih1 ; movlw .255 ; movwf shet ; goto vih1 ;переход на метку vih1 i1 btfsc flag,1 ;определение направления вращения ручки goto vih ;энкодера, если enc1=1 и enc2=0 произошел ;поворот в отрицательную сторону (условно) ;соответственно далее по ходу кода производим ;декремент регистра shet ;состояние enc1=1 и enc2=1 игнорируется- ;переходом на метку выхода vih decf shet,F ;декремент регистра shet, минимальное значение movlw .255 ;ограничивается на уровне 0 xorwf shet,W ; btfss STATUS,Z ; goto vih1 ; clrf shet ; vih1 bsf flag1,0 ;установка флага инкремента/декремента регистра shet bsf flag1,1 ;установка флага регистрации поворота энкодера ;для дальнейшего опроса в основной программе vih rlf flag,F ;сдвиг содержимого регистра flag rlf flag,F ;влево на 2 бита bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0 movlw .15 ;запись числа 15 в регистр таймера TMR0 movwf TMR0 ;равнозначно временной задержке примерно 1мс swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров movwf STATUS ; swapf W_TEMP,F ; swapf W_TEMP,W ; ; retfie ;выход из подпрограммы прерывания ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start movlw b'00000000' ;запись нулей в выходные защелки порта B movwf PORTB movlw b'00000111' ;выключение компараторов movwf CMCON bsf STATUS,RP0 ;настройка линий ввода\вывода порта B movlw b'00110111' movwf TRISB ;запись двоичного числа 11010001 в регистр movlw b'11010001' ;OPTION_REG, тем самым устанавливаем внутренний movwf OPTION_REG ;источник тактового сигнала для TMR0 bcf STATUS,RP0 ;включаем предделитель перед TMR0 ;устанавливаем коэффициент предделителя 1:4 clrf shet ;очистка дополнительных регистров clrf shet1 ; clrf flag1 ; clrf TMR0 ;очистка регистра таймера TMR0 bcf INTCON,T0IF ;сброс флага прерывания по переполнению TMR0 bsf INTCON,T0IE ;разрешение прерываний по переполнению TMR0 bsf INTCON,GIE ;глобальное разрешение прерываний a1 btfss flag1,1 ;опрос флага регистрации поворота энкодера goto a1 ;флаг регистрации равен нулю: переход на метку a1 bcf flag1,1 ;флаг равен единице: сброс флага регистрации movf shet,W ;вывод содержимого регистра shet на цифровое call vivod ;табло goto a1 ................. ;подпрограммы вывода содержимого ................. ;регистра shet на семисегментные индикаторы ................. ; end ;конец всей программы ;</p16f628a> |
Внутри обработчика прерываний сначала сохраняется текущее состояние выводов энкодера, для этого используется дополнительный регистр flag, содержимое которого всегда перед выходом из обработчика сдвигается влево на два бита, таким образом сохраняется предыдущее состояние выводов энкодера. После сохранения текущего состояния в 0-й и 1-й бит регистра flag, осуществляется проверка предыдущего состояния, то есть анализируются 2-й и 3-й биты. Алгоритм следующий: если предыдущее состояние обоих выводов соответствовало логической единице, проверяем текущее сохраненное значение (биты 0,1 регистра flag), если значение битов равно 0 и 1, произошел поворот в одну сторону, если значение равно 1 и 0, произошел поворот в противоположную сторону. После определения факта поворота происходит инкремент или декремент регистра shet, содержимое которого (число от 0 до 255) в основной программе выводится на семисегментные индикаторы. Инкремент производится до числа 255 и ограничивается на этом значении, даже при дальнейшем повороте ручки энкодера, то же самое и при декременте до 0.
Если предыдущее состояние обоих выводов не соответствует 1, просто выходим из обработчика, также смещая содержимое регистра flag влево. Это необходимо чтобы пропустить все остальные возможные состояния выводов энкодера, то есть для определения направления вращения используется половина периода одного дискретного изменения (два состояния из четырех возможных).
При использовании такого алгоритма выявились некоторые недостатки, сам факт поворота ручки определялся стабильно, но из-за наличия дребезга контактов в конце периода одного дискретного изменения (после “щелчка”), происходило повторное определение факта поворота, причем в обратную сторону. То есть после инкремента регистра shet происходил декремент и наоборот. Чтобы избежать этого, после инкремента/декремента регистра shet, я дополнительно добавил условие для многократной проверки состояния выводов энкодера на соответствие высокому логическому уровню. После инкремента/декремента shet, перед выходом из обработчика прерывания устанавливается флаг (0-й бит) в дополнительном регистре flag1. При последующих входах в обработчик, после проверки предыдущего состояния и соответствия выводов энкодера высокому логическому уровню, по установленному флагу в регистре flag1 происходит инкремент регистра shet1. Если его содержимое не равно числу 3 происходит выход из обработчика. Таким образом, после факта поворота, следующее определение состояния энкодера будет выполняться, при условии трехкратной фиксации высоких логических уровней на выводах энкодера, после чего регистр shet1 обнуляется и сбрасывается флаг регистра flag1.
После изменения значения регистра shet в обработчике прерываний, дополнительно устанавливается флаг регистрации поворота энкодера flag1,1, который опрашивается в основной программе, если флаг установлен вызывается подпрограмма vivod, для вывода содержимого регистра shet на семисегментные индикаторы.
Теперь рассмотрим программу опроса энкодера основанную на прерываниях по изменению уровня на входах микроконтроллера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
#include <P16F628A.INC> LIST p=16F628A __CONFIG H'3F18' ;конфигурация микроконтроллера flag equ 20h ;перечисление регистров общего назначения flag1 equ 21h ;присвоение названий адресам регистров shet equ 22h ; ; W_TEMP equ 7Eh ; STATUS_TEMP equ 7Fh ; #DEFINE enc1 PORTB,4 ;присвоение названий линиям ввода-вывода #DEFINE enc2 PORTB,5 ;микроконтроллера ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма обработки прерываний org 0004h ;начать выполнение подпрограммы с адреса 0004h movwf W_TEMP ;сохранение значений ключевых регистров swapf STATUS,W ; clrf STATUS ; movwf STATUS_TEMP ; btfsc enc1 ;опрос состояний выводов энкодера и сохранение bsf flag,0 ;полученных значений в регистр flag btfss enc1 ;сохранение значения вывода enc1 в 0-й бит bcf flag,0 ;сохранение значения вывода enc2 в 1-й бит btfsc enc2 ; bsf flag,1 ; btfss enc2 ; bcf flag,1 ; btfss flag,0 ;Проверка текущих сохраненных значений состояния goto i3 ;выводов энкодера btfss flag,1 ;если enc1=1 и enc2=1 сбрасываем флаг готовности, goto i3 ;иначе переходим на метку i3 bcf flag1,1 ; i3 btfsc flag1,1 ;проверка флага готовности, если флаг установлен goto vih ;переходим на метку vih btfsc flag,0 ;флаг готовности сброшен:Проверка текущих сохраненных goto vih ;значений состояния выводов энкодера btfsc flag,1 ;если enc1=0 и enc2=0 переходим на метку i2, goto vih ;иначе переходим на метку vih i2 btfsc flag,2 ;проверка предыдущих состояний выводов энкодера goto i1 ;если enc1=1 переходим на метку i1, btfss flag,3 ;если enc1=0 и enc2=1 произошел поворот goto vih ;в положительную сторону (условно) ;соответственно далее по ходу кода производим ;инкремент регистра shet ;состояние enc1=0 и enc2=0 игнорируется- ;переходом на метку выхода vih incf shet,F ;инкемент регистра shet, максимальное значение movlw .0 ;ограничивается на уровне 255 xorwf shet,W ; btfss STATUS,Z ; goto vih1 ; movlw .255 ; movwf shet ; bsf flag1,1 ;произошел инкремент регистра shet (поворот энкодера) ;устанавливаем флаг готовности goto vih1 ;переход на метку vih1 i1 btfsc flag,3 ;проверка предыдущих состояний выводов энкодера goto vih ;если enc1=1 и enc2=0 произошел ;поворот в отрицательную сторону (условно) ;соответственно далее по ходу кода производим ;декремент регистра shet ;состояние enc1=1 и enc2=1 игнорируется- ;переходом на метку выхода vih decf shet,F ;декремент регистра shet, минимальное значение movlw .255 ;ограничивается на уровне 0 xorwf shet,W ; btfsc STATUS,Z ; clrf shet ; bsf flag1,1 ;произошел инкремент регистра shet (поворот энкодера) ;устанавливаем флаг готовности vih1 bsf flag1,0 ;установка флага регистрации поворота энкодера ;для дальнейшего опроса в основной программе vih rlf flag,F ;сдвиг содержимого регистра flag rlf flag,F ;влево на 2 бита exxit movf PORTB,W ;чтение порта B, для устранения несоответствия bcf INTCON,RBIF ;сброс флага прерываний по изменению уровня на RB4-RB7 swapf STATUS_TEMP,W ;восстановление содержимого ключевых регистров movwf STATUS ; swapf W_TEMP,F ; swapf W_TEMP,W ; ; retfie ;выход из подпрограммы прерывания ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start movlw b'00000000' ;запись нулей в выходные защелки порта B movwf PORTB ; movlw b'00000111' ;выключение компараторов movwf CMCON ; bsf STATUS,RP0 ;настройка линий ввода\вывода порта B movlw b'00110111' ; movwf TRISB ; bcf STATUS,RP0 ; clrf flag1 ;очистка дополнительных регистров clrf shet ; movf PORTB,W ;чтение порта B, для устранения несоответствия bsf INTCON,RBIE ;разрешение прерываний по изменению уровня на RB4-RB7 bsf INTCON,GIE ;глобальное разрешение прерываний a1 btfss flag1,0 ;опрос флага регистрации поворота энкодера goto a1 ;флаг регистрации равен нулю: переход на метку a1 bcf flag1,0 ;флаг равен единице: сброс флага регистрации movf shet,W ;вывод содержимого регистра shet на цифровое call vivod ;табло goto a1 ................. ;подпрограммы вывода содержимого ................. ;регистра shet на семисегментные индикаторы ................. ; end ;конец всей программы ; |
Выводы энкодера подключены к линиям RB4, RB5, в микроконтроллере включены прерывания по изменению уровня на входах RB4-RB7. Линии RB6, RB7 настроены на выход, чтобы не вызывать ложных прерываний, так как в данном микроконтроллере нельзя разрешать прерывания по отдельности на каждую линию. В обработчике прерываний происходит сохранение текущих состояний выводов энкодера в 0-й и 1-й биты регистра flag, далее идет проверка сохраненных значений, если биты 0 и 1 равны нулю, происходит переход на метку i2, где проверяется предыдущее состояние выводов энкодера записанных в биты 2 и 3 регистра flag. Если значение битов равно 0 и 1 произошел поворот в одну сторону, если 1 и 0 в другую сторону, состояние 0-0 и 1-1 игнорируется, в этом случае происходит выход из обработчика прерываний. После определения факта поворота происходит изменение значения счетчика shet, а также установка флага регистрации поворота энкодера flag1,0. Этот флаг опрашивается в основной программе, и если равен единице вызывается подпрограмма vivod, для вывода содержимого регистра shet на семисегментные индикаторы.
Для лучшей стабильности реализовано игнорирование состояний выводов энкодера после определения факта поворота. То есть после изменения значения регистра shet, устанавливается флаг готовности flag1,1. Состояние выводов игнорируется до момента, когда оба вывода не установятся в единицу, то есть по окончанию периода одного дискретного изменения. Как только значение обоих выводов будут равны единице, флаг готовности будет сброшен, и разрешен дальнейший анализ состояний выводов энкодера. Важное значение имеет наличие конденсаторов на выводах энкодера, которые уменьшают дребезг контактов, улучшая работоспособность данной программы.
Вышеприведенные программы тестировались на микроконтроллере PIC16F628A, тактовый генератор внутренний на 4 МГц, энкодер на 20 дискретных положений. Для отображения содержимого регистра shet, использовано цифровое табло из семисегментных индикаторов на драйвере MC14489AP. Результат представлен на видеоролике ниже.
Не могу написать подпрограмму вывода регистра на семисегментный индикатор, если есть у кого, выложите, пожалуйста.
modul83@yandex.ru и напиши, что за чип…
Может кто посоветовать схему управления асинхронным двигателем на микроконтроллере с энкодером?
А энкодер какую роль должен выполнять? Как именно должен управляться двигатель?
энкодер должен будет задавать определенный угол для поворота двигателя
Асинхронному двигателю нельзя задавать определенный угол поворота, асинхронный двигатель просто вращается, можно регулировать только частоту вращения. Может вы имели в виду сервопривод?
Ну задача такова, что у меня имеется двигатель с редуктором, который в свою очередь должен контролировать положение мембраны в газовом редукторе.
Ну в таком случае (с асинхронным двигателем) на выходе редуктора (на мембране) надо ставить датчик положения (потенциометр, переменный резистор) чтобы отслеживать угол поворота, у обычного переменного резистора диапазон поворота около 270 градусов, то есть мембрана будет поворачиваться только в этом диапазоне (не более 270 град.). Без датчика положения (обратной связи) нельзя будет узнать положение.
А можете какой нибудь аналог схемы посоветовать, буду очень благодарен!
Аналог посоветовать не могу, так как не встречался с такими регуляторами.
Я вижу этот регулятор так: ставим на мембрану переменный резистор который подключается к АЦП микроконтроллера, для отображения угла поворота подключаем дисплей к микроконтроллеру, с помощью энкодера выставляем нужный угол на дисплее, далее микроконтроллер включает один из двух пускателей для запуска асинхронного двигателя, в соответствии с направлением поворота, и исходя из показаний АЦП, следит за углом и отключает двигатель по достижении нужного угла. Энкодер выступает здесь в роли устройства ввода данных (число) в микроконтроллер.
Ну вообще тут могут быть разные варианты управления, например на дисплей выводить текущий угол с датчика положения, а вращая энкодер добиваться нужного угла.
Hi There,
Can you please write the code under MikroC and share here.
Thanks,
Leem.
Hi, unfortunately I’m not programming in MicroC, so I can not help.
Здраствуйте.
Xотел спросить можна переделать немного програму штоб она не изменяла регистр shet, а изменяла логические уровни на двух выводах (имитацыя кнопок).
Cпасибо.
Здравствуйте, поменять можно как угодно, вы не уточнили как именно, например в случае инкремента что должно происходить, если изменение уровня на выводе, то какой уровень выставлять, и что делать при следующем инкременте? Пишите конкретнее.
Имитацыя работы кнопок когда нет возможности изменить програму.
Надо имитировать две кнопки плюс и минус чтоб если крутыш в одну сторону на одном выходе логический ноль крутиш в другую на втором выводе анагогично.
Кнопка может иметь 2 состояния, нажата и отжата, соответственно получаем два логических уровня низкий и высокий. Ладно если произошел инкремент, ставим низкий уровень на выводе, а что дальше, так и оставляем низкий уровень? То есть по вашему получаем имитацию нажатия кнопки, а имитация отжатия в каком случае должна происходить, при следующем инкременте?
Да должна как обычная кнопка нажали отпустили еслы надо ещо нажали отпустили.
а для какого кода надо сделать изменения? в статье я приводил 2 версии.
Как на меня то второй вариант мне больше нравится.
Вот поправил
Огромное спасибо.
Здравствуйте, а для чего в программе в 123 строке подпрограмма program?
В Протеусе работает , хочу перенести на 12f675 чтоб вышло компактное устройство, которое можно подключить к уже готовому устройству на кнопках.
Подпрограмму program я условно указал, например, если еще какое то действие нужно выполнить по повороту энкодера, но в вашем случае как я понял это не нужно, можете убрать этот код, но в основной программе все равно надо что-то делать, или просто бесконечный круговой цикл поставить.
Чет туго у меня с переводом на 675. Я думаю что проблема с конфигурацией битов.
Если можете я б скинул файл.
Попробуйте этот код
Спасибо в протеусе работает буду делать теперь в железе, если интересно то потом могу скинуть печатную плату и фото устройства может у вас получится статья.
получилось?
Выложите, пожалуйста, исходный код для вашего устройства с экодером из видео.
DOBROE VREMYA SUTOK . TEMA ESHE AKTUALNA . MOJETE PODSKAZAT KAK MOJNO PROVERIT ENCODER V PROTEUSE?
Добрый вечер.
Посоветуйте как собрать схему управления отреза материала относительно длины заготовки и положения рисунка на заготовке (чтобы не перерезать повторяющиеся рисунок).
Есть пример китайского аппарата (внешни).