Знаю, что тема уже избита, однако, перечитав кучу сообщений и статей, так и не смог накодить ничего вменяемого.
Выдрал из сторого ЭЛТ монитора энкодер (как в этой статье, только контакты выведены под 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
На 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


