Maker Pro
Maker Pro

PIC - twist yer noodle

A

Active8

Jan 1, 1970
0
modified circuit from a previous BAJ post:

+--- RB0
|
RB7 --+---->|----/\/\/\/\/\--+------/ -------GND
|
| +--- RB1
| |
+---->|---/\/\/\/\/\---+------/ -------GND
|
|
 
C

Casper

Jan 1, 1970
0
This is not an answer to this quizz, but I wanted to note that in assembler
for AVR, I've made a reusable driver for a simple keypad, that -after
debouncing of course- works completely event-based (keyup[n], keydown[n]).
Other pieces of program can write jump adresses to dynamically assign event
handlers. I found this to be very useful if the function of the buttons has
to change run-time.
 
H

Howard Henry Schlunder

Jan 1, 1970
0
in message
_poll_switches
bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit

QUIZ: In 13 lines or less, using the above code frag, write the
code to determine the following:

1) Which switches were closed since the last poll, i.e., they went
from open to closed?
2) Which switches were released since the last poll, i.e., vice-
versa?

bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit
movwf CurrentPORTBState
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf LastPORTBState, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high. Bit 7 is not
meaningful.
comf CurrentPORTBState, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low. Bit 7 is
not meaningful.
movf CurrentPORTBState, W
movwf LastPORTBState
return

The above code can be simplified by 1 instruction and 1 register if it is
assumed that the value of PORTB changes so slowly (human times) while the
code executes almost instantaneously, and it is permissible to have an
inconsistent report from (rare) time to time. The very first time the
routine is called will naturally return unknown data. Your code frag may be
simplified by 2 instructions if bit 7 was always asserted or hardware tied
to Vdd. The hardware may be simplified by using internal PORTB weak pull
ups and throwing away those diodes and resistors (although that natrually
decreases the ESD protection).

Howard Henry Schlunder
 
A

Active8

Jan 1, 1970
0
in message


bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit
movwf CurrentPORTBState
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf LastPORTBState, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high. Bit 7 is not
meaningful.
comf CurrentPORTBState, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low. Bit 7 is
not meaningful.
movf CurrentPORTBState, W
movwf LastPORTBState
return

The above code can be simplified by 1 instruction and 1 register if it is
assumed that the value of PORTB changes so slowly (human times) while the
code executes almost instantaneously, and it is permissible to have an
inconsistent report from (rare) time to time. The very first time the
routine is called will naturally return unknown data. Your code frag may be
simplified by 2 instructions if bit 7 was always asserted or hardware tied
to Vdd. The hardware may be simplified by using internal PORTB weak pull
ups and throwing away those diodes and resistors (although that natrually
decreases the ESD protection).

Howard Henry Schlunder

hi Howard:

that's a nice tight solution. i see i can eliminate 2 intructions
if i get rid of the check for a change marked ** below which could
cause an endless loop, anyway. maybe i can whittle it down more if
i could understand what you mean about the slow change time. and
that comf insrtruction may help too.

here hx refers to switch history or prior states. interesting how
this works even though status and history are negative logic. i
worked it out with positive logic and the only difference is that
colsure info becomes release info and vice-versa.

this was the second routine i wrote:

; hx = history
_poll_switches ; negative logic. 0 = closed; 1 = open
movf switch_hx, W ; save hx in closures
movwf switch_closures ; hx x chg will = closures

_no_change
bsf PORTB, 0 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 0 ; clear poll bit

movwf switch_hx ; current status will be history :)
; save current status in releases
movwf switch_releases ; status x chg will = releases

xorwf switch_closures, W ; get hx back. chg info is in W
btfsc STATUS, Z ; **chk 4 chg.
goto _no_change ; **no change

_switch_event
andwf switch_closures, F ; hx x change -> closures
andwf switch_releases, F ; status x change -> release

goto _poll_switches
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

the first routine i wrote. 1 extra instruction. big deal. it's
easier to read and would exit faster if the no change goto were a
return.

_poll_switches ; negative logic. 0 = closed; 1 = open
bsf PORTB, 0 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 0 ; clear poll bit

movwf switch_status ; save current switch status
xorwf switch_history, W ; change info in W
btfsc STATUS, Z ; **chk 4 chg. chg info in W
goto _poll_switches ; no change

_switch_event
movwf switch_releases ; stash chg info in switch_releases register
movwf switch_closures ; stash chg info in switch_closures register
movf switch_status, W
andwf switch_closures, F ; status x change -> closures
movf switch_history, W
andwf switch_releases, F ; history x change -> releases

goto _poll_switches

maybe you or someone can find further improvements.

brs,
mike
 
M

Michael

Jan 1, 1970
0
Howard Henry Schlunder said:
in message


bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit
movwf CurrentPORTBState
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf LastPORTBState, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high. Bit 7 is not
meaningful.
comf CurrentPORTBState, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low. Bit 7 is
not meaningful.
movf CurrentPORTBState, W
movwf LastPORTBState
return


huh?
If a port pin goes from high to low transition, it will set a bit in
your change mask, which is and'd with the previouse state (high) which
gives you a 1 in your PORTBPinsGoneHigh register, yet this port pin
went low!
 
H

Howard Henry Schlunder

Jan 1, 1970
0
in message
huh?
If a port pin goes from high to low transition, it will set a bit in
your change mask, which is and'd with the previouse state (high) which
gives you a 1 in your PORTBPinsGoneHigh register, yet this port pin
went low!

Oops. My bad; you are right. I was changing things around this morning to
see what I could make, but I was also in a hurry because I had to get to
class. It should not be anding with the old value, it should be anding with
the current value. i.e.:

bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit
movwf CurrentPORTBState
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf CurrentPORTBState, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high.
comf CurrentPORTBState, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low.
movf CurrentPORTBState, W
movwf LastPORTBState
return

Howard Henry Schlunder
 
M

Michael

Jan 1, 1970
0
Howard Henry Schlunder said:
in message


bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
bcf PORTB, 7 ; clear poll bit
movwf CurrentPORTBState
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf LastPORTBState, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high. Bit 7 is not
meaningful.
comf CurrentPORTBState, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low. Bit 7 is
not meaningful.
movf CurrentPORTBState, W
movwf LastPORTBState
return

The above code can be simplified by 1 instruction and 1 register if it is
assumed that the value of PORTB changes so slowly (human times) while the
code executes almost instantaneously, and it is permissible to have an
inconsistent report from (rare) time to time. The very first time the
routine is called will naturally return unknown data. Your code frag may be
simplified by 2 instructions if bit 7 was always asserted or hardware tied
to Vdd. The hardware may be simplified by using internal PORTB weak pull
ups and throwing away those diodes and resistors (although that natrually
decreases the ESD protection).

Howard Henry Schlunder


bsf PORTB, 7 ;poll switches
movf PORTB, W ;read the whole shebang in
bcf PORTB, 7 ;clear poll bit

xorwf Last,w ;w=change mask
xorwf last,f ;last becomes current state

movwf gonelow ;store change mask

andwf last,w ;and changed pins with current 1's
movwf gonehigh ;to get pins gone high

comf last,w ;and changed pins with current 0's
andwf gonelow,f ;to get pins gone low

return

8 instructions in addition to your 3

Anyone wanna try for 7?

I would also like to point out that the RC time constant formed by
your pullup resistors and the capacitance between the places of the
button may not rise fast enough to get the correct reading from the
port.
If this were not a minimum cycle challenge I would put a few nops in
after you set portB,7 high before reading the port.


Michael......
 
A

Active8

Jan 1, 1970
0
On 23 Oct 2003 19:05:01 -0700, Michael said,
huh?
If a port pin goes from high to low transition, it will set a bit in
your change mask, which is and'd with the previouse state (high) which
gives you a 1 in your PORTBPinsGoneHigh register, yet this port pin
went low!

so does my code.

which indicates that the switch was pressed. the other register
indicates which switches were released.

it's really just a conversion from neg to pos logic. i'd rather see
a 1 to indicate a press.

mike
 
A

Active8

Jan 1, 1970
0
On 23 Oct 2003 19:42:04 -0700, Michael said,
bsf PORTB, 7 ;poll switches
movf PORTB, W ;read the whole shebang in
bcf PORTB, 7 ;clear poll bit

xorwf Last,w ;w=change mask
xorwf last,f ;last becomes current state

movwf gonelow ;store change mask

andwf last,w ;and changed pins with current 1's
movwf gonehigh ;to get pins gone high

comf last,w ;and changed pins with current 0's
andwf gonelow,f ;to get pins gone low

return

8 instructions in addition to your 3

= 11

well, i did say that i could remove the 2 lines that checked
whether there was a change. that's the same - 11.
Anyone wanna try for 7?

really! i want to see that, for sure.

i didn't include a spec on number of registers used either, but i
see you and i did it with three registers and Henry used 4. my
first try also used 4.
I would also like to point out that the RC time constant formed by
your pullup resistors and the capacitance between the places of the
button may not rise fast enough to get the correct reading from the
port.
If this were not a minimum cycle challenge I would put a few nops in
after you set portB,7 high before reading the port.

right. that and debounce was not a requirement.

brs,
mike
 
H

Howard Henry Schlunder

Jan 1, 1970
0
I was referring to the storage of the CurrentPORTBState, which could instead
be reread from the pins. In other words:

bsf PORTB, 7 ; poll switches
movf PORTB, W ; read the whole shebang in
xorwf LastPORTBState, W
movwf PORTBPinsGoneLow ;Contains a bitwise pin change mask right now
andwf PORTB, W
movwf PORTBPinsGoneHigh ;Contains all pins which went high.
comf PORTB, W
andwf PORTBPinsGoneLow, F ;Contains all pins which went low.
movf PORTB, W
movwf LastPORTBState
bcf PORTB, 7 ; clear poll bit
return

In the event that the value of PORTB changes while the code is executing, it
is quite unlikely but possible that both a high and low transition will be
reported (most likely a benign result), or quite undesirably and more
possibly, a transition occurs and doesn't get detected. Ultimately,
Michael's code strikes me as highly appealing, so this code is worthless.

Howard Henry Schlunder
 
A

Active8

Jan 1, 1970
0
I was referring to the storage of the CurrentPORTBState, which could instead
be reread from the pins. In other words:

notice that Michael and i store the current state in the history or
last state register once it's no longer needed.
In the event that the value of PORTB changes while the code is executing, it
is quite unlikely but possible that both a high and low transition will be
reported (most likely a benign result), or quite undesirably and more
possibly, a transition occurs and doesn't get detected. Ultimately,
Michael's code strikes me as highly appealing, so this code is worthless.
LOL. oh well. we sometimes don't think of these things until later
than we'd have liked. i like Michael's solution, also.

i've been looking over my code in comparison with yours and
Michael's and what's got me going is the non-difference between
using the comf statements and my way of ANDing the change mask with
the old status and then the current status.

quick check...

you and mike just AND the chg mask with current 1s and then 0s
which are represented by ones. i like that. it makes more sense. i
got my solution by inspection of the truth tables. i guess it makes
sense, also. it's just applying the mask to old and new.

i liked the idea of looping or exiting if there's no change and
this would be ok if waiting for input with nothing else to do
unless interrupted. but it also make it a variable cycle routine
which fouls up any time critical code. one can always check for a
change later or set a register with the number of cycles actually
executed

damned if i can get any lower than 11 lines.

brs,
mike
 
Top