Hi All,
I'm struggling around rotary encoder with push button. I read the forum but not find any successfully solved example.
Here is my code:
Code:
; PIC16F1847
#CONFIG ; 16FF1847.
__config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _BOREN_OFF
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF
#ENDCONFIG
DEFINE OSC 32
OSCCON = %11110000 ;32 MHz
ANSELA = 0
ANSELB = 0
TRISA=%00000000
TRISB=%00000011
LATB = %00000011
Include "modedefs.bas"
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts
INTCON=%10001000
IOCBP=%00000000
IOCBN=%00000011 ;on change interrupt NEGATIVE port RB.0, RB.1
IOCBF=%00000011
wsave VAR BYTE $70 SYSTEM ' alternate save location for W
enc_new VAR BYTE bank0
enc_old VAR BYTE bank0
enc_counter VAR word bank0
Flag var BYTE bank0
asm
INT_LIST macro ;IntSource,Label, Type, Resetflag?
INT_Handler IOC_INT, _enc, asm, yes
endm
INT_CREATE ; Creates the interrupt processor
;================================================
endasm
; Set variable value @ startup
Flag = 0
enc_new = 0
enc_old = 0
enc_counter = 0
@ INT_ENABLE IOC_INT ; enable external (INT) interrupts
Main:
if flag=1 then
SEROUT portb.4,t9600,[#enc_counter,13]
endif
goto main
enc:
asm
;Read latest input from PORTB & put the value in _enc_new.
MOVE?CB 1,_Flag
movf PORTB,W
movwf _enc_new
;Strip off all but the 2 MSBs in _enc_new.
movlw B'00000011' ;Create bit mask (bits 1 & 0).
andwf _enc_new,F ;Zero bits 5 thru 0.
;Determine the direction of the Rotary encoder.
rlf _enc_old,F ;left shift it into _enc_old to align bit 6 of
;_enc_old with bit 7 of _enc_new.
movf _enc_new,W ;Move the contents of _enc_new to W in order to XOR.
xorwf _enc_old,F ;XOR previous inputs (in _enc_old) with latest
;inputs (in W) to determine CW or CCW.
btfsc _enc_old,0 ;Test bit 0 of result (in _enc_old). Skip next line
;if it is 0 (direction is CCW).
goto Up ;Bit is 1 (direction is CW). Go around Down
;and increment counter.
Down
;Decrements _enc_counter because the rotary encoder moved CCW.
;Decrements _enc_counter (16 bit value), sets Z on exit.
decf _enc_counter,F ; Decrement low byte
incfsz _enc_counter,W ; Check for underflow
incf _enc_counter+1,F ; Update
decf _enc_counter+1,F ; Fixup
movf _enc_counter,W
iorwf _enc_counter+1,W ; Set Z bit
;Add here code for the CCW LED if needed.
goto Continue ;Branch around UP.
Up
;Increments _enc_counter because the rotary encoder moved CW.
;Increments _enc_counter (16 bit value), sets Z on exit.
incfsz _enc_counter,W ; Add one to low byte
decf _enc_counter+1,F ; No carry (negates next step)
incf _enc_counter+1,F ; Add one to high byte
movwf _enc_counter ; Store updated low byte back.
iorwf _enc_counter+1,W ; Set Z flag
;Add here code for the CW LED if needed.
Continue
;Assign the latest encoder inputs (in _enc_new) to _enc_old.
movf _enc_new,W
movwf _enc_old
CHK?RP IOCBF
CLRF IOCBF
INT_RETURN
;============ END OF THE ROTARY ENCODER CODE =====
endasm
The problem is, I can't get correct encoder reading. In serial monitor I can see the result but the values goes only to increment no matter if I rotate CW or CCW.
The values increment randomly. I dont know, what is the problem.
The encoder is wired with 10k pullups and debounce capacitors.
I need quic response to rotation fot that I try to use this ASM and DT interrupts metod.
Anyway If I tried another example with no ASM and Interrupts only for testing, the encoder works fine CW and CCW, increments, decrements by one just fine.
Can someone check my code and correct me what Im doing wrong.
Thanks.
Bookmarks