next up previous
Next: What is a 7-segment Up: Background Previous: Background

What is an input/output port?

A micro-controller such as the MicroStamp11 has a number of pins as shown in the pinout of figure 1. The MicroStamp11 communicates with the outside world by changing the logical state of these pins or by reading the logical state of the pins. The logical state of a pin is said to be high if the voltage of the pin relative to ground is 5 volts. The logical state is low if the voltage on the pin is zero (relative to ground).

Figure 1: MicroStamp11's pinout
\begin{figure}
\epsfxsize =3.in
\epsfclipon
\centerline{\epsffile{fig-root/pinout_fig.eps}}
\end{figure}

The majority of the pins on the MicroStamp11 are arranged into two ports that have the logical names PORTA and PORTD. PORTA has 8 pins associated with it (pins 1 through 8 on figure 1). PORTD has 6 pins associated with (pins 15-20). The other 6 pins on the MicroStamp11 are either used for power (pins 10-12) or they are special input pins that can interrupt the execution of a program (pins 9, 13, and 14). Our current interest is with the I/O pins associated with PORTA/PORTD (pins 1-8 and 15-20).

The pins on PORTA/PORTD have two distinct types of states. The logical state, as mentioned above, refers to the voltage level on the pin (5 volts or zero volts). In addition to this, however, each pin has a direction state. In other words, the MicroStamp11 either reads from or writes to a pin; it cannot do both at the same time. This means that each pin on PORTA/PORTD has a directional state that is either IN or OUT. When a pin has the OUT directional state it behaves like an independent voltage source of 0/5 volts. When a pin has the IN directional state it behaves as a high resistance load on the circuit it is connected to.

The MicroStamp11 can control the direction state and logical state of the I/O pins by writing to specific memory locations in its RAM's address space. Remember that Micro-controllers like the MicroStamp11 directly map their I/O pins to hardware registers that are in turn mapped to specific locations in the device's address space. The file kernel.c defines the logical names for these hardware registers controlling the port's logical state. These logical names are PORTA and PORTD. They are 8-bit variables in which each bit is associated with one of the pins on the I/O port.

As mentioned above, these ports can serve as either inputs or outputs. At a given time a pin can only act as input or output, not both. The directional state of an I/O pin is determined by setting appropriate bits in a direction register. Direction registers are hardware registers that can be written to or read from by a program because they are mapped directly into the device's address space. The logical name for PORTD's direction register is DDRD. If the $i$th bit in DDRD is set high, then the $i$th pin on PORTD has its directional state set to output. If the $i$th bit in DDRD is low (0), then the $i$th pin on PORTD is treated as an input pin.

The pins on PORTA are somewhat special in that not all of the pins' are bi-directional. In fact, only two of the pins (PA3-pin5 and PA7-pin1) can have their direction states changed. This is accomplished by setting the appropriate bits in a hardware control register with the logical name PACTL (PortA's control register). The logical names DDRA7 and DDRA3 refer to bytes in which only the 7th and 3rd bit are set to one. Through the use of bitwise operators, we can use these logical names to set, clear, or toggle the specified bits in PACTL, thereby controlling the directional state of these pins. The other pins in PORTA have their directional states fixed because they are associated with specific input or output interrupt functions. In particular, the directional state of pins 2-4 (PA4-PA6) is always OUTPUT, whereas the directional state of pins 6-8 (PA0-PA2) is always IN.

If an I/O pin's directional state is OUTPUT, then we can change its logical state by simply writing a 1 or 0 to the appropriate bit in the port's register. So let's assume that we wish to set pin PD5 (To "set a pin" means to make its logical state HIGH. To "clear a pin" means to set its logical state LOW). The following C-language code segment uses bitwise OR operators to accomplish this

 DDRD |= bit(5);
 PORTD |= bit(5);
The macro bit(i) produces a byte that only has its $i$th bit set to one. This macro is defined in the kernel (kernel.c). The first statement sets the 5th bit in the DDRD register to one, thereby setting the pin's directional state to output. The second statement sets the logical state of the 5th bit to high. If we wish to clear this pin, then we must use a bitwise logical operator on the NOT (complement) of bit(5). This is done in the following code segment
  DDRD |= bit(5);
  PORTD &= ~bit(5);
As before the first statement sets PD5's directional state to OUT. The second statement is equivalent to the statement PORTD = PORTD & (~bit(5)) which simply switches the 5th bit in PORTD to zero.

Setting the logical state for pins in PORTA is similar. Recall that only pins PA3-PA7 can take an OUT directional state. The following code segment sets pin PA7, clears PA5, and toggles PA3.

 PACTL |= DDRA7;
 PORTA |= bit(7);
 PORTA &= ~bit(5);
 PACTL |= DDRA3;
 PORTA ^= bit(3);
We used DDRA7 and DDRA3 to set the appropriate bits in PORTA's control register so that pins PA7 and PA3 are output pins. Note that we did not need to do this for PA5 since it is always an output pin.

To read the logical state of an I/O pin, the pin's directional state must be set to IN. This is accomplished by setting the appropriate bit in the PORT's control/direction register to zero. Once this is done, we can simply read the bit by testing it to see if that bit is one or zero. The following code segment does this for pin PD5 on PORTD.

 DDRD &= ~bit(5);
   if((PORTD & bit(5))==0){
     OutString("PD5 = LOW");
   }else{
     OutString("PD5 = HIGH");
   }
As before the first statement clears the 5th bit in PORTD's direction register thereby making sure PD5 is an input pin. The logical test computes the logical AND of PORTD and bit(5). This logical AND returns a 0 only if the fifth bit in PORTD is zero. If this occurs, our program writes out that PD5 is LOW. If the logical AND does not return 0, then we know the 5th bit must have been set and so the program writes out that PD5 is HIGH. A similar type of test can be used to test the status of pin PA2.
 if((PORTA & bit(2))==0){
   OutString("PA2 = LOW");
 }else{
   OutString("PA2 = HIGH");
 }
Notice that we didn't need to set any bits in PORTA's control register because PA2 is always an input pin. If we had attempted to read pin PA3 or PA7, of course, then we would need to set the appropriate pins (DDRA3 or DDRA7) in control register PACTL.


next up previous
Next: What is a 7-segment Up: Background Previous: Background
Michael Lemmon 2009-02-01