Digital 3: Microcontrollers and Programming
wanted to do a quick recap of a few things from class today, in terms of what you should be reasonably clear on.
- The basic structure of a C file
- What is a SFR (special function register)
- How to manipulate a SFR (set and unset bits)
- How output from an AVR works
- How input into an an AVR works
In particular, we started on timers, but that will be explored more in the next class. As supplemental materials explaining various aspects of what we covered today, I will post a couple of pages regarding input and output, as well as summaries on a couple of peripherals. You should be familiar with these by the next class.
Here are some additional notes from today’s class (some still being written):
- sample code from today’s class (with additional notes and comments)
- A couple of additional notes about if/else and curly braces in code (below)
- notes on connecting switches and LEDs
- notes on outputting from microcontroller and masking (below)
- notes on how PWM works
- avr libc documentation
- Basic makefile instructions (below)
And finally the homework (now due Tuesday):
- Write a program that setups up PC1 as input, and PC2 and PC3 as output, and PC2 to high. Imagine that PC2 and PC3 have LEDs on them, set up to source. At this point, the LED on PC2 is on, and the LED on PC3 is off. In the main loop, continuously check PC1, which has a switch. Toggle PC2 and PC3 when PC1’s switch is pressed (so after first press, PC2 is low, PC3 is high; after second press, PC2 is high, PC3 is low). You will need a variable to keep track of which way the LEDs are toggled.
- Write a program (a different C file) that initialized PC2 to output. Imagine there is an LED on PC2. Now in your main loop, write some code to maintain PC2 at a 30% PWM. To do this, you will need a little extra knowledge:
- #include <util/delay.h> at the top
- This will allow you to use the function _delay_loop_1(unsigned char v). As the name suggests, this function causes a delay. The value can be between 0 and 255. You can call the function like this:
_delay_loop_1(50);
The value 50 is an amount that the MCU will wait before doing the next thing. You can think of the 50 as specified in arbitrary units (so _delay_loop_1(50) delays 50 units of time). - Use _delay_loop_1 to produce the appropriate delay for the on and off period… ie, go high, delay, go low, delay, repeat…
Lab hours will be both tomorrow (Friday) 5-6pm, and Monday 5-6pm to take questions. We will program the MCU during lab hours to see your work in action!
Curly Brace
Curly braces { } go around all “blocks”. As an example:
for (;;} {
while (f1()) {
if (i > 3) {
// do something if i > 3
} else {
// do something else if i is NOT > 3
}
}
}
I generally put curly braces around all if/else/for/while blocks to prevent accidental confusion.
Also note the “else” part. This is to execute some lines of code if the condition is false. You may want to use it for your programs.
Input and Output for Microcontroller Redux
The physical pins on the MCU are divided into sets called ports and are named like PB3, where “B” is the port (port B) and 3 is the particular pin within that port counting from zero (so it’s the 4th pin of port B). We will use PB3 as the example, but you can generalize the idea to PC5 (6th pin of port C). So when I say DDRB below, that’s basically DDR+letter, so for port C, it would be DDRC.
The input and output (I/O) of the microcontroller (MCU) is controller by Special Function Registers (SFRs). To control these functions you need to access 3 SFRs: PORTB, PINB, and DDRB.
First, you need to tell the MCU whether you want to use a physical pin as output or input. This is the function of the DDR (data direction register). If you set a bit in this register, the corrosponding physical pin becomes output. So to turn PB3 into an output, we need to set the 4th bit, so that the contents of DDRB is “0000 1000″.
If the pin is configured as output, then you need to tell the microcontroller whether that pin is high or low. You do this with the PORTB SFR. If you set the 4th bit, the physical pin marked PB3 goes high, and if you set that bit to zero, it goes low.
When you have the port configured for input, you will likely want to read in that input. To do that, you need to examine the register PINB. If the 4th bit is 1, then the physical pin marked PB3 is reading high (ie, connected to +5 or similar), and if it is 0, then PB3 is connected to ground.
Masking
As you noticed, the SFRs group 8 pins into one, and you have to be able to look into and manipulate individual bits, as well as the whole thing. For things like the DDR, you generally don’t change settings too often, so you can just set the entire value at once (ie, DDRB = 0×08, which is 00001000b), so that’s a bit easier.
The idea behind masking goes back to AND and OR gates. Remember that the AND function returns true only when both of its inputs are true. The OR gate, on the other hand, returns true if either input is true. Here are the truth tables for AND and OR.
Using this, we can turn on a bit within a byte by OR-ing with 1. So for example, if PORTB contained 10110010b, and we wanted to turn on PB3 (the 4th bit from the left), we just need to OR it bitwise with 00001000b, which would produce 10111010b. Note that the other bits have not been hurt, because OR-ing 0 and 1 with 0 produces no changes. Now, writing 00001000b or 0×04 is sort of a pain, so we have a built in helper function: _BV(…). Basically, _BV(PB3) = 00001000b (and you can actually say PB3, or CS01 or whatever the NAME of the bit in the datasheet is. A last note: you can combine this, so if you want to turn on PB3 and PB4, you could do
PORTB |= _BV(PB3);
PORTB |=_BV(PB4);
or you could just write one line:
PORTB |= _BV(PB4) | _BV(PB5);
To turn PB3 off, you have to make that one bit zero. We can do this with AND, because we know that 0 or 1 AND-ed with 1 is the same, but anything AND-ed with zero is zero. So if PORTB was 10111010b, and we want to turn of PB3, we need to and everything except the 4th bit with 1, namely: 11110111b. This, by the way, is just the bitwise inversion of 00001000b, so we can use the ~ operator and write:
PORTB &= ~_BV(PB3);
or to turn off both PB3 and PB4:
PORTB &= ~(_BV(PB3) | _BV(PB4));
Note the parens in the latter. That’s because first we want to make a mask for the bits we care about: 00011000b, and then flip it to 11100111b. The parens tell C to do that.
Now to read it, you can check the value of PINB. But remember, PINB gives the state of all the physical pins that are PB<0-7>. If you want to know the state of PB3, you need to get the rest out of the way. We do this using AND again, but in reverse. Now we want to remove everything but PB3. If PINB is 11101111b, and we want to check PB3, we can AND it with a mask, 00001000b, so that what we get is 00001000b. We can test the bit like this:
if (PINB & _BV(PB3)) { … }
Note that we’re usint it in the opposite way of turn-off, so there is no ~.
About Makefiles
It’s generally smart to make folders and keep a makefile and associated C files in that folder per-program, instead of piling them all up in one folder. The makefile is actually not quite code… it contains instructions to allow you to compile and program. Notice that the file’s name is just “makefile”… no extensions!
You have already used the make command without parameters (just “make”), which is the same as “make all”. This basically compiles your code.
You have probably noticed that “making” or compiling produces a lot of extra files. To clean these up automatically, just execute “make clean”.
Within the makefile, there are a few lines of concern:
- TARGET = sample <– this is the .c file (sample.c) that contains your main function
- MCU = atmega88 <– tells what MCU you are using (the mega 88 in your case)
- F_CPU = 1000000 <– speed of your MCU (default 1MHz, we’ll discuss this later…)
- SRC = $(TARGET).c somethingelse.c <– list other C files that need to be compiled here (we’ll discuss this later too…)
After that, almost everything else is automatic or advaced topics.
You’re currently reading “Digital 3: Microcontrollers and Programming”, an entry on Techniques for Design and Fabrication
- Published:
- 10.09.08 / 9am
- Category:
- Announcements
- Tags:
- Post Navigation:
- « Digital 2: Datasheets, Microcontrollers, Video
Digital Session 3 Video »