Microcontroller For Beginners

AVR microcontroller for beginner......




            :: This Site is for the Beginners of AVR Micro ::

If you are a real beginner, this site might be helpful to you. (Not completed)


About the Site Admin:

I am Nahian Rahman, নাহিয়ান রহমান।

My FB: 


Email: nahianme@gmail.com

Blog: http://nahiansrobotics.wordpress.com/ 

বাংলাতে একটি রোবটিক্স কোর্স পড়িয়েছি এখানে,  :  http://www.shikkhok.com/কোর্স-তালিকা/robotics101/

 ### for my Bangladeshi followers:: VUSB video tutorial







 Atmel launched Atmel studio 6, it contains two Architectures in one studio.......hope that will be great







Atmel have launched AVR Studio 5 Beta, seems robust!!!!!!!!!!! click here to download





Atmel's new   is about time to market.

Some chips of AVR series are obsolete totally. Here is a sample of their new FPSLIC.....




However Atmega32 is going to replaced by Atmega32A like some others.(like:Atmega8~Atmega8A, Atmega16~ Atmega16A). They will available soon. 



Main purpose of these pages is only  to explore the various features of Microcontroller (AVR), or more specially Atmega32. NO FULL PROJECT OR CODE. I am preparing another site for complete projects, will publish soon. If you are a beginner, this site is helpful for you. 



 This site is designed for the students to learn micro-controller from very basics. From my experience, students struggle due to two reasons. Firstly they struggle to make theProgrammer. Secondly, lack of basic circuit & programming knowledge. Those who passed these twos, very often read the DATASHEET!! I will post about the AVR series, specially Atmega32 very popular IC manufactured by ATMEL.                                                                                                                                                                                                                                                                                                                     --- Nahian Rahman

                                                                                                                                Site owner   

                          To learn micro-controller, One must have....

a background on Programming language. I will post all the examples written in C language. One important thing, actually you never know microcontroller better if you dont know assembly or other low level language. AVR studio has an editor Assembler and GCC.

Elementary circuit knowledge (like breadboard, KVL,KCL, passive elements) is essential. Finally one must have patience. 


I dont wanna answer questions like, "How to use breadboard?" click below...

 Q-1 How to use breadboard? 

 Q-2 What is KVL? 



Read the articles carefully, if u get a new term, google it. You can also see the FAQ section, Or skip it for the time being and keep reading.  

                            About Micro-controller & Atmega32

::::::::::::::::::::::::::::::::Basics of ATMega32:::::::::::::::::::::::::::::::::::::::::


You can say It is a 8-bit Computer with 32K Bytes In-System Programmable Flash available in 40 PDIP. As every Micro-controller is a mini computer, it has a RAM of 2K Byte, 32I/O general input output registers,1024 Bytes of EEPROM. The speed of this computer is Maximum 16 MHz. (*Atmega32 is 16PU, But Atmega32L is 8PU) I suggest not to run above 12 MHz. Normally, you don't need to connect a Crystal Oscillator to generate clock pulses. The device has an Internal Crystal (RC) Oscillator. By default it operates a frequency of 1 MHz(not accurate), if you don't change the Fuse Bits(CKSEL3,CKSEL2,CKSEL1,CKSEL0 bits of low fuse bit) or change the value of OSCCAL register through programming.  Don't worry!! I will explain all these new terms later on. Lets come to the basics again.  

You may concerned about the speed of controller, where processor speed of Desktop PC is about some GHz these days. Definitely Micro-processor of PC has much more capabilities, but you cant use it for your own embedded system/circuit. They are not available as programmable like micro-controller. It is million times programmable (readable/writable/erasable, 20 years data retention).   

Then again you can say why we should go for Micro-controller interfacing rather than PC interfacing. You can interface your circuit with pc through serial, parallel, USB to the more powerful processor. But the processor does not allow some features through these ports(due to security) which are readily available for use in our controller. (like timer/counter, general interrupts, PWM, ADC/Comparator (dedicated channel) and others) Specially in robotics or other embedded systems these features are necessary. So PC Ports are designed for communication(data) with external world but not for control things.  If your small but applicable low cost project needs a PC to start with for control, horrible! if then your device is a robot, you might have to run with long wires!!  Micro-controller is available at low cost, you only need to load program (ISP is there and million times programable) on it as control strategy. 

So often people get confused with the two terms Micro-controller and Micro-processor. Simply the first term is a mini computer with processor, ram, memory internally. The second term is a processor itself, you need to connect ram, memory, buses externally
I  suggest to see some informations about AVR family, architecture.  


:::::::::::::::::::::::::Be a member to see all pages:::::::::::::::::::::::

                              .:::::::ATMega32 Features:::::::.


  •  32 KB of FLASH
  •  2KB of SRAM 
  •  1024 Bytes of EEPROM for data storage
  •  16 MIPS Processing Speed at 16 MHz
  •  JTAG (IEEE std. 1149.1 Compliant) Interface
  •  32 I/O lines
  •  32 x 8 General Purpose Working Registers
  •  3 Hardware Interrupts
  •  Two 8-bit Timer/Counters with Separate Prescalers and Compare Modes
  •  One 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and  Capture  Mode
  •  Real Time Counter with Separate Oscillator
  •  Four PWM Channels
  •  8-channel, 10-bit ADC, 2 Differential Channels with Programmable Gain  at 1x, 10x, or  200x
  •  Byte-oriented Two-wire Serial Interface
  •  Programmable Serial USART
  •  Master/Slave SPI Serial Interface



 For Details::   See Datasheet



                                                          ATMega32 outlook


                                                               ATMega16/32 PIN DIAGRAM


Please read the page 3 to 9 from datasheet.... 

You cant even think what kind of things can be controlled by this! Most popular PDIP of AVR series are ATMega8/8L,ATMega88,ATMega16/16L,ATMega32/32L as well as the ATtiny ones.You can learn every chips if you learn just one! 

You will see the pinout of Atmega16 and Atmega32 is exactly same. The difference is only in some internal architecture.Like Mega16 has 1 K of Ram, 16 K of flash,512 bytes of EEPROM, where Mega32 has just double.

Designation of "L" (Atmega32L / Atmega8L /Atmega16L) means lower speed grades and less voltage requirements. Example from datasheet:


• Operating Voltages

              –   2.7 - 5.5V for ATmega16L

              –   4.5 - 5.5V for ATmega16

• Speed Grades

               –   0 - 8 MHz for ATmega16L

               –   0 - 16 MHz for ATmega16

• Power Consumption @ 1 MHz, 3V, and 25'C for ATmega16L 



PIC,  manufactured by microchip, where AVR manufactured by ATMEL are the leading micro-controllers these days.  No real reason to choose any of  it, to me Atmel's software is  free and easy to get.  Some say PIC is four times faster than AVR, some  say AVR is three times faster than PIC.   



Its not a matter which one is better. Matter is what you can do. I never used PIC. So I dont know it. According many statistics in the webs its looking AVR The WINNER.  

If you need exact timing an AVR is the optimal solution for your problem. 

To execute one instruction is equal to the processor's clock cycle. If the processor runs on a 4 MHz clock frequency then one instruction requires 1/4 µs or 250 ns, at 10 MHz clock only 100 ns. The required time is as exact as the xtal clock. Note that there are a few commands that require two or more cycles, e.g. the branching instructions (if branching occurs) or the SRAM read/write sequence.

To define exact timing there must be an opportunity that does nothing else than delay program execution. You might use other instructions that do nothing, but more clever is the use of the No OPeration command NOP. This is the most useless instruction:


We will rather write, 


This instruction does nothing but wasting processor time. At 4 MHz clock we need just four of these instructions to waste 1 µs. No other hidden meanings here on the NOP instruction. For a signal generator with 1 kHz we don't need to add 4000 such instructions to our source code, but we use a software counter and some branching instructions. With these we construct a loop that executes for a certain number of times and are exactly delayed. A counter could be a 8-bit-register. 


See datasheet And keep an eye on








So lets make our programmer first...... click here..... I suggest then come again and keep reading.....

:::::::::::::::::::::Be a member to see all pages:::::::::::::::::::::::::::



Lets take a look at the Registers of Atmega32


::::::::::::::::::::::::::Status Register:

contains information about the result of the most recently executed arithmetic instruction. Its term as SREG, when the GCC or Assembler finds SREG in the program, the compiler goes to certain defined address. If you know the lpt1 interface then you set high on data port like



 the hex number(0x378) is actually the destination of data port.

It’s a 8bit register can be read or write. If your program has an interrupt you must set high the msb of SREG. If the Global Interrupt Enable Register is cleared, none of the interrupts are enabled independent of the individual interrupt enable settings.


See other bits significances from datasheet.


::::::::::::::::::General Purpose Register File:


as I mentioned there are 32 general purpose working registers, termed as R0 to R31. They are addressable and definable.


in C,

#define data R15   // assigning anything to data will store &R15..

in Assembly,

.DEF data= R15           ; Define a new name for register R15


The registers R26..R31 have some added functions to their general purpose usage. These registers are 16-bit address pointers for indirect addressing of the Data Space.



::::::::::::::::::::Stack Pointer Register:


The Stack is mainly used for storing temporary data, for storing local variables and for storing return addresses after interrupts and subroutine calls.

The Stack Pointer points to the data SRAM Stack area where the Subroutine and Interrupt Stacks are located. This Stack space in the data SRAM must be defined by the program before any subroutine calls are executed or interrupts are enabled. The Stack Pointer must be set to point above $60. The Stack Pointer is decremented by one when data is pushed onto the Stack with the PUSH instruction, and it is decremented by two when the return address is pushed onto the Stack with subroutine call or interrupt. The Stack Pointer is incremented by one when data is popped from the Stack with the POP instruction, and it is incremented by two when data is popped from the Stack with return from subroutine RET or return from interrupt RETI.




::::::::::::::::::::The EEPROM Registers:


The ATmega32 contains 1024 bytes of data EEPROM memory. It is organized as a separate data space, in which single bytes can be read and written. The EEPROM has an endurance of at least 100,000 write/erase cycles.


  •    Address Register – EEARH and EEARL
  •    Data Register – EEDR
  •    Control  Register – EECR


 See details on datasheet



:::::::::::::::::Oscillator Calibration Register – OSCCAL


Writing the calibration byte to this address will trim the Internal Oscillator to remove process variations from the Oscillator frequency. Note that the Oscillator is intended for calibration to 1.0, 2.0, 4.0, or 8.0 MHz. Tuning to other values is not guaranteed.



:::::::::::::::::::I/O Registers


Atmega16/32 has 4 ports, named A,B,C and D. each port has three registers.


  •    PORTx
  •    DDRx
  •    PINx


x denotes A/B/C/D.




Well, I am avoiding descriptions about the following (more important registers for programming) we will discuss about these when the feature will come.........just mentioning the names...................








Without example and explanation, it will not possible to understand the register's work. 

:::::::::::::::::::::::::::::End of Registers:::::::::::::::::::::::::::::::::::







:::::::::::::::::::::Be a member to see all pages:::::::::::::::::::::::::::


Well done!! You have already read all the register names at least. Dont be frustrated, even i have been working for 3 years with  particular Atmega32, i'm learning a lot of things every single time i open datasheet. The descriptions i made about registers, almost nothing. When you know all the individual bits of each register, microcontroller will be a toy for you. One must have details knowledge to set every registers. Individual feature example will help to realize it properly. For normal I/O operations you need to touch I/O registers. Except PORTC, the other ports are ready to use as I/O. If you see the Pin diagram, every single pin of 32 i/o lines have other individual name. this name is about its other feature. By default all the features disabled except in PORTC (atmega32/16 not in atmega8). To use PORTC as I/O you must disable JTAG. JTAG can be disabled by three ways.


  •  Disable OCDEN Fuse.
  •  Disable JTAGEN Fuse.
  •  Write one to the JTD bit in MCUCSR.
The 3rd option is best for beginner. So you need to touch a Control register. this register is MCUCSR. See this register at page 67.
Lets learn how to write code, Wiring of Circuit..........
Have a look at the code below...
( Please read page 49 & see the DDRx,PINx,PORTx registers at page 64 of datasheet.....)
/* Its an example to set a port as output.......           */ 
/* The code is written in AVR studio 4                     */
#include<avr/io.h>  // header file 
main()                  // main function
        DDRB  =  0xff;  // set 1 to all data direction registers of port b
               to set 1 to all data direction register (DDR) means the
               associated port set as output. The portb will be an output port.   
              DDRB   =  255;   will result same......
              DDRB |=  255; also result same... initial value of any DDR is 0....
              DDRB   =  0b11111111; will result same.....
              DDRB |=  0b11111111; also result same..initial value of any DDR is 0...
               // forever loop, controller trapped and executes nothing here.
              // all the main codes will stay in a forever loop. 

this code does nothing but set the PORTB as output. Now look below:

high = 1 = 5v, the terms 'high' or 'to set high' or 'to set' or 'to make one' or 'pull up' means assigning 1 to the register. if you assign 1 to PORTx it will give a voltage about 5 volt. If your supply voltage of Atmega32L is 2.9 you never get 5 v assigning 1 to any port bit or byte!!  you will get something about 2.3-2.9v.    

low = 0 = 0v, the terms 'low' or 'to set low' or 'to make zero' or 'pull down' means assigning 0 to the register. if you assign 0 to PORTx it will give a voltage of ground.

This high and low that is 1 and 0 are the all about to control, read (except adc and comparator input),write, data transfer what you say!!  

The Register PORTx will be used when we want to make a pin high or low. (The DDR of corresponding port must declared as 'output' before)

Before looking output lets see some basic connections...

vcc(10)  -- connects this pin to 5 volt (Regulated)

gnd(11) -- connects this pin to 0 volt of supply

Provides power for controller(except ADC feature).  If the controller connected properly,  it will do according the loaded program. If nothing loaded, the reset and some pins of PORTC remain high forever. 

for smooth running, some connections are required. Connect a PF capacitor (22/27 or any) between the supply, as close as possible. Set the RESET pin high with a kohms(4.7/10k) Resistor with switch such that if pressed voltage of supply will dropped through the resistor. Connect AVCC(30) with regulated supply, GND(31) to ground as well as PF between them. This supply is specially to use PORTA as ADC. One have to do that if he wants use ADC, better do always.   

See the pins 12 and 13, denoted XTAL2 and XTAL1 (Crystal) for External Clock Sources. We are using Internal RC Oscillator (1 MHz by default) as clock source. So for the time being no connection needed. Here it is.........



If your connection is ok,  microcontroller will start executing things loaded on it.  The switch in the above figure is the reset. The ATmega32 has five sources of reset:


• Power-on Reset. The MCU is reset when the supply voltage is below the Power-on Reset
threshold (VPOT).



• External Reset. The MCU is reset when a low level is present on the RESET pin for longer
than the minimum pulse length. This is we are using.



• Watchdog Reset. The MCU is reset when the Watchdog Timer period expires and the
Watchdog is enabled.



• Brown-out Reset. The MCU is reset when the supply voltage VCC is below the Brown-out
Reset threshold (VBOT) and the Brown-out Detector is enabled.



• JTAG AVR Reset. The MCU is reset as long as there is a logic one in the Reset Register,
one of the scan chains of the JTAG system. Refer to the section “IEEE 1149.1 (JTAG)
Boundary-scan” on page 225 for details.



When any of these occurs all I/O Registers are set to their initial values, and the program starts execution from the Reset Vector. This does not require any clock source to be running.


lets go to the output code again, When we want to give an output from a pin, the corresponding ddr of that pin must set high before, I told. Then make PORTXx pin high, where X denotes A/B/C/D  and small x denotes (0 ~ 7). for example,


           DDRB  = 0xff; //ddr of PB0~PB7 are high, all these pins are set as output....then,

           PORTB =0b10101010; // the statement made PB1,PB3,PB5 and PB7 high .


              0b10101010 (binary), assigning to its decimal or hexadecimal will result same.

              Rest of the pins PB0,PB2,PB4,PB6 remained at ground voltage. Measure the                           voltages of the whole PORT, you will get it.



     In AVR GCC individual pins cant addressed directly, like to make PB3 pin high, 

           PB3=1;  // you will get an error.... while compiling it.....have a look,


           PA0 = PB0 = PC0 = PD0 =0

           PA1 = PB1 = PC1 = PD1 =1

              PA2 = PB2 = PC2 = PD2 =2

           PA3 = PB3 = PC3 = PD3 =3




           PA4 = PB4 = PC4 = PD4 =4

           PA5 = PB5 = PC5 = PD5 =5

           PA6 = PB6 = PC6 = PD6 =6

           PA7 = PB7 = PC7 = PD7 =7



Whats are the benefits of knowing these? its a bit tricky. It will help when you want to make an individual pin low or high. Say you do not know the state of pin PB5, as well the other 7 pins of that PORT. But for certain condition you want to make that pin high without altering the other 7 pins. so if you assign,

            PORTB = 0b00100000; // remember this line set other 7 pins as zero........

We rather write

           PORTB |= (1<<PB5);

If we want to make PB5 low, then,

           PORTB &= ~(1<<PB5);

If you dont know the symbols (~,|,&, <<, >>), please see operations of bitwise operators from elementary books, or search. 

So You should have a clear conception on Output. Here comes Input.

When we were using output there were two states of a pin. either it was one or zero. The general* input (reading) has similar criteria. Either it will read one/high or zero/low. For reading we need to use another Register, PINX. To use a port as input, all the ddr's of corresponding Port must set as 0. (By default ddr of all ports are zero) Dont think that you must set a full port as input/ output. But you can not make a pin as input and output simultaneously. You can write


                          DDRB = 0b10101011;

The statement made PB7, PB5,PB3, PB1, PB0 as output, PB6, PB4, PB2 as input. you can assign values as your wish to set yours own circuit. The above statement can be written like,

                          DDRB = (1<<PB7) | (1<<PB5) | (1<<PB3) |(1<<PB1) |(1<<PB0);

will result same.

So you dont need to write DDRB = 0x00; (by default), but to keep mind. Before writing code example, what is input? input is setting high or low to your predefined pin externally. Remember the two term PULL UP and PULL DOWN.



Pins from 1 to 8 are the pins of PORTB, not mentioned in the above figure, where PB0~1, PB1~2,...............,PB7~8. In this figure the PB0 is pulled up, and PB4 is pulled down with a resistor of 10K. If PORTB is defined as input with no internal pullup, reading of PINB will give a value 

                                     state_of_B_PORT = PINB;

                         then  state_of_B_PORT gets a value of  0bxxx0xxx1. (x-undefined, 1/0)

The lsb is 1 means it has read logic 'one' from PB0 pin. And the 5th pin is zero means it has read logic 'zero' from PB4.  

It is not essential that you have to assign the value of PINB to other variable. It was an example. Remember PIN of any PORT is also a register. They are being updated. for example

           for(;;)          // forever loop.......


                                if(PINB & (1<<PB4))  // if PB4 i.e. number 5 pin gets logic 1, then TRUE


                                                         // something that to be done when PB4 is 1.




Look below, 




If the switch in the above figure is pressed, The state of PB4,(5 number of IC) will be high. Other than it will remain at low. So you should able to make any pin as input/output. should able to take input from high to low or low to high. should able to make any pin low or high in case of output.

Another thing you must note, in case of reading from external world , you must have to make a state of that pin whose state is being reading by program. I have stated 'undefined' in the first reading. if you dont make any state it can read anything. The things we made at PB0, can be done by internally. This is called INTERNAL PULL UP. 

State of pin number 1 i.e. PB0 is high in the above figure. This can be done by internally too. then we dont need external resistor and the connection. For internal Pull up of PB0, write

                                                         PORTB |=0x01;

                                                         DDRB   = 0;


I am mixing the numbers  intensionally with hexadecimal,decimal,binary so that you can learn all the systems.   

In that case measuring the PB0's voltage, you will find it 'high', Without adding pullup resistor. The reading of PINB0 will high too. So you should understand what to do externally, so that the program reads it as zero.  


                                                       Be a member to see all pages          















#include <avr/io.h>                           //1

#include <util/delay.h>                     //2





      unsigned char x=1;                      //3

      DDRA  =  0XFF;                            //4

      PORTA = 0x00;                           //5



     while(1)                                        //6    


                     PORTA = x;                  //7

                     x = x<<1;                   //8

                     _delay_ms(200);         //9    (MC running on 1MHZ internal RC oscillator)

                     if( x== 0)                    //10










1) Its the header file avr/io.h where the i/o registers are defined. (DDRx,PORTx,PINx)

2) Header for delay routine, you can write your own way too.

3) 'unsigned char' is a 8 bit data storage. 'uint8_t' is also 8 bit data storage. two questions i always face from beginner, 'why character? why dont u use integer?' ,

Actually char, int are all data storages, character is not a special storage for characters/signs (A,c,@,#). the memory is similar to the storage of integer. In C when u print the storage value stating a "format specifier" of "%c", it will read the value of that location and convert it according to ASCII table. For example


int x = 65;



it will print "A" (Read elementary C books, if u still cant understand)


2nd question i face 'is there any problem to use int/double?'  

no problem to use int / double but u should notice microcontroller has limited memory (flash/ram). so u should keep an eye on it.


We can also use the (R0~R31) 32 registers to store/assign/Calculation of data. 



4) U have to launch registers, what ever u want to do. To set output,  make high of the DDRx of the pin/port. All DDR's have a default value of 0. So they serve as input by default.


5) Assigning to PORTA by something will result : LSB on 'LSB of PORTA (PA0)' ....MSB on PA7.


6) Infinite loop, code will stay forever if not any break criteria set.


7) since x is equal to 1, as defined when declared; assign x to PORTA register results PA0 high and rest pins to low.


8) left shifts of one times to x and assign in it result x = 0b00000010 (x=2, x=0x02).


9) delay about 200 ms, never be accurate (not to eye), because internal RC not so accurate.

10) x not equal to zero for the first time, so if statement will not true this time.


The control bar will go to the top statement number 7, assign the new value of x to PORTA. this time only PA1 will high, rest will low. Number 8 operations will occur then 9, but if statement still will not true. the values of x will like 0b00000100, 0b00001000 ~ 0b10000000.

when x will equal to 0b10000000, Number 8 operations result x=0. Very important thing, if you declare x is integer type data, the result will not x=0, it results x=256. Because Integer data memory is 16bit, In case of unsigned char / uint8_t, when we were pushing left, the only '1' was eliminated when it was in the MSB position of the memory.  







#include <avr/io.h>                      





      DDRA  =  0XFF;                            // Set portA as output.....

      DDRB  =  0x00;                           // Set portB as input.... 

      PORTA = 0x00;                          

     /*  Make high PB2 pin externally, pull down it as switch */ 






                      if(~PINB & (1<<PB2))     // true when PB2 is low

                      PORTA = 0xff;


                      PORTA = 0x00;     








I dont think explanations are necessary, nothing came new,  start over the code section u will get your answers hopefully.





ADC Tutorial


All the signals of world are analog. They don’t give u the logic we said; two states: high & low. So if you want to measure a voltage from an elementary sensor u must use adc. There are many chips like adc0804 available to convert analog value to a digital value. Well u can interface it with microcontroller, where u read the output of adc0804; simply input to your mcu. But Atmega32/16 has 10bit 8 channel adc itself. Which means it can measure analog voltage from 8 pins with a 10 bit resolution.


See datasheet ADC0804

Lets interface Adc0804 with mcu:


#include <avr/io.h>

#define adc_port PINA                    //ADC data pins PORTA

#define rd PB0                           //Read signal PORTB0

#define wr PB1                           //Write signal PORTB1

#define cs PB2                           //Chip Select PORTB2

#define intr PB3                         //INTR signal PORTB3


void conv();                             //Start Conversion

void read();                             //Read ADC value


unsigned char adc_val;


int main()


        DDRB = (1<<rd)|(1<<wr)|(1<<cs);      //RD, WR, CS as output

        DDRD = 0xFF;                         //PORTD as output

        PORTD = 0xFF;


                  {                            //Forever loop

                         conv();                          //Start of conversion

                         read();                          //Read converted ADC

                         PORTD = adc_val;                 //Move it to PORTD


        return 0;




void conv()


        PORTB = PORTB & (~((1<<cs)|(1<<wr))); //Make CS and WR low

        PORTB = PORTB | ((1<<cs)|(1<<wr));    //Make CS and WR high

        while(PINB&(1<<intr));                //Wait for INTR signal



void read()


        PORTB = PORTB & ( ~((1<<cs)|(1<<rd))); //Make RD and CS low

        adc_val = adc_port;                    //Read ADC port

        PORTB = PORTB | ((1<<cs)|(1<<rd));     //Make RD and CS high




; Assembly.....


.include "m32def.inc"


.equ rd = PORTB0           ;Read signal PortB.0

.equ wr = PORTB1           ;Write Signal PortB.1

.equ cs = PORTB2           ;Chip Select PortB.2

.equ intr = PORTB3         ;INTR signal PortB.3

.equ adc_port = PINA       ;ADC data pins PortA

.def adc_val = r16         ;To store ADC value

.def temp = r17            ;Temporary register


.org 0x00


        ldi temp,low(RAMEND)   ;Load stack with

        out SPL,temp           ;RAMEND - highest value

        ldi temp,high(RAMEND)  ;of internal SRAM

        out SPH,temp


        sbi DDRB,rd            ;Make RD as o/p

        sbi DDRB,wr            ;Make WR as o/p

        sbi DDRB,cs            ;Make CS as o/p


        rcall conv             ;Start ADC Conversion

        rcall read             ;Read ADC conversion

        ldi temp,0xFF

        out DDRD,temp          ;Make PORTD as o/p Port

        out PORTD,adc_val      ;Move the read value to PORT D

        rjmp again             ;Do it again


conv:                      ;Start conversion

        cbi PORTB,cs           ;Make CS low

        cbi PORTB,wr           ;Make WR low


        sbi PORTB,wr           ;Make WR high

        sbi PORTB,cs           ;Make CS high


        sbic PINB,intr         ;Wait for INTR signal

        rjmp wait


        ret                    ;Conversion done


read:                      ;Read ADC

        cbi PORTB,cs           ;Make CS low

        cbi PORTB,rd           ;Make RD low


        in adc_val,adc_port    ;Read ADC data


        sbi PORTB,rd           ;Make RD high

        sbi PORTB,cs           ;Make CS high

        ret                    ;Reading done



please see the timing diagram from datasheet ADC0804 and read


The first diagram (FIGURE 10A) shows how to start a conversion. Also you can see which signals are to be asserted and at what time to start a conversion. So looking into the timing diagram FIGURE 10A. We note down the steps or say the order in which signals are to be asserted to start a conversion of ADC. As we have decided to make Chip select pin as low so we need not to bother about the CS signal in the timing diagram. Below steps are for starting an ADC conversion. I am also including CS signal to give you a clear picture. While programming we will not use this signal.


Make chip select (CS) signal low.

Make write (WR) signal low.

Make chip select (CS) high.

Wait for INTR pin to go low (means conversion ends).



Once the conversion in ADC is done, the data is available in the output latch of the ADC. Looking at the FIGURE 10B which shows the timing diagram of how to read the converted value from the output latch of the ADC. Data of the new conversion is only avalable for reading after ADC0804 made INTR pin low or say when the conversion is over. Below are the stepts to read output from the ADC0804.


Make chip select (CS) pin low.

Make read (RD) signal low.

Read the data from port where ADC is connected.

Make read (RD) signal high.

Make chip select (CS) high.




Atmega's ADC


Now its time to use Atmega's ADC.

  • PORTA is the analog input port on the ATmega32.
    • The ATmega32 has a built in A/D converter which is attached to PORTA.
    • PORTA consists of eight pins (called analog input channels).
  • The ADC converts the voltage on an input channel into a digital representation.
  • Input channels on the ATmega32 can handle voltages between 0 and 5 volts.
    • A signal conditioning circuit can be used to convert an analog signal so that it stays in the range of 0 to 5 volts.
  • The resolution of an ADC is the range of input voltage divided by 2n where n is the number of bits in the digital result.
    • For the ATmega32, n = 10 and the voltage range is 5 volts, so the resolution is 5v/1024 = 0.00488 volts.
    • This means that we cannot tell the difference between voltage variations that are less than 0.00488 volts.
  • We can operate the ADC in 8 bit mode where our resolution is now 5v/28 = 19.4 mV.
  • We can calculate the digital value produced by the ADC as follows: (Digital Output)10 = (Analog Input)/resolution.
  • If we know the result of the ADC, we can determine the voltage on the input as follows: (Analog Input) = (Digital Output)10 * resolution.

 As i said early u have to enable everything through control registers to use any features. So to use adc we need to touch two registers (control, 'ADC' itself a 16bit register, split into two  8bit registers called ADCH,ADCL )




Both are 8 bit register. setting values to individual bits have individual meanings. Lets see the registers carefully. 


 Lets see ADMUX:::    


REFS1 and REFS0 – Reference Select bits


  •   Used to select reference voltage for ADC.
  •   We will use REFS1 = 0 and REFS0 = 1 (use AVCC as the reference voltage).
  •   Using REFS1 = 0 and REFS0 = 0 selects AREF as the reference voltage.
  •   This can be useful if you want to get even higher resolution. For example, if AREF is set to 1V, the 10-bit resolution for the ADC is 1/210 = 0.000977 V (5 times better than if AREF were 5V).



 ADLAR – Analog to Digital Left Adjust Register.

  •   If ADLAR = 0 then two most significant bits of ADC result go in the two least significant bits ofADCH and the eight least significant go in ADCL.
  •   If ADLAR = 1 then eight most significant bits of ADC result go in ADCH and the two least significant bits are the two most significant bits of ADCL.
  •   ADLAR = 1 makes it easy to do eight bit conversion because we have the eight most interesting bits stored in one register.
  MUX4 and MUX3 – Gain selection bits
  •   We will set MUX4 = 0 and MUX3 = 0, single ended analog input channel. Single ended means we're just using one channel for ADC.
  •   There are other modes where you can do things like monitor two channels and ADC the difference in voltage between the two channels.
  •  MUX4-0 = 10000 would ADC the difference in voltage between PA1 and PA0.
  •  MUX4-0 = 01001 would ADC 10 times the difference in voltage between PA1 and PA0.
  •  MUX2-0 – When MUX4-3 = 00, used to select the analog input channel (which pin of PORTA).


  We will typically use 01100xxx for ADMUX where the three least significant bits select which pin onPORTA we wish to convert.

See ATmega32 Datasheet pp. 212-214 for details.



Lets the other register ADCSRA:::





  • ADEN – Analog to Digital Enable (active high)
  • ADSC – Analog to Digital Start Conversion (active high)
    • When set, conversion begins.
    • When conversion is complete, the bit gets cleared.
    • We can poll this bit in order to determine when we can look at ADCH and ADCL.
  • ADATE – Analog to Digital Automatic Trigger Enable (active high)
    • Does continual conversions on the selected channel.
    • Operates in conjunction with the Special Function IO Register (SFIOR).
  • ADIF – Analog to Digital Interrupt Flag
    • Set to high when ADC is complete.
      • ADIE – Analog to Digital Interrupt Enable
        • If enabled, an interrupt occurs when ADIF flag goes high.
        • Once the interrupt occurs, the ADIF flag is reset.
      • ADPS2-0 – Analog to Digital Prescaler Select bits
        • We will just set these all high.
        • Used to reduce the clock speed for the ADC (since running at 16MHz is too fast for ADC).
        • ADPS2-0 = 111 selects a division factor of 128.



SFIOR – Special Function IO Register.

For ADC, we only care about ADTS2-0 – Auto Trigger Source.


  • Choosing ADC Mode And Clock


The mega8 ADC offers 2 modes of operation, the Single Conversion Mode and the Free-Running Mode. Both have advantages and disadvantages and I will try to discuss them both well enough now.

In Free-Running Mode, a new conversion is started when a conversion finishes. The new conversion is done for the ADC channel set in ADMUX. If a new channel has to be converted, it's number has to be set *before* the new conversion starts. If an ISR is used to process the ADC results and update ADMUX, care has to be taken, as a change of ADMUX just after the conversion start can have unpredictable results (read pages 196/197 of the mega8 datasheet for more). As we only want to work with one ADC channel, this is no problem for us. Only the very first conversion has to be started by setting the ADSC bit!

In Single Conversion Mode, every conversion has to be started by setting the ADSC (ADC Start Conversion) bit in ADCSR. The advantage of this is that a new channel can be selected before the conversion is started without watching out for timing problems or unpredictable results. If the ADC Conversion Complete ISR is used for this, the loss in speed is quite small.

In this case we can use the Free-Running Mode - we don't need to change ADMUX (just one channel is used).

The recommended ADC clock range is 50 kHz to 200 kHz. If a faster ADC clock is used, the resolution will go down. The ADC clock is prescaled from the main clock by a seperate ADC prescaler. The division factor is selected with the ADPS2..0 bits in ADCSR (see pages 203/204 of the datasheet). At 4 MHz, appropriate values are 32 (resulting ADC clock is 125 kHz) and 64 (resulting ADC clock is 62.5 kHz). We'll use 32.


  • What The ISR Does...(ISR=Interrupt subroutine...we will discuss this later )


The mega8 interrupt vector for the ADC Conversion Complete ISR doesn't have to do much. When it is called, a fresh ADC result is available in ADCL and ADCH. It is converted to 8 bits (the two LSBs aren't used) and written to PortD. 

The ISR is, of course, only called if the ADIE (ADC Interrupt Enble) bit in ADCSRA is set and if global interrupts are enabled. Here we go


#include <avr/io.h>

void ADC_INITI()


        ADMUX   = 0b01100000; // PA0 channel, ref avcc with capacitor @aref pin,ADLAR=1

ADCSRA  = 0b10000000; //ADEN, division factor 2




     uint8_t x,y;




               ADCSRA |= (1<<ADSC); // ask for conversion

                       while(!(ADCSRA & (1<<ADIF))) // wait until the conv. complete

x = ADCL; // read 

y = ADCH; //read




I know u have some silly questions, where is the converted value ? well just go through again, i have already tell it. It is 'y' the variable carrying the 8 msb's of converted value due to ADLAR=1. Is y is the voltage approaching at PA0? Well I have told u a term 'voltage reference'. The value of ADCH and ADCL will saturated when PA0 approaches equal voltage of selected reference voltage. So 

                                           5*(y/255) voltage

if you want to consider full 10 bit, better rest ADLAR zero. Declare higher bit storage for x.

                                            x   = ADCL;

                                            x +=(ADCH<<8);

For the same voltage reference the voltage of PA0 will

                                            5*(x/1023) voltage




Example with ISR..free running mode/auto trigger mode......


#include <avr/io.h>

#include <avr/interrupt.h>



              // Your duty is only to read ADCL & ADCH



void ADC_init()


            ADMUX   = 0b01100000;

            ADCSRA = 0b11101000;

             sei(); // enable global interrupt......will discuss later







                                // you can write different code.when the conversion completed                                             // program will go to ISR. After completed ISR, it will back exactly                                           // where it was. this feature is interrupt... we will learn it next.

                                // you dont need to check 'ADIF' bit .....thats why called auto trigger




So ADC ends here... I dont know what u have learned but i can say millions of work can be solved by ADC.





Interrupt Tutorial(Hardware/External)


Its been a long time, the last tutorial published, sorry for my inconvenience. You need to know only two Register for using hardware interrupt. (MCUCR & GICR : the register names vary in Attiny series, see their respective datasheet)


**not only two registers, some other function we will use that deals with other registers(like function sei(), cli()) 


**(Interrupt basically two types: Hardware/External Interrupt, Software/Timer/counter Interrupt) Here we are dealing with hardware or external interrupt. There are some other interrupts available in microcontroller. We have discussed about ADC's free running mode, where there was an ADC interrupt. Typical list of all Atmega32's interrupt sources: (page44,datasheet)



It is also telling the interrupt priority(tell you later). For the time being, notice that RESET is the highest priority interrupt. It means that if you press reset button to your PC it will restart whatever it was doing...


First of all we should have a clear concept, what is an Interrupt. Interrupt is an feature that all the microprocessors have. I am quoting an example rather that straight forward definition at first.

Suppose you are working alone in your house, suddenly someone knocks your door. what will you do then? Suppose you were reading a book. definitely you will mark the page somehow where you were or remember the page number at your mind. After doing this you will go to open the door, after dealing the necessary thing at the door, you will comeback and start reading the book from the marked page.


External Interrupt is a similar type of occurrence that may come at a random time from outside world. suppose a device want to send data to your microcontroller. If the microcontroller has some other works to do, it is not feasible to check a pin for input from the device continuously. if it does so, how it will do other work if it has others ?


External interrupt has a specific routine (ISR: interrupt subroutine), some specific task that have to be done when the interrupt occurs. look at the program structure



Header file


ISR(Vector name) // Every interrupt has a vector name.


     Task that have to done when interrupt comes



Main Program()



      Initialize necessary variable, declaration

      Initialize Interrupt(which interrupt, type of occurrence)

      Enable Global interrupt




                 Task 1...........

                 Task 2...........

                 Task 3...........

                 Task 4...........

                 Task 5...........







So see the diagram,




Remember the example of book marking, suppose the program is executing Task 3 , suddenly Interrupt came. It will search the interrupt's ISR (according to its vector name), there can be multiple ISR's, So program will recognize the correct subroutine by its vector name. Please see the names by click below....




It will go to the correct routine and execute the statements. it will like function calling. after doing the routine completely, it will back to task3. And it will do same when interrupt occurs again.



So what is ISR? ISR (Interrupt Sub routine) is a kind of function recognisable by a "Vector", which is automatically called by main program when interrupt occurs. Note that main program does not call ISR, if global interrupt is not activated in the program. (a bit of SREG register enables global interrupt.) We did not talk about how MCU takes interrupt(external) yet, so dont be frustrated, we will discuss it later.



So to use interrupt you need to know the following thing


1) How MCU take interrupt from External world?

2) What if in case of multiple interrupts? How many subroutines program have to deal with?


3) What will be the priority in case of multiple interrupts while they occur simultaneously?


Well we have answer the 2nd question partially..Multiple interrupts should have respective ISR's. Program will realize "what to do, which ISR will have to execute for a particular interrupt?", by its vector name. Note that, if interrupt occurs and program does not find desired ISR, it will do nothing. Even it will not show any error at compiling. I am telling it because so often people do enable an interrupt, use different/ wrong vector in the ISR. Program loads MCU properly, but definitely does not work.


Come from the first question: Interrupt taken by particular pin of MCU, in Atmega32, the pins are


 So the pins PB2,PD2,PD3 are dedicated for hardware interrupts. They play as a input to mcu, logic changes that we learned in Input tutorial. Have a look at the registers.


                                                               Register:: GICR



So 1st you have to enable (make 1) the corresponding bit of GICR. like to enable INT0, simply write

                                                      GICR |= (1<<INT0);

Now you have to set, how the MCU realize the INT0? You have to make a circuitry to PD2 pin. also to the program, that is you have to touch MCUCR. See the ISC10,ISC11,ISC01,ISC00.


ISC00, ISCO1 works for Interrupt 0

ISC10, ISC11 works for Interrupt 1

See The Picture below.......



 It is all similar to Interrupt1, Keep in mind that Interrupt 2 is only an edge trigger interrupt. To enable Interrupt 2,   


                                   GICR |= (1<<INT2);


and the edge type can be selected by ISC2 bit, This bit is located in MCUCSR register (NOT MCUCR). If ISC2 is written to zero, a falling edge on INT2 activates the interrupt. If ISC2 is written to one, a rising edge on INT2 activates the interrupt. Edges on INT2 are registered asynchronously. Pulses on INT2 wider than the minimum pulse width given in Table 36 will generate an interrupt. Shorter pulses are not guaranteed to generate an interrupt. When changing the ISC2 bit, an interrupt can occur. Therefore, it is recommended to first disable INT2 by clearing its Interrupt Enable bit in the GICR Register. Then, the ISC2 bit can be changed. Finally, the INT2 Interrupt Flag should be cleared by writing a logical one to its Interrupt Flag bit (INTF2) in the GIFR Register before the interrupt is re-enabled. non-discussed four bits of GICR are related to sleep mode of microcontroller. There is another Register named GIFR. Its contain the flags of the three hardware interrupts. Flag is an indication, that occurs when interrupt occurs, Simultaneously.


#include <avr\io.h>              
#include <avr\interrupt.h>       

void Int_init(void);



void Int_init(void)
      MCUCR |=(1<<ISC11) | (1<<ISC10);   // set RISING edge of INT1  
      MCUCR |=(1<<ISC01) | (1<<ISC00);   // set RISING edge of INT0 
      GICR |= (1<<INT1);                 // enable INT1
      GICR |= (1<<INT0);                 // enable INT0
      DDRD &= ~(1<<PD2);                 // clear INT0 port ( PD2 pin )
      DDRD &= ~(1<<PD3);                 // clear INT0 port ( PD2 pin )

int main (void)
DDRC=0xFF;                       // set port C as output
sei();                           // Enable global Interrupt
        for (;;) {}

So "What is the benefit of flag?"  It is helpful in some case of programming. You may not always need to do some tasks when interrupt occurs. In some case you may want to check the interrupt status. According to scenario you may want to handle tasks in different ways. I will explain it later. For the time being, keep in mind, 'ISR', may not require always if their is an interrupt.


So last thing may be discussed is differences of edge change and logic change interrupts. I am going to briefly explain it, From Table 32,


1st case : The low level of INT0 generates an Interrupt request. It means whether the pin becomes low, there will be interrupt request. if it remains low, interrupts will continuously occurring.


2nd case: Any logical change, just mean it says. Interrupt will occur both in High to low and low to high. But it will not occur if pin remains high or low.



3rd and 4th Case: Those occur when transition found between edges.






volatile int i =0;




     i = 1;







         DDRA = 0xff;

         MCUCR |= (1<<ISC01); // select falling edge

         GICR |= (1<<INT0) ;       // Enable INT0

        sei(); // enable global interrupt  





                                PORTA = 0x00;



                                                   i =0; 

                                                   PORTA = 0xff;

                                                   _delay_ms(1000); //****











**** _delay_ms(1000) will not work properly, maximum possible delay by this function is 262.14 ms see the manual http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html . We will call small routines multiple times. Or we will use Timer later.

Here is the circuit






Our External Interrupts are over. We will start different issue. 





 I am sorry not being updating features these days........... hope to complete those by march 2012





Will coming shortly/ 


coming features (I am writing)

AVR timers/ pwm

USART Serial communications












Recent Videos

4939 views - 13 comments
1372 views - 1 comment
1043 views - 1 comment
1091 views - 1 comment

Recent Blog Entries

No recent entries