LESSON 3 CONTINUED - display continued
CORRECTION TO MAIN.C:
#include "display.h"
void display_setup(void)
{
// set up the 8 output pins we're using and clear them
DDRB |= PB_MASK; // set pins 0,1,2,3,4 of PORTB as output
DDRD |= PD_MASK; // set pins 5,6,7 of PORTD as output
PORTB &= ~(PB_MASK); // set PORTB pins 0,1,2,3,4 low (xxx0 0000), x = unchanged
PORTD &= ~(PD_MASK); // set PORTD pins 5,6,7 low (000x xxxx), x = unchanged
}
void display(uint8_t num)
{
// write the value of num to the display as a series of 8 bits
PORTB &= ~(PB_MASK); // clear our 5 bits in PORTB
PORTD &= ~(PD_MASK); // clear our 3 bits in PORTD
PORTB |= (num & PB_MASK); // (xxxx xxxx) & (0001 1111) = (000x xxxx)
PORTD |= (num & PD_MASK); // (xxxx xxxx) & (1110 0000) = (xxx0 0000)
}
I didn't follow my own advice about not touching the other bits. Anyway, we're still working with display_setup. Look at the next couple of lines:
PORTB &= ~(PB_MASK); // set PORTB pins 0,1,2,3,4 low (xxx0 0000), x = unchanged
PORTD &= ~(PD_MASK); // set PORTD pins 5,6,7 low (000x xxxx), x = unchanged
Lets look at this piece by piece. First, we have two more register names. These are the Port Data Registers for ports B and D. Writing to them lets us set the pins in those ports. If our pins were inputs, reading these registers would give up the values of those pins. We are using (at least some of) those pins as outputs right now, so we are writing to them (with the equals sign). Next we have this thing: "&=". This is an "and equals" operator. In other words, if something is currently 1, and we &= 1 it, it will remain a one. If it's currently a 0 it would remain a 0. This symbol, "~", is an inverse sign. we put that in front of our bitmasks to invert them. Thus, 0x1F (0001 1111) becomes 1110 0000. When we apply that with the "&=" operator to the value currently in PORTB, the first 5 bits (from right to left) will become 0s, the remaining 3 remain unchanged. This is to set all of our LEDs to off to start. It may not be necessary here, but it's always good practice to initial values of stuff you use so it's not in an unknown state at startup (which can be especially dangerous in robotics).
OK. So that sets up our ports and pins. It can be confusing but I hope everyone is still following along. Next we're going to look at the actual display function, "display". This time, our function requires a parameter to be passed to it when we use it. In other words, it needs to be given a number to display. You can see that in the first line:
void display(uint8_t num)
The "void" at the beginning is what the function returns, which in this case, is nothing (don't worry about this for now). The interesting bit is after the function name, in parentheses: "uint8_t num". What this says is that we need to give our function an 8-bit unsigned char every time we call it, and that we can access that value from inside the function with the variable name "num". Lets look at the function body itself. First, we clear the two data registers (only the bits we're using). This clears old data from them (last "frame", if you will). Then, we do a bitwise & with the number we're trying to show with the bitmask. So for the number 255, for example, which is 1111 1111 in binary, &'ing with our PORTB bitmask, 0001 1111, will give us a result of 0001 1111, which is then |='ed with the value currently in the PORTB data register, where only the 1s will affect it. Get it? Thus, writing our value to those pins. Same for PORTD.
Next - Makefile