07 June 2010

Configuring Inputs & Outputs

The MSP430 becomes especially useful in the laboratory environment when it is used to collect information and send information in conjunction with equipment and measuring instruments. To do this, the chip needs an electrical connection with the transducers, or motors, or whatever other devices are being used. These connections are made through input and output ports.

All MSP430 microcontrollers have general input/output ports. The larger chips, of course, have more ports available, but even the smallest chips have pins for input and output. One of the nice features of these microcontrollers is that the pins can be used as an input or as an output; each port is normally associated with up to 8 pins, and each can individually be an input or an output, and can even change function in the middle of a program. The MSP430F2132 has 3 ports (24 pins) available that can be configured for general I/O.

Keep in mind that,while for low power systems the MSP430 is able to drive devices directly (assuming they run well at 3.3V), many devices will need to be controlled/sampled with transistors and amplifiers, or other intermediate components, to prevent damaging the MSP430 with high voltages or currents.
Part of the memory space in the MSP430 is set aside as specific registers, which are used to store information on how the chip should behave. The behavior of each pin on a port is controlled with the register P#DIR, where the # corresponds to the particular port being used. P#DIR is a 1 byte value with each bit corresponding to one pin for the port. For example, the 3rd bit on P1DIR controls P1.3. (Remember that the bits are numbered 0-7, not 1-8, so the 3rd bit is actually the 4th least significant digit.) When a bit in P#DIR is set to 0, the pin is configured as an input. When it is set to 1, the pin works as an output. As an example, if P3DIR = 0b01100101, then P3.0, P3.2, P3.5, and P3.6 are set to be outputs, while P3.1, P3.3, P3.4, and P3.7 are set to be inputs.

Setting the value on an output is done through the P#OUT register. This register is again a 1 byte value, each bit corresponding to each pin on a port. In the previous post, the LED connected to P1.0 was turned on and off by writing a value to the 0th bit of P1OUT. P1OUT = 0x01 (which corresponds to 0b00000001) turns on the LED by applying Vcc to the pin. P1OUT = 0x00 turns off the LED by grounding the pin. If we had set P1OUT = 0x03 (0b00000011), the LED would have turned on since bit 0 is set to be high. What about P1.1, since the second bit is high? In this case, since P1DIR was configured to have P1.1 an input, no voltage is applied to the pin, but the number is rather stored in a buffer. If we reconfigure P1.1 to be an output after setting P1OUT as above, then it starts with Vcc applied to the pin when switched. It is a good idea to always set P#OUT to the desired initial values before setting P#DIR to be certain the buffer values match what we want the pin behavior to be when the device is turned on. (It wouldn't be so good to turn on the controller and immediately start moving a motor before setting the output to keep the motor from turning.)

Reading inputs is done with the P#IN register. The values in this register correspond to the current voltage level on each pin in the port. Thus, for pins configured as outputs, the bits in P#IN and P#OUT are the same. When an MSP430 of any kind restarts, it defaults to setting the port pins as inputs. (There are exceptions for some pins, such as those intended to connect to a crystal oscillator. See your chips datasheet for details.)








The following program makes use of I/O ideas to turn the LED on P1.0 on and off by using a push-button switch on P3.3. The push button used is connected with a resistor to ground so that when unpressed the output doesn't float, but is tied to ground. When pressed, the output is connected to Vcc. This connection also causes a small current to flow through this "pull-down" resistor. A push button can also reverse this behavior by having the output tied with a "pull-up" resistor to Vcc and grounding the output when pressed. The output of the button can be connected to an input on the MSP430 in either case. For the pull-down setup, the input reads 0 when unpressed and 1 when pressed. I've done this with an external circuit, connecting my push buttons to Vcc and ground with external resistors enclosed in a small box. In the video below, the red button is tied to a pull-up resistor, and the black button to a pull-down resistor. (The black is used in the program below.) The MSP430 actually is built with resistors inside the chip, and each input pin can be set with pull-up or pull-down resistors individually without external pieces. We'll examine how to do that in another post soon.

A quick comment on some parts of the program: the header files include definitions for each individual bit. BIT0 is defined as 0b00000001, BIT1 as 0b00000010, and so on. I've used two definitions to make the program even more clear. I use LED to refer to bit 0 and BTN to refer to bit 3, since those are the bits used in the circuit design for the led and the button. The program also makes a function call. The purpose of the short delay function is to deal with switch bounce. Most mechanical switches will flip on and off a few times when pressed or released. To make certain the led doesn't rapidly turn on and off with the bouncing, a delay is used. The program constantly checks the current state of the button. Each check delays for a brief moment so that any bouncing occurs while the program is in the delay loop.

The method used for switching the output values is also very useful. Any bit and 0 returns 0, while any bit and 1 returns the original bit. ~LED gives the value 0b11111110, in this case, so bits 1-7 remain unchanged while bit 0 is set to 0 when you set P1OUT to P1OUT & ~LED. Any bit or 0 returns the original bit, while any bit or 1 returns 1. Setting P1OUT to P1OUT | LED has the opposite effect of setting bit 0 to 1.


/* buttonF2132: I/O configuration test that lights an LED when a push button is
* pressed. The LED is connected to P1.0, active high. BTN is connected to
* P3.3, active high (ie. when pushed gives a positive voltage, normally gnd.)
*
* Also demonstrates bit manipulation and function calling. The delay function
* accommodates switch bouncing.
*/


#include <msp430f2132.h>


#define LED BIT0 // P1.0
#define BTN BIT3 // P3.3


void delay(void);


void main(void) {

WDTCTL = WDTPW + WDTHOLD;
P1OUT &= ~LED; // initialize output by ensuring bit 0 is 0.
P1DIR = LED; // set bit 0 to output
P3DIR = 0x00; // unnecessary, but explicitly states P3 is all inputs.

for (;;) {

if ((P3IN & BTN) == 8) {
P1OUT |= LED; // set bit 0 to 1, turn on LED
delay(); // delay to prevent switch bounce
}
else {
P1OUT &= ~LED; // set bit 0 to 0, turn off LED
delay();
}
} // infinite loop
} // main


void delay(void) {
int i;
for (i=0; i<0xFF; i++) {
}
} // delay





Reader Exercise: Write a program that controls two LEDs as in the previous exercise. Use two other pins in port 1 as inputs for two buttons, one with a pull-up resistor and one with a pull-down resistor. Have each button control one of the two LEDs. Set one LED to be off unless its button is pressed, and set the other LED to be on unless its button is pressed.

8 comments:

  1. When a bit in P#DIR is set to 0, the pin is configured as an input. When it is set to 1, the pin works as an output. As an example, if P3DIR = 0b01100101, then P3.0, P3.2, P3.5, and P3.6 are set to be outputs, while P3.1, P3.3, P3.4, and P3.7 are set to be inputs.


    I thought you were going to tell me how to set one pin. Please explain this in steps: How to set one pin and then two. I get confused when looking at that number and trying to relate it to the next set of words:
    P3.0, P3.2, P3.5, and P3.6 are set to be outputs, while P3.1, P3.3, P3.4, and P3.7.
    What is the ob for?
    Thanks.

    ReplyDelete
  2. You might consider moving to the Tutorial series... these earlier posts were an initial start before the LaunchPad was announced. I re-did much of what's here in a clearer, more organized way that may be helpful to you!

    This topic should be covered in Tutorial 03.

    ReplyDelete
  3. Sorry I was looking at the bin as a number and not each ind. placeholder. I just learned bin and was confused as how to see the different pins.

    I can see what you mean now by looking at each ind placeholder as reference to each ind pin.

    ReplyDelete
  4. For debouncing the switch, should'nt the delay function be followed by another check where the current value of P3.3 is compared with the value of P3.3 before delay() was called.? If this check is satisfied ie P3.3 maintains its value, the LED should be turned on.

    The current program it seems to me would turn on the LED on even the slightest of glitch on P3.3

    ReplyDelete
  5. AneX: Excellent point; this will be something I address later on, in one of the tutorials. Thanks for pointing it out here-- I may have the excuse that this particular blog post was early on in my experimenting, before I started working with the tutorial series, but I still have a lot to learn all the same.

    ReplyDelete
  6. You could change:

    if ((P3IN & BTN) == 8) {

    to:

    if ((P3IN & BTN) == BTN) {

    What do you think?

    Peter

    ReplyDelete
  7. I think that's an excellent idea!

    In fact, you'll find later on in the tutorials that's exactly the technique I've started to use. Thanks for pointing it out!

    ReplyDelete
  8. You could change:
    if ((P3IN & BTN) == BTN)

    to
    if (P3IN & BTN)

    ReplyDelete

Comments? Suggestions? Did I say or do something wrong? Please contribute to help document this work correctly!