Encoder Front Page
SRS Home | Front Page | Monthly Issue | Index
Google
Search WWW Search seattlerobotics.org


Multiplexing To Get More Outputs

by Tom Dickens

Introduction

Assuming that your system has some digital outputs, but you need more outputs for the current project you're working on, what do you do? This article will explain how to add as many digital outputs to your system as you desire. The types of systems I'm referring to are typically microcontrollers, such as the 68HC11, 68HC12, 68332, PIC chip, BASIC Stamp, ATMEL processor, and a host of others. This technique can also be applied to the parallel-port output of a PC. I will present this information in a generic manner, which should apply to any target system. The usage examples will be in pseudo-code and then in assembly code which are specific to the 68HC11, but this could be easily adapted to any other system.

The Concept

You can use a limited number of digital outputs, along with a simple digital circuit and a simple program, to control as many digital outputs as you desire. The type of circuit we're talking about here is a multiplexer, or MUX for short. With a MUX circuit, you take your digital outputs from your system and group them into two types, data lines and address lines. Depending on the number of system digital outputs you have to work with, and how you group them into address lines and data lines, you can get various numbers of resulting MUX outputs, plus varying complexity of the required digital circuit.

 

 

 

 

 

 

 


Figure 1. Concept of system outputs generating more outputs using a multiplexer circuit.

 

Let's walk through an example using 8 system digital output lines to see the possibilities:

 

Table 1. Address/Data combinations for 8-bit output.

Starting Outputs

Address Lines (A)

Data Lines (D)

Resulting Outputs

8

0

8

8

8

1

7

14

8

2

6

24

8

3

5

40

8

4

4

64

8

5

3

96

8

6

2

128

8

7

1

128

The top row in Table 1 shows us that if we use all 8 lines as data lines, we get 8 resulting output lines (and our circuit is very simple, just wires). The next row uses one of the lines as an address and the other 7 as data. With the address set to 0, we can specify 7 data values and then with the address set to 1 we can specify 7 more data vales, giving us 14 resulting output lines. Continuing down the rows we see that the same 8 system outputs can generate up to 128 resulting outputs. Wow! There is a generic equation to determine the resulting number of outputs we would get. Given N as the total number of system outputs, A is the number of address lines, D is the number of data lines, where A + D = N, we can calculate:

2A * D = R (the resulting output lines) Equation 1.

 

Choosing N=8 we can vary A, which generates D and R.

Figure 2. Plot of data from Table 1; Address to resulting outputs for 8-bit multiplexer.

We can clearly see in the plot in Figure 2 that the more lines we use as addresses, the more resulting outputs we will generate. We can, using Equation 1, see the number of outputs we can get for different numbers of address and data lines.

However, there is a price to be paid for this; the complexity of the required digital circuit, and the complexity and time required to execute the resulting driving program, goes up with the number of address lines. Another factor is the type and configuration of the digital chips that are available to use in the support circuit. In a minute we will look at practical limitations and implementations.

Considering using from 4 to 12 output lines. Figure 3 shows how many outputs could be generated. The maximum for 11 bits is 1024, and for 12 bits is 2048, which is a very large number of outputs from a small number of original output lines

 

Figure 3. Possible number of outputs for 4 through 12 lines.

Before we jump into building a 12-to-2028-output circuit, let's first consider the building blocks available and the hardware/software complexity required, so we can design a reasonable system which can be easily built and easily used, but also gives us a good expanded-output capability.

Circuit Building Blocks

The digital chips available that we will use to build up our multiplexing output circuit are the 74HCnnn family of chips, but similar functionality can be found in the other 74-series (74LS for example), and also in the old 4000-series CMOS devices.

Address Lines

For the address lines, we need to "fan out" the address into N control lines (we'll see why in a moment). The type of device we want here is called a "decoder," also referred to as a "demultiplexer." These take A address lines, and produce 2A outputs, where one output as specified by the address is at one logic level (typically Low), and all the other outputs are at the other logic level (typically High). The two most-used 74HCnnn devices for this are the 74HC138 (1-of-8 decoder) and the 74HC154 (1-of-16 decoder). The '138 (short for 74HC138) takes 3 address lines and produces 8 control lines, while the '154 takes 4 address lines and produces 16 control lines. The typical logic-symbol for such a device is shown in Figure 4.

Figure 4. Decoder logic symbol.

 

The 3 address lines are A0, A1, and A2. There are also 3 enable lines which can be used to configure multiple '138 devices to directly handle up to 6 input address. To enable a device, tie E1 and E2 low and E3 high. The 8 generated outputs are Y0 trough Y7. The circles on the diagram indicate that the active level for that pin is inverted, thus we can see that E1 and E2 should be low (inverted), E3 should be high, and the output addressed in Y0 to Y7 will be low (all other 7 outputs will be high).

Table 2 is a truth-table for the 74HC138, showing the states of the outputs for all input combinations. The '-' entries are "don't care" states. H is logic high, or 5 volts. L is logic low, or 0 volts. Note that any enable input can disable the device.

Table 2. Truth-table for the 74HC138 decoder/demultiplexer..

Address

Lines

Enable Lines

Output Lines

A2

A1

A0

E3

E2

E1

Y7

Y6

Y5

Y4

Y3

Y2

Y1

Y0

-

-

-

-

-

H

H

H

H

H

H

H

H

H

-

-

-

-

H

-

H

H

H

H

H

H

H

H

-

-

-

L

-

-

H

H

H

H

H

H

H

H

L

L

L

H

L

L

H

H

H

H

H

H

H

L

L

L

H

H

L

L

H

H

H

H

H

H

L

H

L

H

L

H

L

L

H

H

H

H

H

L

H

H

L

H

H

H

L

L

H

H

H

H

L

H

H

H

H

L

L

H

L

L

H

H

H

L

H

H

H

H

H

L

H

H

L

L

H

H

L

H

H

H

H

H

H

H

L

H

L

L

H

L

H

H

H

H

H

H

H

H

H

H

L

L

L

H

H

H

H

H

H

H

Data Lines

For the data lines, we need to capture the data and hold their values until we want it to change. The type of device we want here is called a "latch" or a "flip-flop" (FF). These devices take D data lines and will capture their values when commanded to do so. The commonly-used 74HCnnn devices for this are the 74HC74 (dual flip-flop, 2 in one chip), 74HC173 (quad flip-flop, 4 in one chip), 74HC174 (hex flip-flop, 6 in one chip), and the 74HC374 (octal flip-flop, 8 in one chip).

Figure 4. 8-bit latch logic symbol.

These devices have data inputs, data outputs, a clock input, and output enable inputs. The data on the inputs is captured and presented at the outputs when the cock input goes from a low to a high state. Tie the output enable(s) to enable the device (low on the '374).

Figure 4 shows the typical logic-symbol for a 74HC374 8-bit latch.

 

There is a device, the 74HC574 which is identical in functionality to the '374, but all the data inputs are on the left side of the chip, and all the outputs are on the right side of the chip. This makes it much easier to wire up; many people commonly use the '574 for this reason even though the two devices are logically identical.

Putting it All Together

How does this work? Let's use a example to walk through the setup and use of a typical system.

The Hardware

Assume we have 8 system outputs (O0 trough O7) from a microcontroller and we want more outputs. Let's call 2 of these outputs address lines, and 6 of them data lines. With 2 address lines, we will generate 4 control outputs (Y0 through Y3 in Figure 5). Each of these is connected to the clock input of one of the flip-flip devices. The 6 data lines (O2 through O7) are connected to the data input lines (D0 through D5) of all 4 of the hex flip-flops. The resulting outputs are generated from the 4 flip-flops as outputs R0 through R23. Thus, with 5 common off-the-shelf chips, we have turned 8 outputs into 24 outputs.

Figure 5. 8-bit to 24-bit multiplexer circuit.

The Software

To use the circuit detailed above, the software in the system must know about the specific hardware connected to the 8-bit output lines. Given a 24-bit number to output, what does the software need to do? Simply stated:

 

We need to present the correct data to the 6 data lines and then cause the correct output from the 138 to go from low to high to capture the data on the data lines into the correct latch.

 

OK, well walk through this specific example step-by-step. But first, we need to diverge into the topic of Gray Codes. Frank Gray, a research scientist at Bell Labs, on 3/17/1953, filed patent no. 2,632,058 for the Gray code encoding vacuum tube. Were not using vacuum tubes, but the principle is very important here too. Gray code is a sequence of binary numbers such that any two consecutive numbers differ only in a single position. Lets consider the repeating cycle of numbers 0 through 3 as seen in Table 3.

Table 3. Gray Code for a 2-bit number cycling from top to bottom.

Decimal

Binary

Gray Code

0

00

00

1

01

01

2

10

11

3

11

10

0

00

00

1

01

01

2

10

11

3

11

10

 

The red cells in the table cause a problem in our decoding circuit; two bits are changing at the same time as we enter the cell. An actual digital circuit CANNOT change two things at exactly the same time; there will be a slight lag in one of them. So in switching from binary number 00 to 11, for example, the circuit will momentarily pass through either 01 or 10. This will cause a very short change in the corresponding Y1 or Y2 output of the decoder, which will cause the wrong data to be captured in the corresponding latch. Ive seen this problem in embedded software; it is hard to find and it really messes things up! The key is to only change 1 bit at a time, even from the last value back to the fist value, so the decoder will change its Y outputs in a very controlled manner, which is goodness. We dont need to change anything in the circuit to achieve this goodness, we just need to remember to use Gray Code switching in our controlling software, or else our outputs will be very strange and not what we want them to be, and you may think you have a hardware circuit error. Now, on to our code.

Starting assumption: The address bits on the output line are all low from the previous write.

  1. Set the address lines O1-O0 to L L (should already be in this state).
  2. Set the data values V5-V0 on the data lines O7-O2.
  3. Set the address lines O1-O0 to L H. This causes the data values to be captured in the first (right-most) flip-flop as line Y0 goes from LOW to HIGH. Also note that Y1 will now be LOW.
  4. Set the data values V11-V6 on the data lines O7-O2.
  5. Set the address lines O1-O0 to H H (remember, we need to use Gray Code!). This causes the data values to be captured in the second flip-flop.
  6. Set the data values V23-V18 on the data lines O7-O2.
  7. Set the address lines O1-O0 to H L. This causes the data values to be captured in the forth flip-flop.
  8. Set the data values V17-V12 on the data lines O7-O2.
  9. Set the address lines O1-O0 to L L. This causes the data values to be captured in the third flip-flop.

Of course, in your system you would write a subroutine to do this, so your program would just invoke the subroutine to get the job done.

What does this software look like? How does it do the 8 steps details above?

Listing 1 shows a detailed assembly-language program for the 68HC11. The operations used are bit-level manipulations, such as bit-shifting, bit-masking, and bit-setting and bit-clearing. You can accomplish these operations using math-type operations, but the clearest way to do these operations is to use the bit-level operations in your system (I bet you always wondered what they were, and why anyone would every want to use them). In assembly code these operations are the logical shift and bitwise AND, OR, and NOT operators. In C, C++, and Java, look at the shift (<< >>) operations, the bitwise (| & ^) operators.

Practical Limitations

OK, we've seen the theoretical fan-out we can achieve, but let's consider the common building-blocks and what would be practical to build and use. We could use devices without using all of their capabilities, but if you're building an external circuit for your system you would want to keep it as small as possible for reasons of cost, footprint (size), and complexity to build.

We see the 74HC138 decoder is a great 1-chip workhorse that can directly take 3 address lines and produce 8 control lines. Two '138 devices can be combined with 4 address lines (3 in common, and the 4th selecting which '138 to use, for example, address lines A0-A2 connected to the address inputs of both '138s, and the last address line, A3, connected to E1 on one '138 and E3 on the other). Two '138s will produce 16 control lines, or you could use a single 74HC154 (The '138 is a 16-pin chip while the '154 is a wider 24-pin chip. Multiple '138 chips are commonly used). A single '138 can be used with only 2 address lines (A0 and A1, connect A3 to ground), which would then only generate 4 usable control lines, Y0 through Y3.

The other type of device required is a flip-flop to capture the outputs. The four devices discussed handle 2 bits, 4 bits, 6 bits, and 8 bits. The 4, 6, and 8 bit devices all have a common clock, which means that all 4, 6, or 8 bits will be changed at the same time. For some applications this is a problem, but for our purposes this is what we want. Therefore, the "best" combination is one which uses 6 or 8 data lines, since these can be captured in a single flip-flop device for each address. If you use 5 data bits you would use a 6-bit flip-flop and not use on of the bits, and so on.

Let's revisit Table 1, but add columns for the number of chips required to implement each circuit. I've highlighted the interesting numbers in Table 4 in red, showing the number of decoders and flip-flops needed to implement the circuit.

Table 4. Numbers of devices needed for circuits with various latch sizes.

Starting
outputs

Address
lines (A)

Data
Lines (D)

Total
Outputs

74HC138
3-8 decoder

74HC74
2-bit FF

74HC173
4-bit FF

74HC174
6-bit FF

74HC374
8-bit FF

8

0

8

8

0

0

0

0

0

8

1

7

14

1

0

0

0

2

8

2

6

24

1

0

0

4

0

8

3

5

40

1

0

0

8

0

8

4

4

64

2

0

16

0

0

8

5

3

96

4

0

32

0

0

8

6

2

128

8

64

0

0

0

8

7

1

128

14

64

0

0

0

 

Let's suppose you really need 128 outputs. The two solutions above can accomplish this, but need from 72 to 78 chips. I don't know about you, but I wouldn't want to build that! Let's consider different combinations of address and data lines (assuming you have a few more than 8 starting system outputs to work with) to achieve 128 outputs. Note that some of these circuits will not use all control outputs generated. Again, I've highlighted the interesting numbers in table 5 in red:

Table 5. Numbers of devices needed for circuits with various latch sizes to generate 128 outputs.

Starting
outputs

Address
lines (A)

Data
Lines (D)

Total
Outputs

74HC138
3-8 decoder

74HC74
2-bit FF

74HC173
4-bit FF

74HC174
6-bit FF

74HC374
8-bit FF

8

6

2

128

8

64

0

0

0

9

5

4

128

4

0

32

0

0

10

5

5

128

4

0

0

26

0

11

5

6

128

4

0

0

22

0

12

4

8

128

2

0

0

0

16

We clearly see, if we can spare a few more system outputs we can easily generate 128 outputs with much less external circuitry (and effort). If I needed 128 outputs I know I would try to come up with 12 starting outputs and build the 18-chip circuit.

I should mention that you could use a two-level fan-out scheme, such as using 5 starting outputs to fan-out to 12 outputs (2 address lines and 3 data lines), then use these 12 intermediate outputs to fan-out to 128 outputs as we saw above. The software would need to use 4 writes to generate a single 12-bit number, and it would require 16 12-bit numbers to set all 128 output bits. There is also the issue of timing with the edge-triggered flip-flops, which would really force you to use 6 starting bits (2 address lines and 4 data lines) to allow the 4 address lines for the second stage to be changed all at the same time. Using multi-level designs you can fan-out to as many outputs as desired with a very small number of starting outputs, but the required hardware and software would become more and more complex.

Example Circuits and Software

Let's choose a couple of desired configurations and look at the detailed circuits and software. Two that I'm currently adding to 68HC11 systems for robotic use will go from 8 system outputs to 24 outputs, and 11 system outputs to 64 outputs. We will then go on to detail how to use these in the supporting software. Of course, my hope is that you can take the information presented here and customize it to build up the desired circuit and software for your particular application.

8 Outputs to 24 Outputs

The program to drive the miltiplexer circuit is organized as a method that is called to set the entire 24-bit bit number. The application program just calls this method whenever it wants to change these outputs. The pseudo code for this is what we saw before. The hardware requires a 2-bit address and a 6-bit data value. Let's assume this is connected to the B port on the 68HC11, which resides at address $1004.

The software to do this in 68HC11 assembly language is shown in Software Listing 1. Anything after a ";" sign is a comment, which are used describe the logic.

11 Outputs to 64 Outputs

Building on the ideas weve discussed, here is a 9-chip solution to expanding 11 system outputs (3 address and 8 data) to 64 outputs. It uses a single 74HC138 decoder and uses the 8 lines from it to drive eight 8-bit latches for a total of 64 bits.

 

Figure 6. 11-bit to 64-bit multiplexer circuit.

The circuit can be easily wired up from the connections in Figure 6, and the software will be an expansion of the code for the 10-to-32 multiplexer circuit in Software Listing 2.

Conclusions

We have discussed the technique of expanding a small number of digital outputs into a very large number of outputs. We have considered the available off-the-shelf devices commonly used to implement a multiplexer circuit, which in turn dictates the practical limits to these designs.

About The Author

Tom Dickens is an engineer and Associate Technical Fellow at The Boeing Company, where he is a technical architect working on both pure software systems and embedded systems. He also teaches at Seattle colleges in the evenings, currently at the Washington branch campus of the University of Phoenix. Tom is an active member of the Seattle Robotics Society ( http://seattlerobotics.org/) and maintains a web-site of 68HC11 information and examples ( http://tomdickens.com/68hc11/intro.html ).

 

Software Listing 1. 68HC11 code to drive the 8-bit to 24-bit multiplexer circuit.

* Method: SetOutputs
* Purpose: To take a 24-bit input number and set the value
* on a special 24-bit hardware circuit.
* Input: 24-bit number in memory, pointed to by the X register.
* Register Usage:
* X register points to the 24-bit data value. These 24 bits are 
* arranged as the high 8 bits in memory location X, the middle 8 bits
* in memory address X+1, and the low 8 bits in memory location X+2.
* here are the numbered data-value bits showing where they are in
* memory, and where they will end up in the Flip-Flops (FF n).
* 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +----- byte x+0 ------+ +----- byte x+1 ------+ +----- byte x+2 -----+
* +---- FF 3 -----+ +---- FF 2 -----+ +---- FF 1 -----+ +---- FF 0 -----+
*
* A working register for calculations.
* B working register for calculations.
* Hardware is located on the B port, address $1004. The first 2 bits
* are the address bits (B0 and B1), the remaining 6 bits are the data
* (B2 through B7).
* Author: Tom Dickens, 7/1/2002
*
* define a label for the method
SetOutputs:
 psha ; save the value in the A register
 pshb ; save the value in the B register
 
 ldaa #3 ; A = 3
 staa $1004 ; set the hardware address to 3, our desired starting state
 
* do the first 6 bits (bits 5-0 to flip-flop 0)
* In () the number show the bit-positions, - are zero-value bits.
 ldab 2,x ; B = data bits (7 6 5 4 3 2 1 0)
 lslb ; shift data bits to the left, (6 5 4 3 2 1 0 -)
 lslb ; shift data bits to the left, (5 4 3 2 1 0 - -)
 adda #3 ; A = A + 3 = (address = 3 ) (5 4 3 2 1 0 A A)
 staa $1004 ; Set the data without changing the address (add=3)
 anda #%11111100 ; set bits 1 and 0 to zero, keep the rest the same (add=0)
 staa $1004 ; Set the address lines to capture data in the first flip-flip
 
* do the second 6 bits (bits 11-6 to flip-flop 1)
 ldab 2,x ; B = data bits ( 7 6 5 4 3 2 1 0)
 andb #%11000000 ; set all bits but 7-6 to zero ( 7 6 - - - - - -)
 lsrb ; shift bits 7-6 right to places 6-5 ( - 7 6 - - - - -)
 lsrb ; shift bits 7-6 right to places 5-4 ( - - 7 6 - - - -)
 lsrb ; shift bits 7-6 right to places 4-3 ( - - - 7 6 - - -)
 lsrb ; shift bits 7-6 right to places 3-2 ( - - - - 7 6 - -)
 ldaa 1,x ; A = data bits (15 14 13 12 11 10 9 8)
 anda #%00001111 ; set all bits but 3-0 to zero ( - - - - 11 10 9 8)
 lsla ; shift bits 3-0 left to places 4-1 ( - - - 11 10 9 8 -)
 lsla ; shift bits 3-0 left to places 5-2 ( - - 11 10 9 8 - -)
 lsla ; shift bits 3-0 left to places 6-3 ( - 11 10 9 8 - - -)
 lsla ; shift bits 3-0 left to places 7-4 (11 10 9 8 - - - -)
 aba ; A = A + B = (address = 0) (11 10 9 8 7 6 A A)
 staa $1004 ; Set the data without changing the address (add=0)
 adda #1 ; A = A + 1 = (address = 1) (11 10 9 8 7 6 A A)
 staa $1004 ; Set the address lines to capture data in the second flip-flip
 
* do the third 6 bits (bits 17-12 to flip-flop 2)
 ldab 1,x ; B = data bits (15 14 13 12 11 10 9 8)
 andb #%11110000 ; set all bits but 7-4 to zero (15 14 13 12 - - - -)
 lsrb ; shift bits 7-4 right to places 6-3 ( - 15 14 13 12 - - -)
 lsrb ; shift bits 7-4 right to places 5-2 ( - - 15 14 13 12 - -)
 ldaa 0,x ; A = data bits (23 22 21 20 19 18 17 16)
 anda #%00000011 ; set all bits but 1-0 to zero ( - - - - - - 17 16)
 lsla ; shift bits 1-0 left to places 2-1 ( - - - - - 17 16 -)
 lsla ; shift bits 1-0 left to places 3-2 ( - - - - 17 16 - -)
 lsla ; shift bits 1-0 left to places 4-3 ( - - - 17 16 - - -)
 lsla ; shift bits 1-0 left to places 5-4 ( - - 17 16 - - - -)
 lsla ; shift bits 1-0 left to places 6-5 ( - 17 16 - - - - -)
 lsla ; shift bits 1-0 left to places 7-6 (17 16 - - - - - -)
 aba ; A = A + B = (17 16 15 14 13 12 - -)
 adda #1 ; A = A + 1 = (address = 1) (17 16 15 14 13 12 A A)
 staa $1004 ; Set the data without changing the address (add=1)
 adda #1 ; A = A + 1 = (address = 2) (17 16 15 14 13 12 A A)
 staa $1004 ; Set the address lines to capture data in the third flip-flip
 
* do the forth 6 bits (bits 23-18 to flip-flop 3)
 ldaa 0,x ; A = data bits (23 22 21 20 19 18 17 16)
 anda #%11111100 ; set all bits but 7-2 to zero (23 22 21 20 19 18 - -)
 adda #2 ; A = A + 2 = (address = 2) (23 22 21 20 19 18 A A)
 staa $1004 ; Set the data without changing the address (add=2)
 adda #1 ; A = A + 1 = (address = 3) (23 22 21 20 19 18 A A)
 staa $1004 ; Set the address lines to capture data in the forth flip-flip
 
 pulb ; restore the value in the B register
 pula ; restore the value in the A register
 rts ; return from the method
 
* Method: SetBit
* Purpose: To take a 24-bit input number and set the specified bit.
* Input: 24-bit number in memory, pointed to by the X register.
* A register is a bit position, 0 through 23.
* Register Usage:
* X register points to the 24-bit data value. These 24 bits are 
* arranged as the high 8 bits in memory location X, the middle 8 bits
* in memory address X+1, and the low 8 bits in memory location X+2.
* here are the numbered data-value bits showing where they are in
* memory, and where they will end up in the Flip-Flops (FF n).
* 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +----- byte x+0 ------+ +----- byte x+1 ------+ +----- byte x+2 -----+
* A Input value for bit-position, 0 through 23.
* B working register for calculations.
* Author: Tom Dickens, 7/1/2002
SetBit:
 bsr SetupSetClear
 anda 0,x ; A = A and (X). And the value in A with the data in memory
 bra ExitSetClear
 
* Method: ClearBit
* Purpose: To take a 24-bit input number and clear the specified bit.
* Input: 24-bit number in memory, pointed to by the X register.
* A register is a bit position, 0 through 23.
* Register Usage:
* X register points to the 24-bit data value. These 24 bits are 
* arranged as the high 8 bits in memory location X, the middle 8 bits
* in memory address X+1, and the low 8 bits in memory location X+2.
* here are the numbered data-value bits showing where they are in
* memory, and where they will end up in the Flip-Flops (FF n).
* 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +----- byte x+0 ------+ +----- byte x+1 ------+ +----- byte x+2 -----+
* A Input value for bit-position, 0 through 23.
* B working register for calculations.
* Author: Tom Dickens, 7/1/2002
ClearBit:
 bsr SetupSetClear
 eora #$FF ; A = NOT A (flip all bits in A to create a mask with 1 zero bit))
 ora 0,x ; A = A or (X). And the value in A with the data in memory
 bra ExitSetClear
 
* Method: SetupSetClear
* Purpose: Common logic for SetBit and ClearBit.
* Output: B is in the range from 0 to 7, and X points to the correct
* position in memory to directly access the requested data byte.
* Author: Tom Dickens, 7/1/2002
SetupSetClear:
 psha ; save the value in the A register
 pshb ; save the value in the B register
 pshx ; save the value in the X register
 anda 0,x ; A = A and (X). And the value in A with the data in memory
 staa 0,x ; put modified data back to memory
 
 tab ; B = A
 suba #8 ; test A value with the number 8
 blt Range0to7
 tba ; A = B
 suba #16 ; test A value with the number 16
 blt Range8to15
 tba ; A = B
 suba #24 ; test A value with the number 24
 blt Range16to23
* Error, we should NOT have a value not in the range of 0 to 23.
* We may want to flag the error somehow...
 bra ExitSetClear
 
Range0to7:
 inx ; X = X + 1
 inx ; X = X + 1 (Point X to the third byte, bits 7 to 0)
 bra DoSetBit ; jump to common logic
 
Range8to15:
 subb #8 ; B = B - 8 (now in the range of 0 to 7)
 inx ; X = X + 1 (Point X to the second byte, bits 15 to 8)
 
Range16to23:
 subb #16 ; B = B - 16 (now in the range of 0 to 7)
 bra DoSetBit ; jump to common logic
DoSetBit:
* X points to the byte to change
* B is a value from 0 to 7 for the bit to set
 ldy #BINARY_TABLE
 aby ; Y = Y + B (point to the correct bit mask from table)
 ldaa 0,Y ; get the bit mask in A
 rts
 
* Method: ExitSetClear
* Purpose: Store the calculated value and clean-up.
* Author: Tom Dickens, 7/1/2002
ExitSetClear:
 staa 0,x ; put modified data back to memory
 pulx ; restore the value in the X register
 pulb ; restore the value in the B register
 pula ; restore the value in the A register
 rts ; return from the method
 
* Data table to support the SetBit and ClearBit methods.
BINARY_TABLE:
 fcb $01, $02, $04, $08, $10, $20, $40, $80 ; Used to generate a specific bit mask

 

Software Listing 2. 68HC11 code to drive a 10-bit to 32-bit multiplexer circuit.

*
* 32mux.asm
* Tom Dickens - 10/27/2002
* Program to talk to the 10x32 MUX board.
* There are 8 data lines and 2 address lines to the MUX board.
* Data lines are B0-B7
* Address lines are A6 and A7
* This test program will do a binary count on the 32-bit output.
*
 ORG $B600
 BSR Init32 ; this clears address 0-3 
 
Top:
 BSR Load32 ; put the 32-bits of data to the MUX
 INC $00 ; Increment data in address 0
 BNE Top ; if it rolled over to zero, increment next
 INC $01 ; Increment data in address 1
 BNE Top ; if it rolled over to zero, increment next
 INC $02 ; Increment data in address 2
 BNE Top ; if it rolled over to zero, increment next
 INC $03 ; Increment data in address 3
 BRA Top ; goto top
 
* Initialize the 32-MUX stuff.
* Set the address to 11, and set the address lines to outputs.
Init32:
 PSHB
 LDAB $1026 ; get the current value from Port A
 ORAB #%10000000 ; set bit 7, data direction for A7
 STAB $1026 ; set PACTL
*
 CLR $1004 ; clear output on Port B
 LDAB $1000 ; get the current value from Port A
 ANDB #%00111111 ; clear bits A6 and A7
 STAB $1000 ; set address 0
*
 LDAB #$00
 STAB $00 ; set 32-bits in memory to zero.
 STAB $01
 STAB $02
 STAB $03
 BSR Load32 ; put the 32-bits of data to the MUX
*
 PULB
 RTS
 
* Subroutine to take data from memory addresses 0-3 and 
* put that 32-bits of data to the MUX board. 
* Assumes that the address is set to 00. Will leave it
* in that state.
* Don't load address 0, 1, 2, in order, since the change
* from 1 to 2 is a 2-bit change and can cause a glitch in
* the 74HC138s output. Instead make sure to use Gray code,
* which has a 1-bit change. Thus we will order the addresses
* 0, 1, 3, 2.
Load32:
 PSHA
 PSHB
 LDAB $1000 ; get the current value from Port A
 ANDB #%00111111 ; clear bits A6 and A7
* Do 0
 LDAA $00  ; get data from address 0
 STAA $1004 ; put data to Port B
 
* Do 1
 ORAB #%01000000 ; set bit A6
 STAB $1000 ; set address 1
 LDAA $01  ; get data from address 1
 STAA $1004 ; put data to Port B
 
* Do 3
 ORAB #%11000000 ; set bits A6 and A7
 STAB $1000 ; set address 3
 LDAA $03  ; get data from address 3
 STAA $1004 ; put data to Port B
 
* Do 2
 ANDB #%00111111 ; clear bits A6 and A7
 ORAB #%10000000 ; set bit A7
 STAB $1000 ; set address 2
 LDAA $02  ; get data from address 2
 STAA $1004 ; put data to Port B
 
* Set back to 0
 ANDB #%00111111 ; clear bits A6 and A7
 LDAB #%00000000
 STAB $1000 ; set address 0
*
 PULB
 PULA
 RTS
*