You’ve probably heard people say that computers represent everything as 1s and 0s. What that actually means in practice is that everything processed or stored in a computer (text, images, audio, video, whatever) must be represented as numbers, and that each of those numbers is physically stored in “binary” form – as a sequence of 1s and 0s.
- When a piece of text is stored in computer memory, each letter is represented by a single number (if you’re interested, you can see which numbers represent which letters here), and the whole piece of text is basically stored as a list of numbers.
- Similarly, when a photograph is stored in computer memory, it’s actually stored as a very long list of numbers. In a colour image, each pixel in the image is typically represented by three numbers – one for how red it is, one for how blue it is, and one for how green it is.
Anyway, whatever is being stored in computer memory must somehow be represented as numbers, and within the computer those numbers are always represented in binary form, which means using only 1s and 0s.
To explain binary numbers, let’s begin by reviewing how decimal numbers work. The decimal number system is the normal one we’re familiar with, in which each digit is a multiple of a different power of 10. For example, consider the number 5713 (five thousand seven hundred and thirteen).
- The digit 3 represents a multiple of , i.e.
- The digit 1 represents a multiple of , i.e.
- The digit 7 represents a multiple of , i.e.
- The digit 5 represents a multiple of , i.e.
So the total value is 3×1 + 1×10 + 7×100 + 5×1000 = 3 + 10 + 700 + 5000 = 5713
- The decimal number system is “base 10” which means that each digit in a decimal number represents a multiple of a different power of 10 (1, 10, 100, 1000, etc).
- You will also notice that in decimal numbers (base 10), there are exactly ten possible values for each digit: 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9.
The binary number system works exactly the same, except that it’s “base 2” which means that each digit represents a multiple of a different power of 2 (1, 2, 4, 8, 16, etc) and there are only two possible values for each digit – 0 or 1. This takes a bit of getting used to, but it’s important to remember that it works exactly the same as decimal numbers.
Here’s an example of a 4-bit binary number (which just means a binary number with 4 digits):
Consider the binary number 1100. From right to left, the four digits are:
- bit 0: 0, multiple of . i.e.
- bit 1: 0, multiple of . i.e.
- bit 2: 1, multiple of . i.e.
- bit 3: 1, multiple of . i.e.
So the total value is 0x1 + 0x2 + 1×4 + 1×8 = 0 + 0 + 4 + 8 = 12 (decimal).
In other words the binary number 1100 is just a different way of writing the decimal number 12 (twelve). Whether we write it in decimal or binary form, it’s the exact same number! We just have more than one way of writing down a number.
Many C compilers (including the one we’re using for the MSP430) allow us to write numbers in binary form by preceding the number with “0b”. This lets the compiler know you mean “0b1100” (binary 1100) rather than simply “1100” (one thousand one hundred). In the example programs provided here, most binary numbers are written this way.
Digital i/o ports on the MSP430
One of main reasons binary number are relevant here is that we’re using the individual bits (digits) of binary numbers to switch different pins on and off on the microcontroller. I mentioned that computers store everything as numbers (and specifically binary numbers). Each binary number is stored in what we call a “register”, which is basically just a small number storage area inside the chip which can hold one number at a time. Inside the MSP430, some registers can store 16-bit binary numbers and some can store 8-bit binary numbers.
Most registers are just used to remember numbers, and that’s all. However, some registers have special jobs. For example, P2DIR, P2IN and P2OUT are all special function registers (SFRs) which we use to control the 8 pins that make up what we call “Port 2”. Each of these three registers stores an 8-bit binary number. The MSP430G2553 has two 8-bit “ports”:
- Port 1 consists of the following 8 pins: P1.0, P1.1, P1.2, P1.3, P1.4, P1.5, P1.6, P1.7
- Port 2 consists of the following 8 pins: P2.0, P2.1, P2.2, P2.3, P2.4, P2.5, P2.6, P2.7
The diagram below shows which pins are which on the chip (if you look closely at the LaunchPad, you’ll see that the same pin labels are shown beside the chip socket):
To make it clearer, the 8 pins that make up port 1 are coloured yellow, and the 8 pins that make up port 2 are coloured blue. Digital input and output basically work the same for Ports 1 and 2. To illustrate this I’ll describe how P2DIR, P2IN and P2OUT control port 2 (the blue pins), but the same description basically applies to registers P1DIR, P1IN and P1OUT which control port 1 (the yellow pins).
Let’s imagine that we store the 8-bit binary number 0b00000111 into the P2DIR register, using the following statement:
P2DIR = 0b00000111;
Each bit in this 8-bit value controls the “direction” of one pin in Port 2 – i.e. whether it’s an input or an output. A 1 makes a pin an output. A 0 makes a pin an input. That value (P2DIR = 0b00000111) sets the 8 pins as follows (bits are counted from right to left starting at 0):
- bit 0 = 1, This makes P2.0 (pin 8) an output
- bit 1 = 1, This makes P2.1 (pin 9) an output
- bit 2 = 1, This makes P2.2 (pin 10) an output
- bit 3 = 0, This makes P2.3 (pin 11) an input
- bit 4 = 0, This makes P2.4 (pin 12) an input
- bit 5 = 0, This makes P2.5 (pin 13) an input
- bit 6 = 0, This makes P2.6 (pin 19) an input
- bit 7 = 0, This makes P2.7 (pin 18) an input
Now, the number we store in P2OUT controls the voltage of any pins in Port 2 that are configured as outputs (remember, we’ve just made 3 pins outputs). Let’s say the following statement appears later in the same program:
P2OUT = 0b00000101;
Only the last three digits (“101”) of this number are going to have any effect, since these are the only pins which are configured as outputs.
- bit 0 = 1, This sets pin P2.0 high (i.e. P2.0 voltage is 3V)
- bit 1 = 0, This sets pin P2.1 low (i.e. P2.1 voltage is 0V)
- bit 2 = 1, This sets pin P2.2 high (i.e. P2.2 voltage is 3V)
- bit 3 = 0, P2.3 is an input, so this bit is ignored
- bit 4 = 0, P2.4 is an input, so this bit is ignored
- bit 5 = 0, P2.5 is an input, so this bit is ignored
- bit 6 = 0, P2.6 is an input, so this bit is ignored
- bit 7 = 0, P2.7 is an input, so this bit is ignored
I’ll describe P2IN in a subsequent post, but for the time being, suffice it to say that we use this to read the voltage on any Port 2 pins which are configured as inputs.
Finally, I’ll just mention that it’s a matter of convenience that we’re writing the values in binary form in the program. For example, because binary 101 equals decimal 5, instead of writing
P2OUT = 0b00000101;
we could write
P2OUT = 5;
and the program would work exactly the same. The main advantage of writing the numbers in binary form in the program is that we can see which bits (and therefore which pins) we’re setting high and low.