Никак не поборю энкодер

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Добрый день\ночь.
Знаю, что тема уже избита, однако, перечитав кучу сообщений и статей, так и не смог накодить ничего вменяемого.
Выдрал из сторого ЭЛТ монитора энкодер (как в этой статье, только контакты выведены под 90 градусов)
Задача сделать обработчик энкодера, чтоб по щелчку происходило что-то, например, загорался один из 8 светодиодов (типа как счетчик).
Энкодер имеет, как и в статье, 24 щелчка на оборот, каждый щелчек - смена 4 состояний выводов.
Честно говоря, я не совсем понял, как в статье di halt его обрабатывает. Код, судя по всему, для энкодера без щелчков. Если нет, то зачем делается перебор всех 4 комбинаций состояний энкодера.
Я сделал следующим образом:
Изображение

increase\decrease - изменение значения регистра порта, на котором висит 8 светодиодов
newstate в коде обозначен как просто state

Код: Выделить всё

.include "m8def.inc"
.include "macro.asm"
.def temp	=	r16
.def oldstate	=	r17
.def state	=	r18
.cseg 

.org	0 
rjmp	reset
.org	$009
rjmp	T0OVF

reset:      
outi SPH,High(RAMEND)
outi SPL,Low(RAMEND)
;-------------------------------------------------------
outi DDRD,	0xff			;Порт D - выход
outi PORTD,	0b00000001		;Зажигаем 0 пин порта
;-------------------------------------------------------
outi DDRB,	0b00000000		;Порт В - вход
outi PORTB,	0b00000000		;В Hi-Z
;-------------------------------------------------------
outi TCCR0,	(1<<CS00 | 1<<CS02)	;T0 FastPWM, presc:1024
outi TIFR,	(1<<TOV0)
outi TIMSK,	(1<<TOIE0)
;-------------------------------------------------------
sei
in oldstate, pinb	;Тут всегда 0х00. Так устроен этот энкодер
;-------------------------------------------------------
main:
rjmp main           
;-------------------------------------------------------
T0OVF:
in state, pinb
	cp state, oldstate
		breq	reti_	;Если состояние не изменилось - выходим из прерывания
		brne	check
check:
	cpi state, 0x10		;Крутанули назад
		breq nazad
	cpi state, 0x01
		breq vpered	;Крутанули вперед
rjmp reti_
;----------------------
vpered:
in temp, portd			;Взяли значение из светодиодного порта и увеличили
	inc temp
	out portd, temp
	rcall delay
rjmp reti_
;----------------------
nazad:
in temp, portd			;То же, но наоборот - уменьшили
	dec temp
	out portd, temp
	rcall delay
rjmp reti_			;Знаю, что это тут не обязательно, просто так легче ориентироваться

reti_:
in state, pinb			;Не выходим из прерывания, пока энкодер не дощелкнется до конца и не станет 0х00
	cp state, oldstate
	brne reti_
reti
;-------------------------------------------------------
delay:        			;Задержка от дребезга 0,05сек
          ldil  R0, $65
WGLOOP0:  ldil  R1, $A4
WGLOOP1:  dec  R1
          brne WGLOOP1
          dec  R0
          brne WGLOOP0
          ldil  R0, $01
WGLOOP2:  dec  R0
          brne WGLOOP2
          nop
          nop
ret
На portD висят светодиоды
На portB,0 и 1 висят ноги энкодера

В макро

Код: Выделить всё

.macro   outi
   ldi   temp,@1
   out   @0,temp
.endm

.macro LDIL		;Т.к регистры r0-r15 ущербные, юзаю для них такой макрос
  push r16
  ldi r16, @1
  mov @0, r16 
  pop r16
.endm
В итоге, эта дрянь работает очень странно:
ютуб
Щелчки почти не слышны в начале, потом, похоже, что стол вошел в резонанс и стало слышно :)
Я пробовал разные задержки на дребезг, пробовал их вообще убрать и сделать предделитель таймера 1024, но, результат практически такой же.
Понимаю, что разбирать чужие ошибки влом, но может кто-нибудь подскажет, как обрабатывать энкодеры с щелчками? Или пример какой (лучше, если на асме)
Спасибо.

P.S На видео, видимо, сработал эффект показа, но после ресета периодически контроллер просто перестает реагировать на энкодер пока не отрубишь питалово или не прошьешь его заново. Странно

P.P.S Забыл написать, камень - AVR ATmega8
Последний раз редактировалось warezzzok Вс май 12, 2013 02:28:58, всего редактировалось 1 раз.
Реклама
SPY
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Вс авг 20, 2006 20:06:29
Откуда: Брест

Сообщение SPY »

http://www.cqham.ru/swl_receiver.htm
синтез с исходниками , который я собирал.
Реклама
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Спасибо, добрый человек :)
Посмотрел исходники - сломал мозг окончательно, тем более, у вас PIC, а у меня AVR (прошу прощения - забыл указать). Знаю, что алгоритм одинаков, но тут с авр-овским ассемблером не разберусь до конца :(
Друг Кота
Аватара пользователя
Сообщения: 25587
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Даже и не стал смотреть код. Принял алгоритм как он выше кода нарисован.
1. В прерываниях не обрабатывают механические устройства ввода, за исключением подавления их дребезга. После зачистки от дребезга (защелкивания состояния энкодера) по прерываниям от таймера (никаких зависаний в прерывании быть не может), обработка (машина состояний) энкодера производится в основном цикле.
2. В алгоритме не использовано СТАРОЕ состояние энкодера, а именно оно определяет инкремент или декремент произошел.
Реклама
Эиком - электронные компоненты и радиодетали
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Такой вариант глянь.....
http://asis-kbr.ru/forum/viewtopic.php?f=13&t=141
Реклама
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

2. В алгоритме не использовано СТАРОЕ состояние энкодера, а именно оно определяет инкремент или декремент произошел.
Дак oldstate - это и есть предидущее состояние, если оно не равно состоянию в текущий момент времени, начинается алгоритм выяснения в какую сторону крутится.
Такой вариант глянь.....
Спасибо, поглядел. Попробую реализовать на асме - без задержки даже лучше.

Кстати, вчера переписал все в нуля, сделал опрос не прерыванием, а в цикле с задержкой. Вроде получилось, хотя и очень глючно.
Реклама
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Не хочется создавать новую тему, напишу здесь, тем более, что задача та же осталась :)

Наговнокодил что-то с задержками, оно даже вроде заработало, хотя и кривовато пока, ну да не суть.
Четко вылезла другая проблема:
ютуб
В 2 словах - после ресета, очень часто контроллер зависает (не реагирует ни на что) и так пока не протыкатешь ресет n-раз.
Иногда, когда все работает, зависает спустя некоторое время (н видео 0:47).
На этой меге были не правильно прошиты фьюзы, потом через avrdude и avr burn-o-mat делал сброс фьюзов на дефолт. Именно дефолтные фьюзы, как были при покупке меги я не нашел, может быть и сейчас стоит криво. Вообще, что это может быть? Вроде никаких "мертвых" циклов не делал

Код: Выделить всё

.include "m8def.inc"
.include "macro.asm"
.def temp      =   r16
.def oldstate   =   r17
.def state      =   r18
.cseg 
.org   0 
 rjmp   reset
reset:      
outi SPH,High(RAMEND)       ;Инициализируем стек
outi SPL,Low(RAMEND)      ;Инициализируем стек
;-------------------------------------------------------
outi DDRD,   0xff         ;Порт D как выход   |   Диоды
outi PORTD,   0b00001000      ;Порт D.1 лог.1      |   Диоды
;-------------------------------------------------------
outi DDRB,   0b00000000      ;Порт B как вход   |   Энкодер
outi PORTB,   0b00000000      ;Порт В - Hi-Z      |   Энкодер
in oldstate, pinb
;-------------------------------------------------------
main:
in state,pinb
   cp state, oldstate
      breq main
      brne case
rjmp main  
case:
   cpi state, 0x00
      breq state0
   cpi state, 0x01
      breq state1
   cpi state, 0x10
      breq state2
   cpi state, 0x11
      breq state3
rjmp main
state0:      ;энкодер 0, старое значение 1 (назад) или 2 (вперед)
cpi oldstate, 0b00000010
   breq nazad
cpi oldstate, 0b00000001
   breq vpered
rjmp main
state1:      ;энкодер 1, старое значение 3 (назад) или 0 (вперед)
cpi oldstate, 0b00000000
   breq nazad
cpi oldstate, 0b00000011
   breq vpered
rjmp main
state2:      ;энкодер 2, старое значение 0 (назад) или 3 (вперед)
cpi oldstate, 0b00000011
   breq nazad
cpi oldstate, 0b00000000
   breq vpered
rjmp main
state3:      ;энкодер 3, старое значение 2 (назад) или 1 (вперед)
cpi oldstate, 0b00000001
   breq nazad
cpi oldstate, 0b00000010
   breq vpered
rjmp main
vpered:
in temp, portd
   inc temp
   out portd, temp
   in oldstate, pinb
   rcall delay
rjmp main
nazad:
in temp, portd
   dec temp
   out portd, temp
   in oldstate, pinb
   rcall delay
rjmp main
delay:   ;70 миллисекунд (0,07с)
            ldil  R0, $0B
WGLOOP0:  ldil  R1, $D3
WGLOOP1:  dec  R1
          brne WGLOOP1
          dec  R0
          brne WGLOOP0
          ldil  R0, $01
WGLOOP2:  dec  R0
          brne WGLOOP2
          nop
ret
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 330
Зарегистрирован: Чт июн 23, 2011 07:55:51

Сообщение korsaj »

Я бы вот так не делал

Код: Выделить всё

cpi oldstate, 0b00000010
   breq nazad
cpi oldstate, 0b00000001
   breq vpered
и так

Код: Выделить всё

case:
   cpi state, 0x00
      breq state0
   cpi state, 0x01
      breq state1
   cpi state, 0x10
      breq state2
   cpi state, 0x11
      breq state3
т.к. все пины порта на вход, мало ли чего там будет. Вы сначала выделите нужные пины по маске, а уж затем сравнивайте.
Попробуйте промоделируйте ситуацию если у вас oldstate вдруг станет 0b00100001. А именно такое и происходит т.к. у вас входы в 3-м состоянии и любая помеха может изменить состояния порта.
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Спасибо вам за помощ, все оказалось именно как вы и написали из pinb читался мусор.
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Сижу вот щас, играюсь с разными вариантами обработчика энкодера, переделал программу как у ДиХальта в статье - за 1 тик считвается 4 состояния и потом результат делится на 4.
Но никак не могу понять какую задержку делать - делаю маленькую - начинает регистрироваться дребезг, делаю большую - начинает пропускать некоторые состояния, пока контроллер слоупочит в задержке и, вместо 4 состояний, регистрирует меньше. Так и должно быть, или, может быть, это энкодер убитый в хлам уже и он просто так работает? К сожаленю, осцилографом не разжился пока, чтоб все точки расставить.
Мучитель микросхем
Аватара пользователя
Сообщения: 411
Зарегистрирован: Вс авг 10, 2008 19:35:49
Откуда: Евпатория

Сообщение s_black »

Здесь ещё посмотрите.
Контактная информация:
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

Алгоритм ДиХалта дилетанский и ущербный. Дребезг механического энкодера нельзя побороть задержками, т.к. длительность импульсов может быть сильно короче, чем дребезг. Выдавать 4 импульса на один щелчок -вообще глупость. По моему опыту, лучше всего работает опрос энкодера в прерывании с фиксированной частотой (1-2 кГц), с последовательным анализом состояний с учетом возможного дребезга. Но это сложно.
Открыл глаза
Сообщения: 67
Зарегистрирован: Вт дек 04, 2012 21:35:56

Сообщение warezzzok »

Честно говоря, мне, почему-то кажется, что тратить целый таймер с прерыванием на обработку энкодера - жирновато как-то. Им всегда можно придумать другое занятие. А вот сделть проверку без задержки - как-то более приемлемо, хотя, я так и не вкурил суть :(
Щас пока остановился на варианте обработки только первого по счету состояния энкодера, а остальные 3 - по боку. Вроде даже работает, хотя и проскальзывает иногда. Пытался вылавливть момент, когда оканчивается дребезг в самом крайнем состоянии энкодера минуя задержки, но что-то быстро запутался в алгоритме :)
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

Ну так можно использовать этот таймер одновременно и для других задач, например, для подсчета времени, разных длинвых задержек, динамической индикации, звукового сигнала (зуммера) и пр.
Друг Кота
Аватара пользователя
Сообщения: 25587
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Это написано в обработчике системного таймера (таймер на всякую всячину...) с интервалом прерываний 0,256 мс (в другом изделии 0,512 мс - особой разницы нет)
Код в АСМе PIC18
С учетом комментов несложно перевести в чистый алгоритм.

Код: Выделить всё

; антидребезг и обработка энкодера
		clrf           inc_dec                        ; сбрасываем переменную исполнения
		movf		PORTB, w                    ; чтение порта к которому подключен энкодер
		andlw		b'00000011'        ; маска на разряды подключения
		movwf		temp_enc            ; сохраняем текущее состояние ПИНОВ
		xorwf		stack_enc, w        ; сравниваем с  предыдущим (стек пинов)
		movff		temp_enc, stack_enc    ; заносим текущее в стек
		btfss		STATUS, Z
		retfie	FAST		                        ; выход если состояние пинов изменились(дребезг)
		movf		temp_enc, w
		xorwf		old_enc, w            ; если дребезг закончился, то сравниваем текущее со старым ЭНКОДЕРОМ
		btfsc		STATUS, Z
		retfie	FAST		                           ; выход с 0 если старое состояние = новому
		movf		old_enc, f                     ; тест старого состояния на 0
		movff		temp_enc, old_enc     ; перенос текущего в старое
		btfss		STATUS, Z
		retfie	FAST		                          ; выход с 0 если старое состояние не ноль
		bcf		STATUS, C
		rlcf		old_enc, w	               ; умножаем на 2
		addlw		0xFD		         ; вычитаем 3
		movwf		inc_dec               ; сохраняем в переменной исполнения
		retfie	FAST		                          ; выход с плюс 1 или минус 1 в переменной исполнения
Применяем четыре переменные:
Стек энкодера (прежнее состояние) - защита от дребезга (текущее состояние = прежнему, значит дребезг окончен)
Текущее состояние
Старое состояние - предыдущее состояние с учетом защиты от дребезга
Переменная исполнения - при правом вращении равна +1, при левом равна -1
Но последняя переменная образуется корректно только если энкодер подключен к двум младшим разрядам порта, иначе придется привести переменные к этому виду сдвигом.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

:lol: может сейчас по дилетантски напишу, но делал Н-кодер по Ди-Халту. Тоже долго разбирался с его писаниной, очень не нравится, что он для новичков хорошо объясняет, но все время скатывается до конечных автоматов и диспетчера задач... Я не такой матерый программер, чтобы все это усвоить... =)))
Потом, еще и на Си про Н-кодеры у него написано.
Пришлось просто разбирать описание работы его алгоритма, прописывать все в конспекте, а когда дошло, что он хотел сказать, то все написал на ассемблере! =) И отличненько получилось. Подключил то, что было под рукой, т.е. н-кодер от ролика мышки, он щелкает. Все работает и управляет положением сервопривода, используются и таймеры и прерывания по таймерам, там много для чего.
Одно могу еще добавить, чтобы было меньше глюков, надо ставить внешние подтягивающие резисторы к плюсу, иначе шумит сильно (внутренних не хватает).

Кому может надо, и есть желание у кого поразбираться в исходнике, прикрепляю. Там много комментариев, кроме самого Н-кодера... =))))) Было лень...
Вложения
ServEnkd.asm
(ассемблер)
(8.17 КБ) 311 скачиваний
Станислав
Потрогал лапой паяльник
Сообщения: 300
Зарегистрирован: Вт мар 13, 2012 07:24:30

Сообщение lazer »

Доброго времени суток всем. Тема действительно сложная, если хочется добиться очень хорошей работы валкодера. Я тоже очень много вариантов рассматривал и пробовал, голову поломал изрядно и в конце концов, пришел к "своему": опрос одного вывода при перепаде на другом без использования прерываний и таймеров. Дребезг давится задержками. Если кому интересно - попробуйте. Программа сделана на ассемблере для AVR как раз в процессе изучения обработки валкодера.
У меня получился нормальный результат и данный фрагмент обработки валкодера встроен мной в программу синтезатора частот Изображение. Кстати, обработка валкодера по прерываниям не устроила меня по результату работы. Приглашаю к общению на эту тему.
Вложения
CT44780_8VAL1.rar
Программа счётчика витков, на которой отрабатывался фрагмент обработки валкодера.
(11.4 КБ) 222 скачивания
Ответить

Вернуться в «Периферия»