UPDATE : 10 FEB 08 – illustration added



You cannot imagine to use microcontroller without using any of its i/o pins. Finally its all about  : taking input , processing it and generating output ! Thus i/o registers and their correct settings is indispensable part while learning to program any uC.

We will learn how to use AVR ports and actually ‘code’  for writing/reading data to/from port pins. It is slightly confusing for beginners, however once you understand it, you will certainly appreciate the way it is designed.

NOTE : I will frequently refer to  ‘configuring pin’ or simply ‘pin’. Remember, a port has multiple pins. Thus in order to change setting for one port, you have to change setting for all port pins of that port. To change setting for one single pin of the port, you have to change a particular bit in associated register. Got that ? If not read this para again.


AVR is 8 bit microcontroller. All its ports are 8 bit wide. Every port has 3 registers associated with it each one with 8 bits. Every bit in those registers configure pins of particular port. Bit0 of these registers is associated with Pin0 of the port, Bit1 of these registers is associated with Pin1 of the port, …. and like wise for other bits.

These three registers are as follows :
(x can be replaced by A,B,C,D as per the AVR you are using)
– DDRx register
– PORTx register
– PINx register


DDRx register

DDRx (Data Direction Register) configures data direction of port pins. Means its setting determines whether port pins will be used for input or output. Writing 0 to a bit in DDRx makes corresponding port pin as input, while writing 1 to a bit in DDRx makes corresponding port pin as output.


  • to make all pins of port A as input pins :
    DDRA = 0b00000000;
  • to make all pins of port A as output pins :
    DDRA = 0b11111111;
  • to make lower nibble of port B as output and higher nibble as input :
    DDRB = 0b00001111;

PINx register 

PINx (Port IN) used to read data from port pins. In order to read the data from port pin, first you have to change port’s data direction to input. This is done by setting bits in DDRx to zero. If port is made output, then reading PINx register will give you data that has been output on port pins.

Now there are two input modes. Either you can use port pins as tri stated inputs or you can activate internal pull up. It will be explained shortly.

example :

  • to read data from port A.
    DDRA = 0x00;    //Set port a as input
    x = PINA;       //Read contents of port a 

PORTx register

PORTx is used for two purposes.

1) To output data  :  when port is configured as output

When you set bits in DDRx to 1, corresponding pins becomes output pins. Now you can write data into respective bits in PORTx register. This will immediately change state of output pins according to data you have written.

In other words to output data on to port pins, you have to write it into PORTx register. However do not forget to set data direction as output.

example :

  • to output 0xFF data on port b
    DDRB = 0b11111111;        //set all pins of port b as outputs
    PORTB = 0xFF;             //write data on port 
  • to output data in variable x on port a
    DDRA = 0xFF;              //make port a as output
    PORTA = x;                //output variable on port
  • to output data on only 0th bit of port c
    DDRC.0 = 1;        //set only 0th pin of port c as output
    PORTC.0 = 1;       //make it high. 

2) To activate/deactivate pull up resistors – when port is configures as input

When you set bits in DDRx to 0, i.e. make port pins as inputs, then corresponding bits in PORTx register are used to activate/deactivate pull-up registers associated with that pin. In order to activate pull-up resister, set bit in PORTx to 1, and to deactivate (i.e to make port pin tri stated) set it to 0.

In input mode, when pull-up is enabled, default state of pin becomes ‘1’. So even if you don’t connect anything to pin and if you try to read it, it will read as 1. Now, when you externally drive that pin to zero(i.e. connect to ground / or pull-down), only then it will be read as 0.

However, if you configure pin as tri state. Then pin goes into state of high impedance. We can say, it is now simply connected to input of some OpAmp inside the uC and no other circuit is driving it from uC. Thus pin has very high impedance. In this case, if pin is left floating (i.e. kept unconnected) then even small static charge present on surrounding objects can change logic state of pin. If you try to read corresponding bit in pin register, its state cannot be predicted. This may cause your program to go haywire, if it depends on input from that particular pin.

Thus while, taking inputs from pins / using micro-switches to take input, always enable pull-up resistors on input pins.

NOTE : while using on chip ADC, ADC port pins must be configured as tri stated input.

example :

  • to make port a as input with pull-ups enabled and read data from port a
    DDRA = 0x00;        //make port a as input
    PORTA = 0xFF;       //enable all pull-ups  
    y = PINA;           //read data from port a pins
  • to make port b as tri stated input
    DDRB  = 0x00;        //make port b as input
    PORTB = 0x00;        //disable pull-ups and make it tri state
  • to make lower nibble of port a as output, higher nibble as input with pull-ups enabled
    DDRA  = 0x0F;        //lower nib> output, higher nib> input
    PORTA = 0xF0;        //lower nib> set output pins to 0, 
                         //higher nib> enable pull-ups


Following table lists register bit settings and resulting function of port pins

register bits →
pin function↓
DDRx.n PORTx.n PINx.n
tri stated input 0 0 read data bit
x = PINx.n;
pull-up input 0 1 read data bit
x = PINx.n;
output 1 write data bit
PORTx.n = x;


Hands on …

-You can type following programs in CodeVisionAVR and test them on your development kit .
– To know, how to burn code into uC using PonyProg2000, click here.
– If you don’t have development kit, simply connect 8 LEDs to PB (i.e port b).
– In Project>Configure>C compiler do not forget to set following options :
Chip   : ATmega16 (or whatever you are using)
Clock : 16MHz (or whatever you are using)
– Experiment with these programs and try to learn more from it.

1) Blink LED on PB0 at a rate of 1Hz.

#include <mega16.h>
#include <delay.h>

void main()
    DDRB = 0xFF;         //PB as output
    PORTB= 0x00;         //keep all LEDs off

        PORTB.0=0;       //turn LED off
        delay_ms(500);   //wait for half second
        PORTB.0=1;       //turn LED on 
        delay_ms(500);   //wait for half second
To see how to create blank project, write above code in CodeVisionAVR and then how  to MAKE it . Click on following image :

Download Link for illustration.

2) Blink LEDs on PB with  different patterns according to given input.

– Kit : use SW0, SW1
– No Kit : Connect a 2 micro-switches between pin PC0,PC2 and ground. So that when you press the switch pin is pulled low.
#include <mega16.h>
#include <delay.h>

//declare global arrays for two patterns
unsigned char p1[4] = { 0b10000001,
                        0b00011000 };

unsigned char p2[4] = { 0b11111111,
                        0b00011000 };
void main()
unsigned char i;                //loop counter

    DDRB = 0xFF;                //PB as output
    PORTB= 0x00;                //keep all LEDs off

    DDRC = 0x00;                //PC as input
    PORTC.0 = 1;                //enable pull ups for
    PORTC.1 = 1;                //only first two pins

        //# if SW0 is pressed show pattern 1
                PORTB=p1[i];    //output data
                delay_ms(300);  //wait for some time
            PORTB=0;            //turn off all LEDs

        //# if SW1 is pressed show pattern 2
                PORTB=p2[i];    //output data
                delay_ms(300);  //wait for some time
            PORTB=0;            //turn off all LEDs



  1. Saish

    all post by me r for aTmega 32 UC

  2. Saish

    to receive data on rx pin frm receiver module
    is dis da correct command
    PORTD.0= 1;

  3. Saish

    to get input on adc pins is dis da right command
    DDRA= 0X00

  4. Kia

    This arctile shows how pointer and its massive works.thanks


  5. I am really loving the theme/design of your web site.

    Do you ever run into any browser compatibility issues? A number of my
    blog audience have complained about my website not operating correctly in Explorer but looks great in Firefox.
    Do you have any solutions to help fix this problem?

    • Omkar

      This is developed using standard wordpress templates. These templates are well tried and tested and work properly on most of the platforms.

  6. S.Vishali

    why we are not getting the voltage at the specified port

  7. M.Sabeena

    i have flashed the servo program in the ATMEGA 8L controller and practically checking the controller by connecting the servo . servo was not running and we didn’t get the voltage at the output port .

  8. sharma

    same characters data is given into microcontroller atmega16L but it is taking some of the continous same bits as different.
    help to resolve the problem

  9. jay dubey

    i tried to read keypad from portA and use pull ups but it displayed random numbers. can you help??


  10. The DDRC.0 = 1; format doesn’t work for me. I get something like:

    expected ‘;’ before numeric constant

    I have to mask the relevant bits to make it happen. Is it just me?

    • Omkar

      DDRC.0 = 1; >> This format is supported by CodeVisionAVR compiler. Other standard C compilers don’t support it, so you will have to do masking.


      • How can we do this type of programming in AVR Studios ?? I am not able to get how to address the particular pins of a port.

        • Etienne Doucet

          Here’s some example of how you can manipulate a single bit in AVR Studio

          DDRx &= ~(1<<4); //To clear a bit (Same as DDRx.4 = 0)
          DDRx |= ~(1<<4); //To set a bit (Same as DDRx.4 = 1)
          DDRx ^= ~(1<<4); //TOGGLE bit 4 in DDRx register

          x Can be A,B,C,D … depending on what you need to change
          4 Can be 0-7 (the bit number you want to change)

          You can also change an entire port value with 1 command
          DDRB = 0xFF; //0b11111111
          PORTB = 0x07 ; //0b00000111

  11. ran

    I don’t understand how to set an interupt. Can you help me, if I want to program atmega 8535 with interupt after 1 minute. I really need some help :(

  12. WSS



  13. Its a great start for freshers…thanks.

  14. Jason

    Now can you make a tutorial for AVR32? I can’t make a freakin port any which way and Atmel Studio 6 won’t let you..

  15. h_chinh94fbr

    thanks a lot

  16. Treehouse Projects

    Thanks a lot, great tutorial for someone just starting with the Atmega series!


  17. Very neat and easy tutorial about AVR I/O, the overall credit goes to omkar. The article presentation is very impressive!

  18. Ariz Zubair

    it was quite useful .
    Can u please help me with receiving 16 bit serial input on porta.1 and output the parallel data on portb and port c.

  19. Thoufeeq

    Thanks for the article, was quite helpful…

  20. Rafael

    Thanks! With this info I can work with input! :)

  21. kingsley

    How can i use ATmega16 16 bits timer to create delays

    • Omkar

      Configure the timer in CTC top mode, set the top count in OCR register and wait till the count match occurs. This will give u variable delays.

      • kingsley

        Thanks for the hint, to be frank i’m new at using AVR. Can you give me any code in C that is used to create the delay.

  22. kingsley

    Thank you so much, your tutorial has given me a head start. I really appreciate your effort simplifying AVR programming

    • Omkar

      Thank you.


  23. wow! I was really wondering how the hell was this PINx working? and I got the answer. Thankx admin


    wow it had really helped me


  25. hafxx

    thanks a lot for this information.. very nice.. and its give me some idea/clue to understand basic i/o for microcontroller…

  26. manisha

    What is the meaning of y[0]=(PINA & 0x01);

    • Omkar

      it means, y[0] will get the value of 0th bit of port A. It will be either 0 or 1.

      • gautam

        i have error of above program so please tell me solution

    • neeraj

      how to declare the y[0] over here

  27. kedarnath reddy

    Thanks a lot this gives a clear idea of the Input and Output configuration.

  28. Iqbal

    is there any tutorial for AVR assembler and c language??

    • hassan

      well there is one at a time, first learn assmbly thn c,, thts recomendation,..

  29. Shakhawat

    Thanx a lot. Its something exxactly, I was looking for.

  30. anoop

    Sir i am saying you my extreme thanks..Actually i was in a problem with the port setting of my ATmega32 controller.Your tutorial help me a lot…Once again i am thanking you..Expect more like this from you..

    • Omkar

      :) … thanks for appreciation.

  31. Owais

    Thanks alot Sir, Exactly what I was searching.
    You really need a big round of applause…. Hats off.

  32. rajput vikas singh

    sir i think u should include more led blinking programs to clear the concepts


  33. DDRx.n, PORTx.n and PINx.n (n=0..7)do not work in WINAVR. Would have been nice if you added code for that too.

  34. sabeeh

    thx alot man!…this is wht i waz lookin 4…


  35. Thank you for the superb tutorial, but there is one thing I don’t fully understand.

    I have an input signal and I want it to be 0 when the output device is not connected. You mention to set the PORTX high to achieve pull-up, and set it to zero to achieve tri-state. But I want to achieve pull-down. It isn’t mentioned in the tutorial how to do this. I tried setting neither and just let it choose by it’s own, but I’m not getting a pull-down. Could anyone help me with this?

    • Omkar

      To do this, make port pin tri stated and then connect external 10K resistor between port pin and ground pin. This 10k resistor will act as a ‘pull down’ resistor. In this way, when device is not connected, pin will get pulled down to ground potential.

  36. kiran

    superb tutorial, first para. gives idea of importance of this tut.

  37. rishi

    i really like ur tutorials.i have doubts in interfacing keyboard with atmega16 using code vision avr.please clarify me the concept and programming.

  38. Priyanka

    Thanx…this is what i was exactly looking for.

  39. saeed

    i can’t run portl and h & k in avr stadio4.micro is atmega2560

  40. Elliot Brown

    <codePINC.1==0</code Is this valid for atmega8 and all compilers? I've heard it doesn't work for all.

    • Omkar

      – ATmega8 has PORTC and hence you can use the statement if(PINC.1==0) – This statement is valid only in those compilers which support bit level access. For other compilers you can use : if( (PINC & 0x02) == 0)

      • Tony

        i use AVR Studio, and it doesnt work with single bit acces (PORTC.1 = 1;).
        What compiler should i use to make it works?
        I work with ATMega16 THX

        • Omkar

          you can use CodeVisionAVR compiler. Or in AVR Studio you can also write like this : PORTC.1 = 1;.is equivalent to : PORTC = PORTC | 0x01;

          • MP

            hey man.. what is the equivalent of PORTC.1 = 0; ?????

    • MP

      hey man.. what is the equivalent of PORTC.1 = 0; ????

      • Omkar

        “PORTC.1 = 0″

        is equivalent to :

        “PORTC = PORTC & 0b11111101″

  41. fabrizio

    this is exactly what I wanted to know !

    well done

  42. zayed

    Design and implement a a communication link of two AVR’s using SPI. One AVR is connected to
    switches through its GPIO lines. It reads the status of the switches and send it to another using
    SPI. The second AVR reads the received data and display it on 7-segment displays. Include a
    snapshot of the serial clock and data lines as seen on an oscilloscope.

  43. divyanaidu

    yeah,in a very simple and understanding way explained ,its very helpful for begginers,
    i am using atmega2560 –from external sensors to adc through spi communication i suppose to do

    would any one send me any source code or something how to implement


  44. Im including a list of great AVR tutorials on my blog, so ill have to sift through your work and see if I can include your tutorials!!

  45. almostnone

    Thanks. This helped me understand Atmega1280 as well.

  46. noufal

    Halo, I’m just beginner of programming AVR and I have some problems. I’m working with AVR Studio 4 and writing a program for ATmega16 TIMER0 normal mode in assembly language..the code is
    .equ TCCR0=$33
    .equ TCNT0=$32
    .equ TIFR=$38
    .org 0x00

    LDI R16,0X02
    out TCCR0,R16
    l1: SBIS TIFR,0
    JMP L1

    when compiling it shows the error
    D:avrtimer.asm(13): error: Operand 1 out of range: 0x38
    D:avr assemtimer.asm(22): No EEPROM data, deleting D:avr assemtimer.eep

    please help me to find the error… hopefully

  47. praveen

    please post AVR : Tutorial 3.
    Ur first two were very informative, so please post AVR : Tutorial 3
    write abt advance prog n burning da hex file in da uC

  48. Niklas

    Very nice and informative tutorial. Please post more of these tutorials they are really usefull for me, on the right level so to speak.

    Perhaps you can recommend some other resoures for beginners, perhaps the ones who helped you when you first got started.

    I look forward to your next post, its been 8 months!


  49. josh

    never mind, I found it. This site is very helpful, keep it up.

  50. josh

    hi, where can i find the mega16 and delay header file? I have the original AVR library but has none of those file in it.


  51. aak fajar

    In datasheet ATMega8535, ADC has 10-bir resolution. But I can’t setting ADC in this resolution (10-bit). May u can help me how to setting ADC in ATMega8535 with 10-bit resolution. Or may be i must to add other circuit to use ADC 10-bit?
    I hope u can reply this question ini my mail. Thanks.

  52. harsh

    How to burn a program from computer to atmega16 microcontroller using ping prong.

  53. Omi

    I don’t think its possible to overclock low speed (L) versions. I have tried overclocking 16PU versions and they work fine. 16PU can be overclocked upto 24MHz, but you should give supply voltage of 5.5 and not 5.0. Whenever you overclock, you should increase supply voltage upto (just less than) maximum limit of the chip for proper operation at elevated clock rate. However don’t run it at 24MHz unless really required. In my opinion you can run it safely upto 20MHz.


  54. Nice work. Have you tried overclocking avrs. Can the lower power versions (L) can be made to run with speed more than 8Mhz?

  55. Omi

    >>Sri Ram
    I will post tutorial on interrupts soon.


  56. Thank you very much. U tutorial really helped me in understanding i/o ports. Though I did not understand clearly (I am not EEE) the concept of impedance for tri state input, but it clarified the main concept how to use ports for different purposes. It seems to me your knowledge of AVR programming was mastered, can you please send me tutorial on interrupts and interrupt vectors (mega128 or similar) to my mail vsriramkshdev@gmail.com if you have any. Any help will be much appreciapted. Thank you.

  57. Omi

    @Donatas : Whats this “delay.h” stuff ???

    In above function some delay will be generated by loop at line 5. You can change the loop count to adjust the delay. You can fix the loop count by some trial and error for 1ms or so and then use that function. You can also put lots of assembly “NOP” instructions inside loop at line 5 and get some predictable delay. For example if your uC is operating at 8MHz, then one NOP will take 125ns …

    001: void my_delay_ms(unsigned int m )
    002: {
    003: unsigned char p;
    004: for( ;m>0;m=m-1 )
    005: for(p=0;p<100;p++) //This will generate approximate delay
    006: { //of 1ms using NOPs
    007: #asm(“nop” )
    008: #asm(“nop” )
    009: #asm(“nop” )
    010: #asm(“nop” )
    011: #asm(“nop” )
    012: // … repeate total 80 times. So these NOPs will
    013: // give delay of 80 x 125ns = 10uS
    015: }
    016: }

    This function will provide approximate delay in multiples of 1ms. Delay is approximate because, delay occured by instructions required for looping are ignored. Because of this actual delay will be slightly more than the specified one.

  58. Omi

    @Donatas : Whats this “delay.h” stuff ???

    You have mentioned AVR studio 4 but not mentioned which compiler you are using. Anyways … many AVR C compilers have built-in delay functions to ease programming. They are defined in delay.h.

    In above program, to generate delay I am using such library function “delay_ms()”. It is defined in “delay.h” (for this specific compiler, i.e. codevisionavr) and hence included. See the code vision avr help for more details of “delay_ms()”.

    For avr-gcc, similar file is “util/delay.h”. See this for more information about this file.

    Alternatively, if you don’t want to use built in delay, you can make some function like this :
    001: void some_delay(unsigned int some_number )
    002: {
    003: unsigned long int p;
    004: for( ;some_number>0;some_number=some_number-1 )
    005: for(p=0;p<300000;p++ )
    006: {
    007: }
    008: }

  59. Donatas

    Hi, I’m just beginner of programming microcontrollers and I have some problems. I’m working with AVR Studio 4 and writing a program for ATmega16. In your examples and in a lot of other examples delay.h is included, but I can’t find it and for this reason I have an error. What I should do and where I can find this file?
    P.S.: it would be very nice if you write some examples about processor sleep mode and saving battery when mC is doing nothing.

  60. Benzun

    I must say your tutorial is very good.. i am just entering second yr… and was never clear about avr pin setting.. but your tutorial cleared a lot of doubts.. can u just explain me the purpose of pull up… i dont understand it clearly.. if u have time can u pls mail me at benzun1999@gmail.com ?? must say your work is awesome.. you have a very clear understanding of avr programming….

  61. Ashutosh

    Actually iam using two ir sensors kept at a fixed distance.Both connected to two adc pins of atmega8L.When a object passes in front of first sensor,the analogue signal is taken and converted into digital and goes to pc via parallel port,here a timer starts as the signal is received and stops on receiving second signal.As distance is known and time ir there,speed can be calculated.I want to know abt how to go for programing.

  62. elecrom

    I didn’t get what u say.

  63. Ashutosh

    Hey i need to use adc port of atmega8L to receive input from ir sensors and then send to the parallel port to measure speed. Guide me in programming part.

  64. ashishd

    Omkar, Can u created swf file?
    Are we not suppose to upload files?


Post Comment