Code:
'Read Quadrature Encoder and display value on LCD. for pic16f876a
'setup PIC Config Fuses
@ Device pic16F876A, HS_OSC, BOD_OFF, PWRT_ON, WDT_OFF, PROTECT_OFF
'************************ DEFINES HERE *************************************
DEFINE OSC 20 ' set to 20mhz
DEFINE LCD_DREG PORTA ' Set Data Registers port
DEFINE LCD_DBIT 0 ' Set starting data bit
DEFINE LCD_RSREG PORTB ' Set LCD RS Port
DEFINE LCD_RSBIT 1 ' Set LCD RS Bit
DEFINE LCD_EREG PORTB ' Set LCD Enable Port
DEFINE LCD_EBIT 2 ' Set LCD Enable Bit
DEFINE LCD_BITS 4 ' Set LCD 4bit Mode
DEFINE LCD_LINES 2 ' Set number of LCD Lines
DEFINE LCD_COMMANDUS 2000 ' Set Command Delay time in uS
DEFINE LCD_DATAUS 60 ' Set Data delay time in uS
clear 'clear out variables
'*********************** CHIP REGISTER SETUP *******************************
ADCON0 = 7 ' turn off analog porta, set to digital IO
ADCON1 = 7 '
CMCON = 7 ' Turn off Port A Comparator
TRISA = 0 ' output ports
TRISB = %11000001 ' set input and output ports
TRISC = 0 ' output ports
'************************ PROGRAM VARIABLES HERE ***************************
symbol led = portc.2 ' status led
symbol led2 = portc.0 ' status led2
symbol lcdbkl = portc.7 ' lcd pannel backlight
symbol sw1 = portb.0 ' encoder switch
enc_old VAR BYTE
enc_new VAR BYTE
enc_tmp var byte
enc_counter VAR WORD
enc_counter_old VAR WORD
enc_scaler var word
'*********************** ASSEMBLY INTERUPT VARIABLES ***********************
wsave var byte $20 system
wsave1 var byte $a0 system ' Necessary for devices with RAM in bank1
wsave2 var byte $120 system ' Necessary for devices with RAM in bank2
wsave3 var byte $1a0 system ' Necessary for devices with RAM in bank3
ssave var byte bank0 system
psave var byte bank0 system
goto start 'skip over interupt handler
'*********************** ASSEMBLY INTERUPT HANDLER *************************
define INTHAND myint
Asm
myint
; Save W, STATUS and PCLATH registers
; Not Necessary for Chips with >2k of Codespace
; movwf wsave
; swapf STATUS, W
; clrf STATUS
; movwf ssave
; movf PCLATH, W
; movwf psave
;====== BEGINNING OF THE ROTARY ENCODER CODE ========
;The Rotary Encoder is connected to PORTB
;The A signal of the encoder connected to the PIN portB.7
;The B signal of the encoder connected to the PIN portB.6
;
;The 4 variables used are declared in the PicBasic code.
;
; enc_new VAR BYTE
; enc_old VAR BYTE
; enc_tmp VAR BYTE
; enc_counter VAR WORD
;
;================================================
;Read latest input from PORTB & put the value in _enc_new.
movf PORTB,W
movwf _enc_new
;Strip off all but the 2 MSBs in _enc_new.
movlw 0xc0 ;Create bit mask (bits 7 & 6). b'11000000' ?
andwf _enc_new,F ;Zero bits 5 thru 0.
;check to see if encoder has moved
movf _enc_old,W ;move enc_old to W
movwf _enc_tmp ;put W to enc_tmp
movf _enc_new,W ;move enc_new to W for XOR
xorwf _enc_tmp,F ;XOR enc_tmp to detect encoder movement
btfsc _enc_tmp,7 ;if bit is clear, encoder moved.
goto Continue ;no movement exit isr
;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,7 ;Test bit 7 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.
bsf _led ;turn on led
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.
bsf _led2 ;turn on led
Continue
;Assign the latest encoder inputs (in _enc_new) to _enc_old.
movf _enc_new,W
movwf _enc_old
; Restore saved registers
movf psave, W
movwf PCLATH
swapf ssave, W
movwf STATUS
swapf wsave, F
swapf wsave, W
bcf INTCON, RBIF ; Clear the Interupt Flag
RETFIE ; Return from interrupt
endasm
'***************************************************************************
'************************* PROGRAM STARTS HERE *****************************
'***************************************************************************
START: ' Main Program starts here
LCDOUT $FE,1 'Init The LCD
pause 500 'wait for LCD to start
lcdout $FE,1,"ENCODER" 'display splash screen
LCDOUT $FE,$C0," TEST "
high lcdbkl ' turn on backlight
'************************** SET DEFAULT SETTINGS HERE **********************
pause 2000 ' just wait a bit to read splash screen
enc_counter = 1024 ' set default encoder value
enc_counter_old = 1024
lcdout $FE,1,"ENCODER" ' change display
lcdout $fe,$C0, DEC5 enc_counter
INTCON = %10001000 ' Enable PortB Change Interupts
'************************** TESTING ROUTINES HERE **************************
test:
if enc_counter <> enc_counter_old then 'see if value has changed
enc_counter_old = enc_counter 'move new value to old
lcdout $fe,$C0, DEC5 enc_counter 'display enc_counter value
low led 'turn off CCW led
low led2 'turn off CW led
endif
goto test
Bookmarks