Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

LCD via rotary encoder + PIC - sanity check

Status
Not open for further replies.

dsc

Member
Hi guys,

I've decided to use a quadrature rotary encoder for my next project and the encoder itself will be used to control some settings via a 20x4 LCD. The idea is to have the knob 'scroll' through the available settings (3 for now) and the button to select the setting you want. After pressing the button you access the setting and further knob turns will scroll through the available options for that setting (usually ON or OFF). So it's like a two level menu accessible via encoder.

To handle the encoder I've written a short function which uses a primitive delay method to debounce the contacts:

Code:
[SIZE="2"][FONT="Times New Roman"]; ######################### CHECK ENCODER ##########################

Rot_Enc

movf	PORTC, W		;copy PORTC to W
andwf	b'00000111',W	;mask bits3-7 so only 0,1,2 are saved (the rotary enc inputs)
movwf	PORTC_new	;copy to variable

subwf	PORTC_last, W	;do (PORTC_last - PORTC_new) => W
btfsc	STATUS, Z		;check zero bit
goto	Rot_Enc_end	;values the same because result = 0
btfsc	deb_flag		;test debounce flag to see if this is first change detected
goto	Rot_Enc_change	;if PORTC is different than last value and again different after 50ms
call	Delay50		;primitive debounce by waiting 50ms
bsf	deb_flag, 0		;set debounce flag
goto	Rot_Enc		;after debouncing check port again

Rot_Enc_change

; check if turned right
movlw 	HIGH turn_right	;preload PCLATH with
movwf 	PCLATH		;high byte of turn_right table
movf	PORTC_last, W	;move PORTC_last to W
call	turn_right		;get the next correct value from the table
subwf	PORTC_new, W	;do (PORTC_new - next correct value) => W
btfsc	STATUS, Z		;check zero bit
goto	Rot_Enc_right	;values the same because result = 0
	
; check if turned left
movlw 	HIGH turn_left	;preload PCLATH with
movwf 	PCLATH		;high byte of turn_left table
movf	PORTC_last, W	;move PORTC_last to W
call	turn_left		;get the next correct value from the table
subwf	PORTC_new, W	;do (PORTC_new - next correct value) => W
btfsc	STATUS, Z		;check zero bit
goto	Rot_Enc_left	;values the same because result = 0

; check if pressed
btfss	PORTC_new, 2	;check bit 2 = knob press
goto	Rot_Enc_press	;values the same because result = 0
goto	Rot_Enc_update	;if not it means that there was a skip in steps so just update the value

Rot_Enc_right
; knob turned right


goto	Rot_Enc_update

Rot_Enc_left
; knob turned left

goto	Rot_Enc_update	

Rot_Enc_press
; knob pressed


Rot_Enc_update
; update the last scan value

movf	PORTC_new, W	;move new value to W
movwf	PORTC_last		;update last scan value

Rot_Enc_end

retlw	0x00[/FONT][/SIZE]

[NOTE: the function grabs the PORTC value (only bits 0-2 are used for the encoder) and compares it to the last scan value. Tables turn_left, turn_right are not shown, but they hold the next correct values when turning the knob. The right/left/press parts don't hold any code yet of course]

Now the encoder will be turned by hand and obviously if you turn it too fast it will skip a step and not do anything. I'm curious if the 50ms delay for debounce is not going to force very slow turns in order to change the settings. Perhaps someone here tried something similar?

Regards,
dsc.
 
I've used a rotary encoder for the input portion of an LCD menu system before and it worked quite well. The encoder I used had 16 detent positions with all four quadrature states between the detents so I simply detected all of the "change" states but ignored all but the change into the detent state. I used something like 2-msecs between samples...

Regards, Mike

<added>

You can determine "direction" of a quadrature A-B signal state change by exclusive-or'ing the A or B bit from the new sample with the opposite bit from the previous sample. Here's a quick example that uses a single variable (though you would still need to add your "inc" and "dec" code).

Code:
;
;  sample rotary encoder at 2-msec intervals
;
         movf    PORTC,W         ; sample encoder, W = '------BA'
         andlw   b'00000011'     ; mask off unused bits
         xorwf   encold,W        ; state change?
         bz      done            ; no, branch, else
         xorwf   encold,W        ; restore WREG
         rrf     encold,F        ; shift B old '-------B'
         xorwf   encold,F        ; bit 0 = direction (A new ^ B old)
         rrf     encold,F        ; Carry = direction
         movwf   encold          ; update 'encold' to current sample
;
;  Carry = direction.  Check for detent position.
;
         xorlw   b'00000011'     ; detent (BA = 11)?
         bz      done            ; no, branch, else

done
 
Last edited:
Hi Mike,

ah yes the famous XOR, much easier indeed, thanks for the tip.

I've noticed you haven't bothered with debouncing, is that because the transitions are pretty much bounce-less?

Regards,
Tom

EDIT: I've just checked and my rotary encoder goes through the entire A/B cycle per dent. This means the above code should work but it might lose a lot of steps (especially if I want to do time-based) debouncing. I might consider switching to 3 tactile switches instead.
 
Last edited:
Hi Tom,

The switches still bounce but the intermediate state changes between detents are ignored in my implementation so it doesn't matter if they're bouncing between left and right.

The 2-msec sample interval I used seemed fast enough to keep me from missing a change and long enough to debounce the switches.

Regards, Mike
 
Hi Mike,

ah yes true you only act on a dent (11 state) and not in between states. Might give this a try, although the encoder I've got has 32 positions instead of 16, so it's actually quite hard to make small changes manually and it might be quite hard to operate.

Regards,
Tom
 
Hi Mike,

unfortunately I don't know the model number (nothing on the case), don't know the manufacturer and don't have a datasheet. It's a big unknown to be honest.

Regards,
Tom
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top