|Digital Input Technical Details
The Digital Input System consists of a hardware interface and a software queuing
mechanism that makes it easy for hobbyists to build up elaborate home automation
systems. A simple language is provided that allows easy programming of what will
happen when any of the input buttons are pressed (or released). The software
mechanism uses an interrupt signal from the Digital Input Board (or other device) to
start the process. It determines which of the input signals have changed state (one or
all of them), then creates "packets" on a queue for each changed input event. Part of
the program periodically processes the packets. Any "handlers" that are of the
correct type automatically get called to take the described action.
This makes it easy to use the system for any purpose.
One example is an "evening mode lights" push button as part of a home automation system, but this could equally apply to bump sensors on your robot, limit switches in a factory process or sensors in your car. Connecting a push button to a microprocessor works easily enough if that's the only thing that needs to be monitored. A typical method is to connect the sensor input to an I/O pin on your controller. The input pin is then checked periodically. But in a system that is responsible for reacting to many external events, the controller may be busy processing something while the push button is pressed, the event could be lost and missed events are bad.
To make sure you never miss that event, you could connect a latch to the input. But the state of the latch still needs to be checked often so that the event can be handled in a timely manner. Another disadvantage is that your controller is spending time checking something that rarely changes state. If many inputs are to be handled, it can become impractical.
Another way to handle the push button problem is by tying it to the interrupt line of your microprocessor, but again, handling many inputs means that a way is needed to determine which input changed and what will happen if you get more events than expected? The system could be brought to its knees if it is spending all of its time in the interrupt handling state. Interrupt based methods can be tricky, too. It would be nice if there were a system to make this aspect much easier.
What is presented here is a method that uses a small interrupt service routine, in combination with an event queue, to capture events, such as push buttons being pressed. Event handlers and a simple language allows for flexible handling of these events. Using this system makes it much easier to build up a sophisticated system while the user programming is kept simple.
The Digital Input PCB Layout
The Digital Input Board described here will accept up to sixteen dry contact inputs. It will interrupt the processor if any of them change state. It doesnt matter if the inputs are normally open, or normally closed, or if they happen once a month or many times per second. Even if 6 inputs change state at the same time, all will be handled efficiently. The software remembers all the changes that have taken place.
For each device in the system, there will usually be some software (drivers and other code) that provides the means for easily adding a new type of device to the system. Users may wish to add their own creations to the system, or devices can be purchased on the authors web site. Typically, the driver for a device that can generate events will include an interrupt service routine which handles the external hardware event. Then events are added to the queues for other routines to process. A simple language is also implemented which provides a method to "script" actions by matching fields in the current event packet and creating new packets if a match is made.
The Digital Input Board is connected to the controller through a simple serial bus
called SPI. Many devices may share the interface, and only 5 signal wires are
needed to connect the digital input board to the controller. Even if your controller
doesn't have SPI, it's not difficult to adapt any controller to use SPI devices. Some
controllers have a similar interface which are also easily adapted. Any number of SPI
devices may share the bus. Each SPI device shares the SCK, MISO and MOSI
lines. A select line is provided for each individual SPI device so that only one is
active at a time.
Digital Input Board Schematic (click here)
Figure 1 shows the block diagram for the digital input board. When an input changes state, an interrupt is generated as a result of the comparitors changing to a "not equal" state. The interrupt service routine for the digital input board causes data to be read from the MISO pin (Master In, Slave Out). The same data is then sent back in to the board via the MOSI (Master Out, Slave In), which causes the INT line to go high (normal state) clearing the interrupt state. A type "1000" packet is created and queued that reflects the data just read from the digital input board, which will be handled by the type 1000 handler.
The program "homesys" included here provides means for setting up a complete home automation system. It includes a way to write a script that allows creation of new packets when certain parameters match the current packet being processed on the queue. The new packets created can trigger things like the SPI-X10 interface to dim your lights. For example, a statement can be written that matches packets created by the digital input system, looking for one of the inputs to change state (perhaps connected to an "All Off" button). When the match is detected, the new packets defined in the statement are queued and subsequently sent to the SPI-X10 board, turning off all the lights in the house. This is a flexible system providing a working example of operation in a way that makes it easy to extend the system for more elaborate tasks. The example configuration script (cfg-table.txt) defines a number of push buttons that generate different types of X-10 events. The system works by comparing each event queue packet as it is being processed with each "statement" in the configuration script. When a match is found, the new packets defined (after the colon) in that statement are added to the queue as new events to be processed. These new packets can be packets destined for the SPI-X10 interface to dim your lights (1201 packets) or they can even simulate other push button events by generating different 1100 type packets! If any additional devices (and drivers) are installed, packets can just as easily be written for them.
Theory of Operation - Hardware
The software also remembers the last state of each line, so that it can create a new event packet based on each bit that has changed state - if one or any number of them have simultaneously changed state. This scheme can be easily extended to monitor any number of inputs using additional digital input boards. All inputs have opto isolators to make it safe to string wire all over the place, reducing the risk of blowing any chips due to static electricity or lightning. The production boards have a header allowing TTL inputs to bypass the isolators if desired for applications that need a smaller board, and are only using nearby switch inputs such as with robots connected to bump sensors.
Theory of Operation - Software.
Here's what happens when someone presses the "Evening Lites" push button in my living room. So the button is pressed. The Digital Input board's comparitor becomes out of balance (A<>B) since the new state of the screw terminals no longer matches the remembered state sent to the A side of the comparitors. Since the output of the comparitors drives the host controller's IRQ line, the Digital Input board's associated interrupt service routine (ISR) is called. This causes data to be exchanged with the board to obtain the current state of all the inputs. A 1000 type packet is created with this data, which is placed on the main queue. The newly acquired data (16 bits) is sent back to the board in a second transfer releasing the interrupt since the comparitor is again balanced, now that the data from the screw terminals read from the B side has now been sent to the A side of the comparitors.
A routine called check_queue is periodically called by the main routine in homesys.c. It should be called often in a loop. Each time it is called, one packet is taken from the highest priority queue and processed. The 1000 type packet generated by the interrupt service routine will be taken from the queue and offered to all the handlers in digxlib.asm to see if there is a matching handler. These handlers are generally looking for packets with "output" information that might cause action to some external device, such as the type 1201 packet for the SPI-X10 interface. In addition, the configuration script is also checked for matches. If any are found, the associated packets are added to the main queue.
There is a "1000" type handler which then processes the packet that was on the queue.
It takes the data in the packet
describing the new state of all the input lines and compares it with the last known state.
input line that has changed state, a new 1100 type packet is queued.
This packet type contains the input line number (0-15), and the
state that it has just changed to (my living room Evening Lites button is input line #10).
check_queue continues to be called by the main routine.
Eventually the 1100 packet
that says that my living room Evening Lights button
has just been pressed becomes the current packet being processed.
The handlers are searched. There is one, but it only prints a message to the
screen showing which lines have just changed state (Line number 10 is now 1).
The configuration script is checked, and there is a matching "statement" that looks for packets of
type 1100, with the first data byte matching input #10 (0A in hex) and the second byte equaling 1. Since
this statement matches, everything following the colon and up to the semicolon, are taken as new packets
and they are placed on the queue.
Four new packets - of type 1201 are queued.
These are SPI-X10 output packets.
When check_queue is again called, the first of the new 1201 packets gets processed.
The 1201 handler is activated which selects the SPI-X10
board, and sends the data contained in the SPI-X10 board.
This first 1201 packet says to dim two of the dimmers to the off position. I do this first
in order to put the lights
in a known state before sending a bright command to bring them to the desired level.
Someone could have dinked
with the lights since the last command was sent to that unit.
There are a number of ways to do this depending on your taste.
The process continues until all of the four packets that were queued have been processed.
If no other external events have occurred, then the queue will be empty and
nothing more happens until the next external event occurs.
Table 1. J1 SPI connector pins. Only pins listed are used on the 14 pin header.
There are actually two event queues, though this is largely transparent to the user. The normal queue is most often used. The second, high priority queue is mainly for event processors that create other events, which should be handled before any other events are handled. The check_queue routine always returns with the highest priority event. In the case of the digital input board, one ISR-generated event could potentially be turned into many events (line 1 on, line 5 off, line 6 on, and so on). However, if these were simply added to the end of the main queue, they might be placed after some other hardware-generated event that happened after the digital input event. They would be processed out of order. By placing events created as the result of other events on a special high priority queue, the order of events can be maintained.
Construction. Refer to the layout diagram Figure 3 for assembly. The passive components R1 and C1 through C7 should be installed first. Note the polarity of C1. Next, install J1. If the connector used for J1 has a polarity mark, be sure this goes into the square pad indicating pin 1 (this might be indicated by a triangle on the outer casing. The board can be cleaned at this point, before sockets and other components that could get flux in them are installed. Sockets should be used at least for the SIP resistors, RP2 and RP4, since these control how much current goes through the external contacts. Sockets make it easy to change these resistors if it is desired to alter the current supplied through external wires, through contacts at the other end and ultimately to the LEDs in the opto isolators. An ammeter can be used to verify loop current which can be compared with the manufacturer's data sheet for the exact optoisolator used. But generally, when a switch input is closed the loop current should be somewhere between 5 and 15mA. The current limiting resistors RP2 and RP4 have been chosen as reasonable values, and should work for local push-buttons or ones located 20 feet away. However in certain situations the loop current might be lower than normal due to additional resistance in the loop due to long wires, or high-resistance contacts. Lower values for RP2 and RP4 could then be used to compensate.
Sockets should also be used for the opto isolators U9 though U12, because if some nasty spikes come down the long wires, and an opto isolator gets fried, it is easily replaced. Install the terminal strips TS1 and TS2 (or the header part if the two-piece connectors are used). Clean the board, if desired, being careful not to get solvent and flux in any sockets or connectors. Next, plug the socketed components in using layout diagram Figure 3.
In the authors prototype two-piece terminal strips were used for TS1 and TS2 (Phoenix p/n 17-57-09-3 terminals and 17-57-32-3 matching PCB headers). The artwork accommodates the single piece type as well (Phoenix p/n 17-29-20-9). Actually, any terminal strips can be used that have 0.2 inch spacing between the PCB pins.
As with any electronics assembly project, very carefully inspect your work before applying power for the first time. Look closely, since it is very easy to look right at a solder bridge an not see it, so spend at least a couple minutes searching for errors carefully.
TS1 and TS2 terminal strip connections
A test button or switch should be connected to either TS1 or TS2 between any input line and ground. Ground connections are provided on the screw terminals.
Two test programs are provided to assist checkout. The files mentioned here are available in the archive dig-in-test.zip. To perform a simple test to check out the basic operation without using interrupts, assemble and load digtest1.asm. Or, pre-assembled files are available, to save time, as digtest1.s19 and digtest1.lst. How the resulting ".s19" file is loaded will depend on the processor used. (ModCon users will typically use the Buffalo Monitor command "LOAD T"). The ".s19" file is then uploaded through the terminal program's text upload feature, or through the cut and paste method.
When this program is run by typing "call 8000," it will continuously display the state of all the inputs. The display should change as the test switch connected to an input line is pressed and released. Also, as the test switch is pressed and released, pin 19 of U3 (A=B output of comparitors) should go from logic 0 to logic 1 briefly, then return to logic 0, indicating that the correct data is being loaded, and then sent to the board thus balancing the comparitors.
Example 1. This screen shot shows digtest1 in operation.
Once the basic operation of the board has been checked, the next step is to verify operation using the interrupt system and basic queue operation. Assemble and load digtest2.asm. Or use the pre-assembled file digtest2.s19 The assembler listing, digtest2.lst, can be used for reference. Digtest2 demonstrates a more "real time" response system. When running, any changes to the input lines generates an interrupt. The Interrupt Service Routine (ISR) communicates with the board, obtains the latest state of all the lines, then sends the same data back to the board in order to balance the comparitors and reset the interrupt line (derived from pin 19 of U3). Rather than do something directly, the ISR simply creates an "event packet" and places it on the normal event queue. The benefit of this scheme is that the ISR doesn't have to know anything about what the event means. This "event" (a 1000 type packet) simply means that something on the board changed, here's the new state of all 16 inputs. It is usually important to keep the amount of programming inside interrupt service routines as small and fast as possible for the best overall system response. The digital input system does this by doing nothing more than creating a packet on a queue - then it's finished. Note that this test program uses 8 byte event packets while the next program, Homesys, uses 16 byte packets.
Example 2. This screen shot shows digtest2
in operation. Dots are printed to
It's interesting to try out the system, then take a look at the data in the actual event queues to see the results of the test. The memory areas that the queues occupy can be filled with some value before the run, so that the queue activity is more obvious. The command "bf 9000 91ff aa" will block fill both queue areas with the value "AA." The normal queue is set to start at address 9000, while the high priority queue is immediately after it, at address 9100, therefore this command fills both in one step. Any value can be used, but an unlikely value to appear in the packets is best such as hex value AA. Note that digtest2.asm uses smaller 8 byte packets.
Example 4. Displaying data in event queues
To run homesys, first load the homesys.s19 file included in the archive, or compile your own. Upload the program as with the previous examples. Issue the command "call 9500" to start the program. Period characters should start zipping across the screen. Now, upload the configuration file by pressing "L," then send the configuration file (using ASCII upload or the cut and paste method). After the successful upload, trigger an input line that has an action defined for it in the configuration file. Packets should be queued, and the desired operation should take place. Lines on the terminal screen should look similar to example 2 above.
Expanding the system.