Brief Tutorial on Programming the AVR without Arduino
Enviado por ADMAESMO • 20 de Junio de 2013 • Tutorial • 3.621 Palabras (15 Páginas) • 484 Visitas
Brief Tutorial on Programming the AVR without Arduino
Motivation
Just to get started on the wrong foot: "sometimes Arduino is the wrong choice." Depending on what you're doing, maybe your app's structure isn't very well suited to the Arduino framework. Maybe you need to write smaller code than what would be produced by Arduino, sometimes you just can't run Arduino at all...
I'm in that latter category. I'm not such a big fan of Java, and I'm comfortable with a text editor and driving the compiler by hand, so I'm going to do this the hard way. Arduino trowels some nice plaster over top but it's nothing you can't do by hand. Really, all you should need is avr-gcc, avr-libc, avr-binutils and avrdude. Getting these packages is beyond the scope of this document, it's quite likely there are pre-built packages for your OS.
This document was written give a basic introduction to some of the specifics of AVR programming, assuming you already have a handle on C. It approximates the order I came to understand things while learning to program the AVR. I'm doing a lot of this "the hard way", there are a number of macros in avr-libc or avrlib to do much of this but it's important to understand the underlying principles. If you understand what's going on, moving your code (from a '168 to a '644P for example) is very easy.
A blinking LED - Busy Waits and IO ports
Two blinking LEDs - Addressing Pins
A switched LED - Digital Input and output
Serial Output
Serial Input
Putting it together: printing button presses and controlling LEDs
Analog Output
avr-libc goodies
Analog Input
A blinking LED - Interrupts and timers
Persistent Storage
Input Capture
Watchdog
I2C/SPI peripherals
ATmega644P-specific
ATtiny85-specific
AT90USB162-specific
Lesson 1: A blinking LED - Busy Waits and IO ports
This section is an introduction to microcontrollers. Out of the box, your microcontroller won't do anything - you need to load a program before it's useful. Here I present the the hardware equivalent of "Hello World" - a blinking light.
To begin, let's look at the pin map. We see that Arduino pin 13 is PB5 on the ATmega168 - part of port B. To use this pin, port B must first be set to be an output pin. There are various ways to do this[2] - writing to Port B Data Direction Register[3] at address 0x24 or the lazy/better way, using the DDRB macro. Let's keep things simple and set the whole port to output with DDRB = 0xff;. Finally, we can start writing to PORTB (address 0x25).
A simple approach would would be to do something like this:
while(1){
PORTB = 0xff;
_delay_ms(500);
PORTB = 0x00;
_delay_ms(500);
}
which makes use of the delay routines defined in <util/delay.h>. If you try run this, you'll find your LED blinking very rapidly. Far more rapidly than you'd like.
A brief inspection of delay.h is instructive: with respect to _delay_ms, "The maximal possible delay is 262.14 ms / F_CPU in MHz." This can easily be addressed by computing the maximum time _delay_ms will sleep, and given that, the number of times to call _delay_ms to achieve the desired delay interval. You may wish to put this computation into a separate function which you can call whenever you need to delay.
lesson1.c is one possible solution.
Lesson 2: Two blinking LEDs - Addressing Pins
This section builds on the previous section. By now you're probably bored of looking at the onboard LED blinking. That's good. Let's try hooking up some other LEDS. If you try this, you'll find they'll all blink together. Why?
Because you asked for it with PORTB = 0xff;. More astute readers may have figured out that writing all 1's to the port would set all the pins to 1. If you're new to this... well, I just said it. By the same token, writing 1 to only a single bit in the port's register will only turn that pin on.
Recall that the Arduino pin map said that pin 13 - the LED - is PB5. In other words, bit 5 of port B, or 0x20. Take a copy of your solution from lesson 1, and change it to write 0x20 to PORTB, rather than 0xff. After doing this, your program should blink just the onboard LED.
Now that you have control over a given port, extend your program to alternate or cycle the LEDs lesson2.c is one possible solution.
Lesson 3: A switched LED - Digital Input and output
We've now become comfortable with basic digital output, let's work on getting signals in.
Bear with me a moment while we look at some background on inputs. We like to think of processors as purely digital entities - ones and zeros, highs and lows. Alas, there are plenty of analog signals inside, and depending on your processor (like AVRs and PICs) you may even have specific analog inputs. A pin connected to ground is logic 0, and a pin connected to power is logic 1, but what value does an unconnected pin have? Indeterminate. The pin is said to be floating.
Typically, pins are connected to high or low through a relatively high-value resistor, called a pull-up or pull-down. This offers a weak signal to that pin, putting it into a known state. This known state is then selectively overriden by shorting the pin to low or high. Think of it as someone yelling "zero", and someone whispering "one". The very loud zero will overpower the quiet one, but in the absence of other input, you'll hear the one. As to what value of resistor to use, I've heard "it depends", "low enough to get the signal, high enough to not waste power", and "47K". My point in mentioning this is to let you know that something will need to be done to the input signal so the AVR knows it's there.
If you're lazy (or wise), you can tell the AVR to use internal pull-ups rather than having to mess with them on your own. Using Port D as an example, let's set up Digital Pin 2 (PD2) as an input with internal pull-up:
DDRD &= 0xFB; /* leave all the other bits alone, just zero bit 2 */
PORTD |= 0x04 /* leave all the other bits alone, just set bit 2 */
value = PORTD & 0x04; /* and that's what's on the pin... */
Try a program to read a switch connected between digital pin 2 and ground, and use this to control an LED. One possible solution is lesson3.c
...