[CCC DEV] The third button problem

Steve Pretty steve.g.pretty at btinternet.com
Sun Feb 6 19:34:31 GMT 2011


At present, the "plumbing" library has a significant limitation in that 
it can only deal with two digital inputs (buttons). The current code 
uses interrupt driven digital input. It uses the two external interrupts 
provided by the Atmel chip, which are connected to pins 2 and 3 of the 
arduino.

So what happens when the user wants 3 or more digital inputs?  Here is a 
sample use case:

Quiz controller - there are two teams, A and B. Each team has a button 
and a lamp. The quiz master asks a question - first team to press the 
button lights their lamp and blocks the other team. Once the winning 
team has answered the question, the question master presses a button to 
reset the system ready for the next question (note - the quiz controller 
is also recording and displaying scores, so the arduino reset button 
cannot be used for the quiz master button).  I built a system like this 
once (using TTL logic).

The existing digital.input proc can service the Team A and Team B 
buttons.  Because this routime is interrupt driven, it should have very 
low latency and be able to accurately discriminate the winning team. 
What can we do for the quiz master's button?  One solution would be a 
timed poll variant of digital.input. This would have some latency - but 
that is not an issue for this button.  timed poll is a widely used micro 
controller strategy for handling multiple buttons - e.g. keyboard 
scanning.  Here is my test code, which test out OK:

#INCLUDE "plumbing.module"

--{{{ PROC digital.input.polled
--* Read digital levels on external pins using timed polling
-- This procedure will output a LEVEL (either LOW or HIGH) whenever the
-- pin changes value.
--
-- @param board.pin The pin number (any I/O pin).
-- @param period The time in milliseconds between polls
-- @param out The LEVEL, output when the pin changes level.
PROC digital.input.polled (VAL INT board.pin, period, CHAN LEVEL out!)
   LEVEL last, level:
   SEQ
     digital.read (board.pin, level)  -- find initial port level
     out ! level
     last := level
     WHILE TRUE
       SEQ
         delay (period)
         digital.read (board.pin, level)
         IF
           level <> last
             SEQ
               out ! level
               last := level
           TRUE
             SKIP
:
--}}}

PROC main ()
   CHAN LEVEL x:
   SEQ
     PAR
       digital.input.polled (4, 100, x!)
       digital.output (13, x?)
:

A nicer solution would be to keep with interrupts, I think. This would 
mean supplying a PROC to deal with the three interrupts PCINT1, PCINT2, 
PCINT3.   These interrupts each deal with an 8 bit port, and will flag 
an interrupt for a state change on selected pins on those ports.

With the current digital.input, there would be a separate PROC instance 
running for pin 2 and pin 3 - i.e. a one to one relationship between an 
interrupt, its interrupt vector and the handling PROC.  I presume that a 
one to one relationship would be needed for the PCINT1, PCINT2 and 
PCINT3  ( or could one PROC wait on an ALT of the three interrupts?)

I am thinking a handler routine would have to deal with up to 8 pins.  
It could have a signature:

PROC (VAL INT intID, mask, CHAN LEVEL out0, out1, out2, out3, out4, 
out5, out6, out7)

where intID is the name of the interrupt (and hence the range of pins), 
mask is used to flag which bits of the port are of interest and should 
be reported, and then there are 8 CHANs for the output.   This is not 
very nice, as you would have to provide "black holes" for any unused 
outputs?

Ideally, I would want a user interface identical to the current 
digital.input - where I can set up a PROC to handle one pin and 
associate it with one output CHAN. This would somehow have to register 
the pin / CHAN with some underlaying helper PROC which is actually 
managing the interrupts - I have no idea how to do that in occam (if it 
is even possible).  What I would really like to be able to do is pass a 
list of pin / CHAN tuples to the handler - but again, I don't think 
occam supports that kind of thing.

Could I start a handler and then use a protocol to pass in the pin/CHAN 
pairs?  If I did that, can I somehow save the set of CHANs I want to use 
in an array, and then send on the CHAN references in the array.  (Is 
this what Mobile CHANs are for?)

There are probably a lot of basic occam pi questions here which I should 
be answering myself - but I have yet to find comprehensive occam-pi 
language documentation - is there anything more comprehensive that the 
Peter Welch quick guide?


I would be interested to know what your thoughts are for the third 
button problem.

Steve





More information about the developers mailing list