the encoder knob the program can still keep up.
The present state of the input pins is copied into
newscan, and that is copied into tmp1 where we’ll use it
to check on the button. To check the button input, we
AND (using test) the button mask with tmp1 and save the
result in the Carry flag. We’re using an active-low circuit,
so a set Carry flag means that the button is not pressed. If
that’s the case, the value of btnwork is cleared. Otherwise,
it’s incremented.
The next step — using max — actually does two things
for us: 1) It keeps the value of btnwork at the debounce
timing limit to prevent a roll-over on a stuck switch; and 2)
The Carry flag indicates whether btnwork is less than
BTN_TM (set for 25 ms). If the Carry flag is set, the button
is not fully debounced and we move zero to tmp1.
Otherwise, we move IS_PRESSED (true) to tmp1, then
write it to the hub at the address for the button status.
Again, the encoder value address is stored in par, so four
(for a long value) is added to this value to get the correct
address of the button status variable.
With the button debounced (or not), we can check to
see if the encoder moved. We’ll start by isolating the
encoder inputs and comparing them to the last scan.
chkencoder shr newscan, basepin
and newscan, #%11
cmp newscan, oldscan
wz
if_e jmp #encloop
Now you can see why we want the A and B pins in
contiguous, ascending order on the inputs; we’re simply
shifting the scan value right by the base (A) pin number
and masking off the other bits. This is compared to
oldscan and if they’re equal (i.e., no change), we jump
right back to the top.
Okay, I know there’s more than one of you hardcore
types that might want to go willy-nilly on input mapping;
maybe a PCB routing problem prevents keeping the pins
contiguous and in ascending order. Here’s what to do:
Create pin masks for the A and B pins (just like we did for
the button input) and then change the code like this:
chkencoder mov tmp1, #0
test amask, newscan wc
muxc tmp1, #%01
test bmask, newscan wc
muxc tmp1, #%10
mov newscan, tmp1
cmp newscan, oldscan wz
if_e jmp #encloop
As you can see, this version tests each input and
moves them through the Carry flag, into the correct
locations in newscan. I really like the muxc operator; this
code snippet shows how useful it is, allowing us to move
what’s in C to any bit position of a variable. Remember, if
you update the PASM code to handle non-contiguous
16 May 2010
encoder pins you’ll need to update the initialization of
oldscan and add a B pin parameter to the init() method.
Actually, I’ve done the work for you. (See
jm_grayenc2btnx.spin in the download package at
www.nutsvolts.com. This version allows us to disable the
button pin, as well.)
Okay, let’s say we have a change. What I use is an
assembly version of a case structure, using the previous
scan and comparing it to the value for a positive
(clockwise) change.
case11 cmp oldscan, #%11 wz
if_ne jmp #case01
cmp newscan, #%01 wz
jmp #update
case01 cmp oldscan, #%01 wz
if_ne jmp #case00
cmp newscan, #%00 wz
jmp #update
case00 cmp oldscan, #%00 wz
if_ne jmp #case10
cmp newscan, #%10 wz
jmp #update
case10 cmp oldscan, #%10 wz
if_ne jmp #encloop
cmp newscan, #%11 wz
You’ll see that each section is identically constructed.
If the new scan represents a clockwise move, the Z flag
will be set. Otherwise, the Z flag will be cleared. The
program then jumps to update which does the final
routing.
update rdlong tmp2, par
if_nz jmp #decvalue
incvalue adds tmp2, #1
maxs tmp2, hilimit
wrlong tmp2, par
mov oldscan, newscan
jmp #encloop
decvalue subs tmp2, #1
mins tmp2, lolimit
wrlong tmp2, par
mov oldscan, newscan
jmp #encloop
At update, we retrieve the encoder value from the
hub (because it could have been changed by the top-level
program) and then increment or decrement it (based on
the state of the Z flag) using the previously defined limits.
The updated value is written back to the hub and we’re
done.
Well, almost — we need a method to read the current