Code:
'Read Quadrature Encoder and display value on LCD in .25 increments. 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 '
CCP1CON = 0
CCP2CON = 0
TRISA = %00000000 ' output ports
TRISB = %11000000 ' set input and output ports
TRISC = %00100000 ' output ports
portB.4 = 0
portB.5 = 0
'************************ PROGRAM VARIABLES HERE ***************************
symbol ledUp = portC.2 ' status led
symbol ledDown = portC.3 ' status led2
symbol lcdbkl = portC.4 ' lcd pannel backlight
symbol sw1 = portC.5 ' encoder switch
symbol ledTest = portC.6
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
enc_dir VAR enc_old.bit7
Counter VAR word bank0
enc_SIGN VAR counter.bit15
Sign VAR BIT
'*********************** 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
;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 STATUS,Z ;if result is not zero, 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 _ledDown ;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 _ledUp ;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
INTCON = %10001000 ' Enable PortB Change Interupts
LCDOUT $FE,1 'Init The LCD
pause 500 'wait for LCD to start
lcdout $FE,$80, "TEST ANGLE DISP " 'display splash screen
LCDOUT $FE,$C0, "Initializing... "
high lcdbkl ' turn on backlight
'************************** SET DEFAULT SETTINGS HERE **********************
pause 2000 ' just wait a bit to read splash screen
lcdout $FE,1
enc_counter = 0 ' set default encoder value
enc_counter_old = 0
Counter = 0
lcdout $FE,$80, "Measurement "
lcdout $FE,$C0,"TST ANGLE: "
'************************** TESTING ROUTINES HERE **************************
test:
If portC.5 = 0 then clearall
if enc_counter <> enc_counter_old then 'see if value has changed
enc_counter_old = enc_counter 'move new value to old
Counter = enc_counter '(enc_counter */ 250)/2
Sign = Counter.15 ' Save sign
Counter = ((ABS Counter) * 25) ' Degrees is now 0 to 900
If Sign THEN Counter = -Counter ' Restore sign, value is now -900 to 900
If not sign AND (-Counter > 0 or Counter < 0) then
lcdout $FE,$80, "Measurement "
lcdout $FE,$C0,"TST ANGLE:", "-",sdec Counter /100 , ".", sdec Counter // 100, " "
else
lcdout $FE,$80, "Measurement "
lcdout $FE,$C0,"TST ANGLE:", " ", sdec -Counter /100 , ".", sdec -Counter // 100, " "
endif
low ledUp 'turn off CCW led
low ledDown 'turn off CW led
endif
goto test
ClearAll:
enc_counter = 0
enc_counter_old = 0
Counter = 0
clear
lcdout $FE,$80, "Measurement "
lcdout $FE,$C0,"TST ANGLE:", " 0.00 "
high ledtest
pause 1000
low ledtest
goto test
@INT_RETURN
Bookmarks