AVR GCC Tutorial (1) – Basic I/O Operations
Atmel has come up with a whole range of superb AVR microcontrollers which are the dream of every hobbyist. However, the real icing on the cake is that these µControllers can be programmed with just a parallel port connector and nothing else!!!. However, Atmel µC’s have their downsides too. They have to be programmed in either Assembly or in C. There is one program – Bascom AVR – which reportedly allows programming in BASIC. But, unfortunately it doesn’t seem to work (?) with the el-cheapo parallel port programmers
. So, the only option left is C, unless you are willing to dabble with Assembly.
I’ll attempt to give a brief introduction to basic I/O operations in C for AVR microcontrollers.
First of all, you need a programmer to program. As i told you, its all very simple, you just need a parallel port cable. Follow this excellent tutorial by The Real Elliot at Instructables.com
So, first make a simple programmer, test out the blinking LED program and then come back.
PS: Your programmer doesn’t have to include all the header pins, a board etc, that Real Elliot has shown in his tutorial. A basic parallel port connector with a few wires and resistors soldered directly on it is what i have been using from the past couple of months. It works just as well.
Before starting, there are a few things i would wish to tell. First of all, at first sight , (especially to those unacquainted to C), all this “_BV(PD4)” stuff may seem a little too cryptic. At one point, you probably will be tempted to ditch GCC and learn Assembly. However, i assure you that Assembly is much more frightening than AVR C. AVR C is not at all hard to learn, it just looks a bit alarming because of those weird symbols like << >> ~ which keep floating around. Once, you understand what all that is about, it’ll all be a piece of cake.
What you should know before reading this tutorial:
1) I expect that you are somewhat well acquainted with atleast any 1 high level programming language. (BASIC, Java, C/C++ etc)
2) I expect that you are reasonably comfortable with the C syntax. You do not need to know all the stuff that comes in the 10th and 11th chapters of C++ books. Just the basics – Program syntax, header files, functions, if then else, loops - should be enough.
3) I expect you to be comfortable with binary numbers, logic gates and Boolean algebra.
If the answer to any of the above is no , then brush up and then come back.
I also recommend that everyone goes through this excellent pdf to brush up you C skills in case they are a bit rusty.
The Port Control Registers
For easier access , the I/O pins on an AVR uC are grouped into a number of ports. Each port contains a number of pins ranging from 3 to a maximum of 8. To control these Ports , 3 registers have been provided. Each register controls a specific feature of the Port. Let us examine each Register one by one.
And , one more thing. Unfortunately , both the register PORTx and the Portx physical pins are referred to by the same name. To avoid confusion , i will be referring to the register as PORTx and the physical pins as Portx.
Defining a pin as either Input or Output – The DDRx Registers
If you take a look at the tiny2313 datasheet, it says something on the 1st page – “18 I/O lines”. This means that out of the 20 pins of tiny2313, 18 can be used as either input or output pins.
But then, immediately the doubt arises ”How do I tell the micro controller whether I want to use a pin as input or as output?”
For this purpose, there exists a register known as the DDRx register for every port. The “x” stands for the port alphabet. Every bit in the register controls a single pin of the port.
In case of the DDRx register, each bit controls the I/O of the respective port pin. I.e., the 5th bit controls the 5th pin of the PORT et cetera.
To make a pin work as Input, just write a LOW to its respective bit in the appropriate DDRx register.
To make a pin work as Output, just write a HIGH to its respective bit in the appropriate DDRx register.
Now suppose, i wanted to configure the 3rd and 7th pin of portb as output and the rest as input :
DDRB = 0b10001000;
Notice that the 7th and the 3rd bits are made high. And the rest are all LOWs. The above command, when executed, will configure PORTB as we selected.
Similarly, you do the same thing for other ports as well.
Suppose you wanted to make all the pins of portd as output:
PORTD = 0b11111111;
But, if you are a keen observer , you might have noticed one thing. PORTD has only 7 pins. However, we have written an 8 bit value to the DDRD register. So, what happens to the last bit? The answer is: nothing. Nothing happens. The eight bit is simply ignored by the microcontroller.
Making a pin go HIGH or LOW – The PORTx register
There is one more register that controls the HIGH/LOW status of a pin. That register is called the PORTx register. Every bit in the register controls the state of the respective bit in that port. i.e. the 5th bit controls the 5th pin of the port etc.
It has 2 functions:
Case 1 : To make a pin go high or low ( if it is an output pin).
DDRB = 0b10001111; /* Configuring I/O pins of portb */
PORTB = 0b10001010 /* Write this byte to PORTB */
Now, the 7th bit, 3rd bit and the 1st bit will be set. The 0th and 2nd bit will be reset. The other bits will be in a High-Z state as they are configured as input pins.
Case 2 : To activate / Deactivate pull up resistors.
The input pins of tiny2313 are generally in the Hi-Z state. This makes them prone to catching noise and picking up false signals. Hence, it is advisable to put a pull-up resistor to reduce noise. The resistor will normally hold the input pin at logic HIGH. Any external source can pull the voltage down to LOW when required.
Fortunately, Atmel has already included internal pull-up resistors. You can enable them by writing a HIGH to the appropriate bit of the PORTx register.
DDRB = 0b00000000; /* Configuring I/O pins of portb */
PORTB = 0b01110101; /*enable internal pull-up resistors on output pins 1 , 3 , 5 , 6 , 7 */
Reading the status of an Input Pin - The PINx register
To put it bluntly, the PINx register contains the status of all the pins in that port. If the pin is an input pin, then its corresponding bit will mimic the logic level given to it. If it is an output pin, its bit will contain the data that has been previously output on that pin.
DDRD = 0b00000000; /* Set all pins as input */
uint8_t status; /* Define a 8 bit integer variable */
status = PIND; /* Store the current value of PIND in status */
The above code will cause whatever input has been given to the 8 pins to be written to the variable status.
PS : Dont worry yourself if you cant understand the uint_8 stuff. All you need to understand is that we have just created a 8 bit variable with the name “status”. “uint8_t” in AVR C is kinda like the equivalent of “int” in ANSI C.
The Practical Stuff
Now that you know about the 3 registers , you are all set to actually start programming some real stuff. Why dont we program a running light sequence?
In our running light sequence , there will be 8 LEDs which will light up in sequence. It will be something very similar to a ring counter made using a CD4017.
Since ,we are using 8 LEDs , we must use a port that has 8 pins. That port in the Attiny2313 is the Portb.
So , first we must configure all the pins of Portb as output. For that we need to set all the bits in the DDRB register high.
DDRB = 0b11111111;
Now that we have configured the LEDs as output , we are now ready to start lighting the LEDs one by one. We will set each bit in PORTB register high one after the other , with a small delay in between
DDRB = ob11111111
PORTB = 0b10000000;
_delay_ms(50);
PORTB = 0b01000000;
_delay_ms(50);
PORTB = 0b00100000;
_delay_ms(50);
PORTB = 0b00010000;
_delay_ms(50);
PORTB = 0b00001000;
_delay_ms(50);
PORTB = 0b00000100;
_delay_ms(50);
PORTB = 0b00000010;
_delay_ms(50);
PORTB = 0b00000001;_
delay_ms (50);
With the above code , the LEDs will just run once and then stop. We need to it keep on running in a cycle like in a CD4017. To do that , let us add a infinite loop. We also have to declare the main function and include the all essential header files.
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>int main(){ // The main function
DDRB = 0b11111111; // Set all the pins of PortB as output
while (1) { // Set up an infinite loop
PORTB = 0b10000000; // Turn on LED1
_delay_ms(50); // Wait
PORTB = 0b01000000; // Turn on LED2
_delay_ms(50); // Wait
PORTB = 0b00100000; // The same sequence repeats…
_delay_ms(50);
PORTB = 0b00010000;
_delay_ms(50);
PORTB = 0b00001000;
_delay_ms(50);
PORTB = 0b00000100;
_delay_ms(50);
PORTB = 0b00000010;
_delay_ms(50);
PORTB = 0b00000001;
_delay_ms(50);
}}
The statment while (1) is forever true , so the LEDs keep cycling forever.
There’s just one teeny weeny thing left : the Makefile. You can use the same one that Real Elliot provides in his Ghetto programming tutorial here. For your convenience i have uploaded both here :
Ready to use Makefile – The full credit goes to Real Elliot.
Dont forget to remove the .txt extension from the makefile after you download it.
If you compile it and load it into your Attiny2313 , you will see the LEDs on PortB running in a chain like this :
Note : This code is a terrible example of how to make an LED chain. The same thing can be accomplished more efficiently by a loop in less than 5 lines of code.
Selective bit modification in Registers
However there is a huge disadvantage in the modifying registers in this way! Suppose you want to set the 7th bit of PORTB and reset the 3rd bit without affecting the rest, how would you do it?
It seems like its impossible, because bits in the AVR registers cannot be accessed individually. Despite this fact, with a little bit of Boolean algebra , it is possible to modify just the bits we need without touching the rest. I’m still writing the post on this. So, I’ll post the tut on selective bit modification later.
Thats all for now,








[...] AVR GCC Tutorial [...]
Clear & practical
thx. that really helped me!
Thank you man. Good tutorial
Great tut! Escpeccialy that scheme of the registers is good!
Excellent illustrations! The links to external sites don’t work though. You are prepending your blog URL to every link which works only when they are local pages.
jonsoons
ah…thanks for pointing that out.
I’ve fixed it now.
thanks, that is a great tutorial for first c learners.
Excellent tutorial!!! I’d be really interested in hearing more about “selective bit modification.”
Cant wait for selective bit manipulation!
Hi,
Thank you for this wonderful tutorial. I am really new to hardware programming and
. I can use the concept to connect
your tutorial helped to improve my confidence
a display device. If there are any examples you have for display devices please do
let me know.
Thanks.
u r awe some teacher……do u teach atmega32 avr-gcc tutorial????i am working on that sir
[...] AVR GCC Tutorial (1) – Basic I/O Operations « Suhas’s Blog At one point, you probably will be tempted to ditch GCC and learn Assembly. However, i assure you that Assembly is much more frightening than AVR C. AVR C … iamsuhasm.wordpress.com/…/avr-gcc-tutorial/ – [...]
tks for the effort you put in here I appreciate it!
I have just started reading your tutorial and I know that it is what I’ve been looking for the last days.
Thank you very much of making me able to start with AVR µCs
Nice tutorial…
I really help me on study about the AVR
Thank you. Really nice tutorial.
thanks:)!!! nice tutorial
You can use bascom to write your program and it will generate a .hex file (and .eep if you need data in the eeprom area), then just upload it with any other program. I write smaller programs in bascom (Up to 4k output and you can use the FREE demo version
and then program my chip with ponyprog using a simple parallell programmer.
nice tutorial. very simple and helps new people like me understand stuffs a lot easier.
I am only a week into learning AVR microcontroller programming, and I found this tut exceptionally comprehendable. Great job man, and Thank you!!!
Quick remark about the DDRx section:
[quote]Suppose you wanted to make all the pins of portd as output:
PORTD = 0b11111111;[/quote]
I’d write DDRD instead of PORTD…?!?
Yeah…Thats what you would do.
if you declare PORD as 11 all you do is starting the internap pull-up on that port… you need to declare the DDRD as a data direction register to output…
so the right statement would be
DDRD=0xFF;
PORTD=0b000001;
and for the while
int x=1;
while(1)
{
for(x=0;x<=7;x++)
PORTD=(1<<x);
}
this is so simple
Iamsuhasm,
you’ve explained some complex topics simply and effectively.
You are also appreciative of feedback, complementary or otherwise. Well done.
Thank you for sharing.
Thanks for the simple tutorial. Just bought an Atmel STK500 starter kit, couldn’t find appropriate information how to control the ports. The fact that register name and physical connection both are named PORT didn’t help. Glad you pointed that out.
stay away from such simple LPT programmer…and invest in a good USB programmer…
Nice tutorial to get started. I have actually worked with Bascom AVR and a cheap parallel port programmer. Never had any problems. But I must say, programming in Basic is not for me.
Thanks
Hi,
Great post on AVR GCC. I was having some troubles with finding ATtinys and ATmega168s. Can you suggest some places where I can find some of these online?
thankyou tor the clear explanation of the port registers and how to set the bits correctly, might I suggest an addendum of how to do the same but using hex ?
Regardless it is very well put together and has clarified it for me (to the point that I can ask about hex !!)
When you say:
“Now suppose, i wanted to configure the 3rd and 7th pin of portb as output and the rest as input :
DDRB = 0b10001000;”
is this right, or do you mean: “DDRB = 0b00100010″ – for pins 3 and 7 ?
No, he started to count at 0 and from the right (as you would count in binary)
HOW TO change single bits of At8bit registers:
-> DDRB is 0b00000000
-> PORTB is 0b00000000
Setting PB2, PB3, PB4 as OUT HIGH:
DDRB |= ((1<<2) | (1<<3) | (1<<4));
PORTB |= ((1<<2) | (1<<3) | (1< DDRB is 0b00011100 now
-> PORTB is 0b00011100 now
PB2 is set to IN:
DDRB |= (1 < DDRB is 0b00011000 now
PB4 is set to OUT-LOW:
PORTB &= ~(1<<4)
PORTB is 0b00001100 now
For people that don’t like the |= ((1<<2)|(1<<3)) syntax (although it clearly identifies the pins) you can also do:
DDRB |= 0b00001100; //that sets the individual pins at 1 and leaves the other pins (the 0's) as they were before
Thanks,
This is good for new ones
Sameer Khanna
Could you give us an example of context switch in AVR ?
Great Tute, Best explanation of this stuff that i have found.
Well done
This tutorial is just great, it helped me a lot in my beginnings. Thank you.
Helped me greatly in my first LED to blink-Attiny461. Continue please
Thanks for sharing
Thanks very much! I’ve been struggling with the online documentation of avr-gcc and it’s got quite a learning curve… The description of port registers and what they do cleared things up! Thanks again
Great tutorial. Make it easy to understand the registers with the graphics.
QUOTE:
Fortunately, Atmel has already included internal pull-up resistors. You can enable them by writing a HIGH to the appropriate bit of the PORTx register.
DDRB = 0b00000000; /* Configuring I/O pins of portb */
PORTB = 0b01110101; /*enable internal pull-up resistors on output pins 1 , 3 , 5 , 6 , 7 */
QUOTE
I think it should read PORTB = 0b11101010 ?
[...] a single instruction that takes a single clock cycle to execute. You can learn something about that here. Now, let’s consider the Arduino [...]
Nice tutorial
Thank you.
Sorry my eng is bad.
I compiled code below :
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */
#include
#include
#include
int main(){ // The main function
DDRB = 0b11111111; // Set all the pins of PortB as output
while (1) { // Set up an infinite loop
PORTB = 0b10000000; // Turn on LED1
_delay_ms(50); // Wait
PORTB = 0b01000000; // Turn on LED2
_delay_ms(50); // Wait
PORTB = 0b00100000; // The same sequence repeats…
_delay_ms(50);
PORTB = 0b00010000;
_delay_ms(50);
PORTB = 0b00001000;
_delay_ms(50);
PORTB = 0b00000100;
_delay_ms(50);
PORTB = 0b00000010;
_delay_ms(50);
PORTB = 0b00000001;
_delay_ms(50);
}
}
But it don’t work , i use Ubuntu 10.10 and last version of eclipse IDE.
Fantastic graphics Sir, and that makes a great difference for people trying to understand.
I appreciate your effort as I’m sure many others do.
Now, if I could just understand ‘floating’ inputs..
I’ve been playing around with (Attiny2313 USI –> I2C) and the board I’m using already has 10k pullups which may be a bit too much resistance.
Just wondering if internal + external pullups actually accumulate resistance or not.
Try this.
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */
#include
#include
#include
int main(){ // The main function
DDRB = 0b11111111; // Set all the pins of PortB as output
PORTB = 0b10000000;
while (1) { // Set up an infinite loop
_delay_ms(50); // Wait
PORTB = PORTB<<1;
}
}
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */ #include #include #include int main(){ // The main function DDRB = 0b11111111; // Set all the pins of PortB as output PORTB = 0b10000000; // Turn on LED1 while (1) { // Set up an infinite loop PORTB = PORTB<<1; //Shift LED _delay_ms(50); // Wait; } }You made some first rate factors there. I seemed on the internet for the issue and found most people will go along with along with your website.
i still confuse using each of them… can it probably have different I/O for each of them like DDRx as input and port as ouput then pin as input…can you make it simple example for each of them??
I am not a programmer, i was in need for some basic info to do a small task related to my main master thesis project in laser, your tutorial was very useful and handy, many thanks
look for ‘ob11111111′ in the text. it should probably read as ’0b11111111′
besides, i didn’t get this part
DDRB = 0b00000000; /* Configuring I/O pins of portb */
PORTB = 0b01110101; /*enable internal pull-up resistors on output pins 1 , 3 , 5 , 6 , 7 */
the second line – is it correct?
PORTB = 0b01110101; /*enable internal pull-up resistors on output pins
1 , 3 , 5 , 6 , 7 */
I dint get how it enables internal-pull resitors o pin 1,3,5,6,7 ?
please help ?
thanks.
It is a wonderful tutorial
am now working on fingerprint base attendance system and i need your help how to interface sm630 finger print module to atmega32 please give a hint
thanks
ismailkamal2099@gmail.com
[...] ենք ինետից ցանկացած օրինակ, ասենք վազող լույսերը այստեղից քոմփայլ անում, ու լցնում կոնտրոլերի [...]
[...] [...]
[...] [...]
[...] [...]
[...] AVR GCC Tutorial (1) – Basic I/O Operations « Suhas’s Blog [...]
You show that you make the third and seventh pins outputs like this:
DDRB = 0b10001000;
And then that you can make all pins outputs like this:
PORTD = 0b11111111;
Does that mean that DDRx and PORTx are interchangeable and equivalent?
Nick
Could you give and example for for every pulse input time distance assigned to an instance as an integer for a logic anaylises.
Thanks.
[...] [...]
[...] [...]
Thanks for your tutorial. it useful for me because i am learn about avr with programming C. I hope better more tutorial from you!!!!
good animations for better understanding
Awesome, guys! Thanks! Use your uCs to unlock you phone!
[...] [...]
Infinite thanks!!!
doesn’t the output current of port have a certain limit? isn’t it better to connect the led to vcc and give ground of the led through ucontroller? to protect it from damage? like PORTB = 0b11111110; to light up led1
can u help me..how to make only 1port as input and output..?for example switch on led blinking and motor run
[...] to assist in generating the necessayr settings (and it even generates C-code!). By the way, here http://iamsuhasm.wordpress.com/tutsp…-gcc-tutorial/ is a tutorial on writing C-Code for the AVR controllers. [...]
[...] Asli ArtikelNya Like this:LikeBe the first to like this [...]
pls some one should help me write c++ program to swap between two output pins at a time of 3hour per pin continuous. i mean one output pin must be on for 3hours , goes off the other pin comes on for 3hours continues and respective pin which switch on must display on an lcd screen, am using 8bit atmel avr mcontroller and a standard 16*2 lcd
easy and understandable article on ports! nice explanation with diagrams especially the last gif image.
amazing peice would you link to my article please?
i need to test a single pin then what is instruction?
[...] համար քաշում ենք ինետից ցանկացած օրինակ, ասենք վազող լույսերը այստեղից քոմփայլ անում, ու լցնում կոնտրոլերի [...]
informative and very usefull . thanks
[...] Here is a nice writeup on basic port manipulation for AVR microcontrollers: Suhas's Blog: AVR GCC Tutorial (1) [...]