Electronics – Tuts, tips and much more …

If we hear, we forget; if we see, we remember; if we do, we understand – Confucius

AVR : Tutorial 2 : AVR – Input / Output

Posted by Omkar on February 12, 2008

         UPDATE : 10 FEB 08 – illustration added

Tutorial

Overview

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.

Registers

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.

example:

  • 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
    

Summery

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;
n/a

 
 

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

    while(1)
    {
        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 :
.blink

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,
                        0b01000010,    
                        0b00100100,
                        0b00011000 };

unsigned char p2[4] = { 0b11111111,
                        0b01111110,    
                        0b00111100,
                        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

    while(1)
    {
        //# if SW0 is pressed show pattern 1
        if(PINC.0==0)                                           
        {
            for(i=0;i<3;i++)
            {
                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
        if(PINC.1==0)           
        {
            for(i=0;i<3;i++)
            {
                PORTB=p2[i];    //output data
                delay_ms(300);  //wait for some time
            }
            PORTB=0;            //turn off all LEDs
        }

    };        
}
About these ads

85 Responses to “AVR : Tutorial 2 : AVR – Input / Output”

  1. 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?

    Like

    • Omkar said

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

      Like

  2. S.Vishali said

    why we are not getting the voltage at the specified port

    Like

  3. M.Sabeena said

    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 .

    Like

  4. sharma said

    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

    Like

  5. jay dubey said

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

    Like

  6. 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?

    Like

    • Omkar said

      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.

      Like

  7. ran said

    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 :(

    Like

  8. WSS said

    THANKS A LOT. REALLY THANK YOU :-)

    Like

  9. Its a great start for freshers…thanks.

    Like

  10. Jason said

    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..

    Like

  11. h_chinh94fbr said

    thanks a lot

    Like

  12. Treehouse Projects said

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

    Like

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

    Like

  14. [...] so I looked up the basics of driving an AVR to make its input/output ports work.  I stumbled on this explanation, telling me about the main three registers and pull-up resistors and so on, which was very [...]

    Like

  15. Ariz Zubair said

    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.

    Like

  16. Thoufeeq said

    Thanks for the article, was quite helpful…

    Like

  17. Rafael said

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

    Like

  18. kingsley said

    How can i use ATmega16 16 bits timer to create delays

    Like

  19. kingsley said

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

    Like

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

    Like

  21. DEEN BANDHU AGRAWAL said

    wow it had really helped me

    Like

  22. [...] [...]

    Like

  23. [...] [...]

    Like

  24. hafxx said

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

    Like

  25. manisha said

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

    Like

  26. kedarnath reddy said

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

    Like

  27. Iqbal said

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

    Like

  28. Shakhawat said

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

    Like

  29. anoop said

    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..

    Like

  30. [...] Posts How to make simple Infrared Sensor ModulesAVR : Tutorial 2 : AVR – Input / OutputMake your own, ultra simple, universal AVR programmer !!Anode and Cathode of LED !AVRDude Tutorial : [...]

    Like

  31. Owais said

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

    Like

  32. [...] Good information about configuring the ports for input/output. UPDATE : 10 FEB 08 – illustration added Tutorial Overview 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 … Read More [...]

    Like

  33. [...] line up the m328p schematic so I’ve often misplaced a pin and had to test it a couple times. This is very useful especially in its explanation of ports. I’m unsure on why part of that code [...]

    Like

  34. rajput vikas singh said

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

    Like

  35. Munish said

    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.

    Like

  36. sabeeh said

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

    Like

  37. Marco said

    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?

    Like

    • Omkar said

      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.

      Like

  38. kiran said

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

    Like

  39. rishi said

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

    Like

  40. Priyanka said

    Thanx…this is what i was exactly looking for.

    Like

  41. saeed said

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

    Like

  42. Elliot Brown said

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

    Like

  43. fabrizio said

    Mate,
    this is exactly what I wanted to know !

    well done
    fabrizio

    Like

  44. zayed said

    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.

    Like

  45. divyanaidu said

    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

    Like

  46. naz said

    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!!

    Like

  47. [...] AVR : Tutorial 2 : AVR – Input / Output [...]

    Like

  48. almostnone said

    Thanks. This helped me understand Atmega1280 as well.

    Like

  49. noufal said

    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
    .cseg
    .org 0x00
    JMP MAIN

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

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

    please help me to find the error… hopefully

    Like

  50. praveen said

    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

    Like

  51. Niklas said

    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!

    /Niklas

    Like

  52. josh said

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

    Like

  53. josh said

    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.

    Josh

    Like

  54. aak fajar said

    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.

    Like

  55. harsh said

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

    Like

  56. Omi said

    >>Avinash
    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.

    Like

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

    Like

  58. Omi said

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

    Like

  59. 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.

    Like

  60. Omi said

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

    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
    014:
    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.

    Like

  61. Omi said

    @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.

    http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

    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: }

    Like

  62. Donatas said

    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.

    Like

  63. Benzun said

    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….

    Like

  64. Ashutosh said

    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.

    Like

  65. elecrom said

    @Ashutosh
    I didn’t get what u say.

    Like

  66. Ashutosh said

    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.

    Like

  67. ashishd said

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

    Like

  68. [...] AVR : Tutorial 2 : AVR – Input / Output [...]

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 98 other followers

%d bloggers like this: