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 */
}
}
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