Code:
'Read Quadrature Encoder and display value on LCD. for ****pic16f876****
'************************ 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 bank0
enc_counter_old VAR WORD bank0
enc_scaler VAR WORD bank0
'*********************** 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
; ****Changed from original isr initialization settings****
;movwf wsave
;swapf STATUS, W
;clrf STATUS
;movwf ssave
;movf PCLATH, W
;movwf psave
; Changed from original isr initialization settings
movwf wsave
swapf STATUS, W
clrf STATUS
movwf ssave
movf PCLATH, W
movwf psave
CLRF PCLATH
;====== 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. ************Not sure what needs to happen here**************
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 ************Not sure what needs to happen here**************
;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 1000 ' just wait a bit to read splash screen
enc_counter = 0 ' set default encoder value
enc_counter_old = 0
' Initial display
LCDOUT $FE,1,"ENCODER" ' Initial display
LCDOUT $FE,$C0, "00.00"
INTCON = %10001000 ' Enable PortB Change Interupts
'************************** TESTING ROUTINES HERE **************************
test:
if buffered_enc_counter <> enc_counter_old then 'see if value has changed
'enc_counter_old = enc_counter 'move new value to old ******Removed this line and replaced with*******
gosub get_enc_count '******this line******************************
Counter = buffered_enc_counter
Sign = Counter.15 ' Save sign
Counter = ((ABS Counter) * 5) ' Degrees is now 0 to 900
If Sign THEN Counter = -Counter ' Restore sign, value is now -900 to 900
If NOT sign then
LCDOUT $FE,1, sdec Counter /10 , ".", sdec Counter // 10
else
LCDOUT $FE,1, "-", sdec -Counter /10 , ".", sdec -Counter // 10
endif
'*********************************************************************************
low led 'turn off CCW led
low led2 'turn off CW led
endif
goto test
get_enc_count:
intcon.3=0 ; rbc_int off
buffered_enc_counter=enc_counter
intcon.3=1 ; rbc_int on
return
Bookmarks