Wednesday, June 27, 2012

AVR Tutorial - 3 Beginning AVR microcontroller Programming


1.                  Beginning AVR µC Programming

AVR is a RISC µC ie. Reduced Instruction Set Computing. So the number of instruction in the assembly for the µC will be much lesser as compared to CISC µCs. So it will take only lesser decoding time for instructions and will be comparatively faster for Embedded Systems.

1.        In this tutorial we will be using ATMEGA 32 and WinAVR Programming environment with avrdude as programming tool. We will be using USBasp as the AVR Programmer.
2.        If you are using any other AVR µC then just refer to the manual and see if there are some differences.
3.        ATMEGA 32 has got 32 kB flash memory for storing the program. It has got four  x  eight bit ports which they do label as PA, PB, PC, PD


·         Before going to the first example, let us get familiarized with the three types of basic port operating registers for AVR:
i.                    DDRx (x = A / B / C / D ): It is called Data Direction Register. It is used to set whether a particular bit in a port is being used for input or output. If we give a high value for a bit then that bit will be used for out putting something in the later programs.
Eg:                   DDRA = 0b00001111;
Here the first four bits (ie. bit 0 to bit 3) of port A is being used for outputting something and the last four(bit 4 to bit7) is being used for inputting something.
We could also write similarly in hexadecimal as:
                        DDRB = 0xf6;
ii.                   PORTx (x = A / B / C / D ): It is the Register which we use to output something into a port. As an example if we have set DDRA to have the bit 0 as output and if we want to set that to high we write as:
PORTB = 0x01;

iii.        PINx (x = A / B / C / D ): It is used to read value from a register. as an example if we want to check the input in the most significant four bits of port C, we do write the program with the use of bitwise operator as follows:
                        if( (PINC & 0b11110000) = = 0b101010000 )
{
                        -- do something --
                        }

The above usage of bitwise operator to mask the four lower bits which we are not concerned about is called bit masking. If we AND a bit with 0, it will become 0 and if we OR a bit with 1, it will become one. In the later on programming examples we will encounter the usage of bitwise operators a lot many times.

Example 1: Lighting an LED with µC

Circiut:

Program:
#include <avr/io.h>

void main()
{
  DDRB = 0b00000001;//Setting Bit 0 for Out put
  while(1)
  {
        PORTB = 0b00000001;//Setting Port B0 to High
  }
}

-          In the circuit given above, we have used a 8 MHz external crystal to clock the µC. There is an internal clock in a µC but its frequency is low limited (about 1MHz) and it is not precise. So we add an external crystal to the µC to make it run faster.
-          The output coming from the µC is 5V and the LED needs just a 2 to 3 V voltage. So we use a 330Ohm resistor to reduce the voltage.
-          Using the command PORT PORTB = 0b00000001; we do assign a high voltage to the 0th bit of PORTB and so the LED keeps on lighting.
-          Here you can see  unlike the usual C-Program which goes sequentially and terminated after certain number of steps, the programs for a µC are generally written inside an infinite while loop so that it gets executed infinitely.
-          Now we will change the code slightly with the same hardware to make the LED blink.

Program:
#include <avr/io.h>
#include <util/delay.h>

void main()
{
     DDRB = 0b00000001;
     while(1)
     {
                             PORTB = 0b00000001;
                             _delay_ms(100);
                             PORTB = 0b00000000;
                             _delay_ms(100);
    
     }
}

·         Here we are using a  _delay_ms( ) function which makes the µC do nothing for some milliseconds. So for using that function, we do include the header file delay.h
·         When we program this, we could see the LED blinking.


Now we will try to add an external switch to our circuit and do something…


Example 2: Adding a switch into µC
·         In the above circuit, we have connected a switch to the PINB1. If the switch is not being pressed, then a high voltage will be dropped across the resistor and the PINB1 will be having a logical high voltage.
·         If we press the switch then a logical 0 voltage will come to the PIN1 and we have added a capacitor across the switch to avoid de-bouncing.




Program:
#include <avr/io.h>
#include <util/delay.h>


void main()
{
           DDRB = 0b00000001; //Here we are setting PB0 for output
          
           while(1)
           {
                 if( (PINB & 0b00000010) == 0b00000000) //Checking whether switch is pressed
                       {
                                   PORTB = 0b00000001;
                                   _delay_ms(20);
                                   PORTB = 0b00000000;
                                   _delay_ms(20);
                       }
                       else
                       {
                                   PORTB = 0b00000001;
                                   _delay_ms(100);
                                   PORTB = 0b00000000;
                                   _delay_ms(100);
                       }
           }
}

We could make a slight modification in the program and we ccan give an internal pull up to avoid the external 10K pull up resistor.

#include <avr/io.h>
#include <util/delay.h>


void main()
{
           DDRB = 0b00000001; // setting PB0 for output
           PORTB = 0b00000010; //Setting the PINB1 with a high voltage
          
           while(1)
           {
                       PORTB |= 0b00000010;
                 if( (PINB & 0b00000010) == 0b00000000) //Checking whether switch is pressed
                       {
                                   PORTB = 0b00000001;
                                   _delay_ms(20);
                                   PORTB = 0b00000000;
                                   _delay_ms(20);
                       }
                       else
                       {
                                   PORTB = 0b00000001;
                                   _delay_ms(100);
                                   PORTB = 0b00000000;
                                   _delay_ms(100);
                      
                       }
          
           }


}

·         In the above program if we press the switch, then the LED will blink faster.





Interfacing LCD:
For interfacing LCD we will be using the header file lcd.h from http://www.jump.to/fleury and we will be calling the functions defined in that header file.

LCD Connection:

Vee is the Pin in the LCD used to set the contrast of the LCD. So use a resistance nearly 1 K with that to connect to Vcc.





·         Make sure to set your Clock speed properly in the lcd.h header file.

Sample Program:
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#include "lcd.c"
void main( )
{
lcd_init(LCD_DISP_ON_CURSOR); 
    while(1)                      
    {
        lcd_clrscr();             /* clear screen of lcd */
        lcd_home();               /* brings cursor to starting position */
        lcd_puts("Hello");        /*Prints on the first line */
        lcd_gotoxy(0,1);        
        lcd_puts("World");  /* Prints on the second line */
        _delay_ms(50);            /* wait 50ms */
    }
}



Integers and floating pont numbers are first converted to a string of characters and then they are printed using the usual lcd functions
Printing Integers
char temp[15];
int x = 246;
itoa(x, temp, 15);
lcd_puts(temp);

Printing Floating Point Numbers:
char temp[15];
float y = 56.7891;
sprintf(buffer, "%f", y);
lcd_puts(temp);

No comments:

Post a Comment