3 Simple Ways to
Share What You Make

With Instructables you can share what you make with the world — and tap into an ever-growing community of creative experts.

PhotosPhotos

Share one or more photos of a project, recipe, or whatever you've made, quickly and easily.

Step by StepStep-By-Step

Share your step-by-step photos with text instructions of what you made so others can do it too!

VideoVideo

Share your how-to video. You'll need your embed code from a video site such as YouTube.

Ghetto Programming: Getting started with AVR microprocessors on the cheap.

Step 10Explaining the software

The code's pretty simple, as far as AVR code goes, but still displays a few tricks of the trade. If you're still basking in the glory of your blinking light, you can come back later.

The #include lines load up some of the extra functions and definitions in the AVR-libC suite. In particular, the delay function _delay_ms() is in delay.h. Interrupt.h has all the pin definitions which make life easier. You're always going to want to include it.

The program always starts from the function main(). In this simple case, it's the only function we have.

The first command in main(), DDRD = _BV(PD4);, seems pretty cryptic, but here's what it's doing. DDRD is the Data Direction Register for port D. All the input/output pins are broken up into different ports for easier access. The one we're using happens to be in D. We need to enable the pin PD4 for output for the LED.

The DDRs are set up so that they have 8 bits, one for each pin in the port. You set a pin up for input by writing 0 to its bit in the register. You can set it to output by writing a 1. We want the contents of DDRD to be 00001000, or output only on pin 4 (read right to left). So how do we do this?

_BV(i) takes a number, i, and converts it to an 8-bit binary number where the i'th bit is a 1 and the rest are zeros. Just exactly what we need. And PD4 is the number corresponding to pin 4 on this port. So we set DDRD to _BV(PD4), and then pin 4 (and only pin 4) is set up for output -- blinking our LED.

The rest of the program repeats forever in a loop. It alternates between turning pin D4 on and off, with a delay in-between.

You can turn the individual pins on (and off) by writing a 1 (0) to the PORT register. The syntax is just like above with the DDR -- PORTD = _BV(PD4) sets the fourth pin in port D to 1.

The _delay_ms() function then waits for a bit. It may not be quite 1ms, though. Depending on what clock speed your chip is set at, it may be a lot faster. The timing's not critical here, so let's overlook that for now.

Finally, PORTD &= ~_BV(PD4); turns pin PD4 off without affecting the rest of the values in PORTD. Let's look in detail at how it does it.

_BV(PD4) creates a binary number with the 4th bit (from the right) as a 1 -- 00001000. "~" is the logical complement operator. It turns the 00001000 into 11110111. "&" is the bitwise "and" operator. It compares two bits, and returns a 1 if and only if both bits are 1. If either is 0, it returns a 0.

The "&=" in PORTD &= ~_BV(PD4) is a very common shortcut. It stands for PORTD = PORTD & ~_BV(PD4). This last command compares the current value of PORTD (00001000) and the value (11110111) described above. The zero in the 4th place in ~_BV(PD4), when used with the & operator, always makes the 4th bit of the result = 0, effectively turning off bit PD4.

The 1s in the rest of ~_BV(PD4) make it so that the & operator doesn't clobber the rest of the contents of PORTD. Since the & returns 1 only if both inputs are 1, the remaining bits in PORTD are re-assigned whatever value they already have -- leaving them unchanged.

Could we have set PORTD = 0? Sure. Since we're only using the one pin in D, it would turn it off just fine. But it would have the side-effect of turning off _all_ the pins on port D, and it wouldn't have provided such a nice example. The bit-masking techniques ( &= ~_BV() and its opposite, |= _BV() ) are pretty useful to learn for chip-level programming.

The last part of the code, return(0), never gets reached. The while(1) command ensures that the chip is always going to be stuck in the while loop. I just included the return() command because the compiler complained when I didn't include it -- the main C function in a program is always supposed to have a return value, even if the chip will never get there.

That's a lot of programming for one day. Take some time to admire the simple beauties of the flashing LED.

« Previous StepDownload PDFView All StepsNext Step »
4 comments
Jan 15, 2008. 7:23 PMjosheeg says:
great tut for window$ but notice PB4 in your code and PD4 in your tut. I noticed it when I was trying to make a arduino blinky. Actually boarduino blinky.
Aug 7, 2007. 7:27 PMseraphus says:
I'm using a ATMega8, so I had to do things a little differently, but I followed the pin overviews and got the programmer "working" in that it will talk to the microcontroller and send over the program. Only problem is that my lights don't blink!

I've tried sending out through PD4 and PC5, neither will light an LED or tell Mr.Fluke that there is any voltage coming out. is there anything you'd suggest to try now?
(I got the PC5 idea from http://www.tuxgraphics.org/electronics/200411/article352.pdf )
Aug 7, 2007. 7:38 PMseraphus says:
nevermind. I just discovered that the program doesn't start until you unplug it from the computer. Yay!

Pro

Get More Out of Instructables

Already have an Account?

close

All Steps Viewing
View all steps of an Instructable on the same page when you're a Pro Member.

Upgrade to Pro today!
95
Followers
7
Author:The Real Elliot