You are on page 1of 34

Small Dc Motor Control by PWM Method Using MOSFET H-Bridge with Atmega8

Microcontroller
Hi Friends,
Here Im discussing DC motor control using the PWM counters of AVR ATmega8 microcontroller. I had used a DC
motor from an old personal stereo cassette player. The circuit provides speed and direction control of the motor. The
PWM waveforms are used for driving the MOSFET H-bridge as shown in the schematic:

At a time only one of the two PWM channel is active, driving only two MOSFETS (either Q1-Q4 or Q3-Q2). Other two
MOSFETs remain OFF. Whenever the Direction Control switch is toggled, the PWM channel is also changed, driving
the alternative pair of MOSFET, which changes the direction of current flow through motor, resulting in the direction
change in rotation of motor shaft.

Code:
//********************************************************
// *********** PWM DC MOTOR CONTROL *************
//********************************************************
//Controller : ATmega8 (1MHz internal Crystal)
//Compiler
: ICCAVR
//Author
: CC Dharmani, Chennai(India)
//Date
: Nov 2008
//********************************************************
#include <iom8v.h>
#include <macros.h>
#define
#define
#define
#define
#define
#define

increaseButton_PRESSED !(PIND & 0x40)


increaseButton_OPEN
(PIND & 0x40)
decreaseButton_PRESSED !(PIND & 0x80)
decreaseButton_OPEN
(PIND & 0x80)
DIRECTION_FORWARD
!(PIND & 0x20)
DIRECTION_REVERSE
(PIND & 0x20)

#define
#define
#define
#define

STOP_MOTOR
START_MOTOR
set_FORWARD
set_REVERSE

TCCR1B
TCCR1B
TCCR1A
TCCR1A

=
=
=
=

0x00; TCCR1A = 0x00


0x09
0x81
0x21

//defining macros for setting minimum and maximum PWM counter values
//and step-size for controlling the voltage applied to MOSFETs base
#define COUNTER_LOWER_LIMIT 0x0090
#define COUNTER_UPPER_LIMIT 0x00f8
#define STEP_SIZE 0x0008
void port_init(void)
{
PORTB = 0x00;
DDRB = 0x06; //PWM pins OC1A & OC1B defined as outputs
PORTC = 0x00;
DDRC = 0x00;
PORTD = 0xE0; //internal pull-up enabled for three pins connected to switches
DDRD = 0x00;
}
//TIMER1 initialize - prescale:1
//PWM Frequency: 1KHz
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xFC; //setup
TCNT1L = 0x18;
OCR1A = COUNTER_LOWER_LIMIT;
OCR1B = COUNTER_LOWER_LIMIT;
ICR1H = 0x03;
ICR1L = 0xE8;
TCCR1A = 0x81; //set forward; OC1A connected, OC1B disconnected
TCCR1B = 0x09; //start Timer
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer1_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//***** FUNCTION FOR SOFTWARE DELAY OF 1 mSEC (appx.) *******
void delay_ms(int miliSec) //for 1 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<100;j++)
{
asm("nop");
asm("nop");
}
}
//************************ main ***************************

void main(void)
{
unsigned int counter = COUNTER_LOWER_LIMIT;
unsigned char dir = 0, dir1 = 0;
init_devices();
while(1)
{
CHECK_PB:
while(increaseButton_OPEN && decreaseButton_OPEN)
{ //loop here until any push-button is pressed
if(DIRECTION_FORWARD) //check for Direction control switch status
dir = 0;
else
dir = 1;
if(dir != dir1) //chenge direction if switch position has changed
{
STOP_MOTOR;
delay_ms(500);
if(dir == 0)
set_FORWARD;
else
set_REVERSE;
START_MOTOR;
dir1 = dir;
}
}
if(increaseButton_PRESSED) //Speed-increase push-button is pressed
{
delay_ms(20); //key debouncing delay after key-pressed
if(increaseButton_OPEN) goto CHECK_PB;
while(increaseButton_PRESSED); //wait here till the push-button is kept pressed
delay_ms(20); //key debouncing delay after key released
if(counter >= COUNTER_UPPER_LIMIT) //if speed is already maximum, no action
counter = COUNTER_UPPER_LIMIT;
else
counter += STEP_SIZE; //increase speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
else //speed-decrease push-button is pressed
{
delay_ms(20); //key debouncing delay after key-pressed
if(decreaseButton_OPEN) goto CHECK_PB;
while(decreaseButton_PRESSED); //wait here till the push-button is kept pressed
delay_ms(20); //key debouncing delay after key released
if(counter <= COUNTER_LOWER_LIMIT) //if speed is already minimum, no action
counter = COUNTER_LOWER_LIMIT;
else
counter -= STEP_SIZE; //reduce speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
}
}
//****************************** END ***************************************
//********** CC Dharmani, www.dharmanitech.com ****************

ADC Project - with ATmega32


*********************************
Hi friends,
Im presenting here a small project on how to make use of the ADC of ATmega32. The circuit
checks the voltage present at the ADC channel and displays voltage value on the LCD (16x2).
Whenever the push-button is pressed, the LCD displays voltage present on the next ADC
channel (total 8 channels, CH0 to CH7). The schematic and the firmware of the project are
given here.

Code:

Total 6 files: 3 program files (ADC_main.c, LCD_routines.c, ADC_routines.c) and 3 header


files(ADC_main.h, LCD_routines.h, ADC_routines.h)

//*****************************************************************
// **************** ADC_routines.h *********************
//*****************************************************************
#ifndef ADC_ROUTINES_H
#define ADC_ENABLE ADCSRA |= (1<<ADEN)
#define ADC_DISABLE ADCSRA &= 0x7F
#define ADC_START_CONVERSION ADCSRA |= (1<<ADSC)
void ADC_init(void);
int ADC_read(void);
float ADC_calculateTemp(int);
unsigned char* updateTempDisplay(float);
unsigned char* temporary(void);
void ADC_displayValue(void);
#endif

//*****************************************************************
// **************** ADC_routines.c *********************
//*****************************************************************
//Controller: ATmega32 (16 MHz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//*****************************************************************
#include
#include
#include
#include

<iom32v.h>
<macros.h>
"ADC_routines.h"
"LCD_routines.h"

unsigned char valueDisplay[]=": . volt"; //11 char global string for


//voltage value display
float Vref = 5.00; // Reference voltage Vref of ADC
//*****************************************************************
//Purpose : Initialize the ADC
//*****************************************************************
void ADC_init(void)
{
ADCSRA = 0x00; //disable adc
ADMUX = 0x40; //select adc input 0
ADCSRA = 0x86;
}
/********************************************************************
* Purpose : Do a Analog to Digital Conversion
* Paramtr : none
* return : integer voltage value
********************************************************************/
int ADC_read(void)
{
char i;

int ADC_temp, ADCH_temp;


int ADC_var = 0;
ADC_ENABLE;
ADC_START_CONVERSION; //do a dummy readout first
while(!(ADCSRA & 0x10)); // wait for conversion done, ADIF flag active
ADCSRA|=(1<<ADIF);
for(i=0;i<8;i++) // do the ADC conversion 8 times for better accuracy
{
ADC_START_CONVERSION;
while(!(ADCSRA & 0x10)); // wait for conversion done, ADIF flag set
ADCSRA|=(1<<ADIF);
ADC_temp = ADCL; // read out ADCL register
ADCH_temp = ADCH; // read out ADCH register
ADC_temp +=(ADCH_temp << 8);
ADC_var += ADC_temp; // accumulate result (8 samples)
//for later averaging
}
ADC_var = ADC_var >> 3; // average the 8 samples
ADC_DISABLE;
return ADC_var;
}
/**************************************************************************
* Purpose : To calculate temp in degre celsius
* Paramtr : Integer value of voltage, received from ADC read
* Return : float voltage value
***************************************************************************/
float ADC_calculateValue(int inputValue)
{
float actualValue;
actualValue=(inputValue * Vref/1024.0); //calculates the voltage present
return actualValue;
}
/***************************************************************************
* Purpose : To update the tempDisplay string based on the latest temp read
* Paramtr : Float value of voltage
* Return : String pointer pointing to the updated valueDisplay
***************************************************************************/
unsigned char* updateDisplay(float actualValue)
{
int temp;
unsigned char c;
temp=(int)(actualValue*100.0); //to include decimal point for display
if((actualValue*100.0 - temp) >= 0.5) temp=temp+1;
valueDisplay[5] = ((unsigned char)(temp%10)) | 0x30;
temp=temp/10;
valueDisplay[4] = ((unsigned char)(temp%10)) | 0x30;
temp=temp/10;
valueDisplay[2] = ((unsigned char)(temp%10)) | 0x30;
temp=temp/10;
return valueDisplay;
}
/**************************************************************************
* Purpose : To display value of voltage applied to selected ADC channel on

the LCD
* Paramtr : None
* Return : None
***************************************************************************/
void ADC_displayValue(void)
{
int value;
float value1;
value = ADC_read();
value1 = ADC_calculateValue(value);
LCD_DisplayString(2,4,updateDisplay(value1)); //voltage display on 2nd row,
//4th column
}
//*****************************************************************
// **************** LCD_routines.c *********************
//*****************************************************************
#ifndef LCD_ROUTINES_H
// *** LCD Functions declaration *** //
void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void
void
void
void

LCD_DisplayString_F(char row, char column, const unsigned char *string);


LCD_DisplayString(char row, char column, unsigned char *string);
LCD_Cursor(char row, char column);
delay_ms(int miliSec);

#define ENABLE_LCD PORTD |= 0x80


#define DISABLE_LCD PORTD &= ~0x80
#define SET_LCD_DATA PORTD |= 0x20
#define SET_LCD_CMD PORTD &= ~0x20
#endif

//********************************************************
// ************** LCD_routines.c ******************
//********************************************************
//Controller: ATmega32 (16 MHz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//********************************************************
#include <iom32v.h>
#include <macros.h>
#include "LCD_routines.h"
// *********************************
// *** Initialize the LCD driver ***
// *********************************
void LCD_init(void)
{
delay_ms(100); // wait for 100ms
LCD_WriteCommand
LCD_WriteCommand
LCD_WriteCommand
LCD_WriteCommand

(0x38);
(0x06);
(0x0f);
(0x01);

//
//
//
//

8 data lines
cursor setting
display ON
clear LCD memory

delay_ms (10); // 10ms delay after clearing LCD


}
// **********************************************
// *** Write a command instruction to the LCD ***
// **********************************************
void LCD_WriteCommand (unsigned char Command)
{
SET_LCD_CMD; // Set LCD in command mode
PORTC = Command; // Load data to port
ENABLE_LCD; // Write data to LCD
asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}
// *****************************************
// *** Write one byte of data to the LCD ***
// *****************************************
void LCD_WriteData (unsigned char Data)
{
SET_LCD_DATA; // Set LCD in data mode
PORTC = Data; // Load data to port
ENABLE_LCD; // Write data to LCD
asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}
// *********************************************************************
// *** Display a string at the specified row and column, from FLASH ****
// *********************************************************************
void LCD_DisplayString_F ( char row, char column , const unsigned char *string)
{
LCD_Cursor (row, column);
while (*string)
LCD_WriteData(*string++);
}
// *********************************************************************
// *** Display a string at the specified row and column, from RAM ****
// *********************************************************************
void LCD_DisplayString (char row, char column , unsigned char *string)
{
LCD_Cursor (row, column);
while (*string)
LCD_WriteData(*string++);
}
// ***************************************************
// *** Position the LCD cursor at "row", "column". ***
// ***************************************************
void LCD_Cursor (char row, char column)
{
switch (row)
{
case 1: LCD_WriteCommand (0x80 + column - 1); break;
case 2: LCD_WriteCommand (0xc0 + column - 1); break;

default: break;
}
}
// ********************************************************
// **** Function for delay of 1 msec (appx.) at 16Mhz *****
// ********************************************************
void delay_ms(int miliSec) //for 16 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)
{
asm("nop");
asm("nop");
}
}
//********************************************************************
// ADC_main.h
//********************************************************************

#ifndef ADC_MAIN_H
#define KEY_PRESSED !(PINB & 0x02)
#define KEY_OPEN (PINB & 0x02)
void port_init(void);
void init_devices(void);
#endif

//********************************************************************
// ****** MAIN PROGRAM FOR TESTING ADC OF MEGA32 ADC_main.c******
//********************************************************************
//Controller: ATmega32 (Crystal: 16Mhz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//********************************************************************
#include
#include
#include
#include
#include

<iom32v.h>
<macros.h>
"ADC_main.h"
"LCD_routines.h"
"ADC_routines.h"

//port initialize
void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x00;
PORTB = 0x02; //internal pull-up for push-button
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0xF0;
PORTD = 0x00;
}
//call this routine to initialize all peripherals
void init_devices(void)

{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
ADC_init();
LCD_init();
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
// SEI(); //re-enable interrupts
}
// MAIN FUNCTION
void main(void)
{
unsigned char channel = 0;
init_devices();
LCD_DisplayString_F(1,1,"ADC Testing.. ");
while(1)
{
LCD_DisplayString_F(2,1,"CH");
LCD_WriteData(channel | 0x30); //display channel number
START:
while(KEY_OPEN) //wait here till key is open
{
ADMUX &= 0xe0;
ADMUX |= channel; //select ADC channel
ADC_displayValue();
delay_ms(50);
}
delay_ms(20); //key debounce delay when key is pressed
if(KEY_OPEN)
goto START;
while(KEY_PRESSED); //wait here till key is pressed
delay_ms(20); //key debounce delay when key is released
channel++; //select next channel after key-press
if(channel == 8) //only channel-0 to channel-7 can be selected
channel = 0;
}
}

//*********************** END **************************

Ring Detector for Caller ID Unit


Hi Friends,
this is an addition to the caller ID circuit of my previous post. For deciding whether call is received call or missed call, u need to
monitor the ringing signal along with the off-hook detector signal, which is discussed in the last post. If the off-hook detector
signal goes low (i.e. receiver lifted) before the ringing signal stops, then the call is labeled as received call, otherwise it is a missed
call.
This small circuit converts the ringing signal (sine wave 90vrms) into 5v dc pulses which can be directly fed to microcontroller pin.
The circuit outputs a pulse for each ring. The delay between two pulses is to be monitered and if it exceeds 4 sec, then ring is

dead, hence, the call is missed call.!


Try it out..

Make-Yourself ATmega32 Starter's Kit with LCD, I2C, SPI, RTC, ADC interfaces
Hi friends,
here is my home-made kit of ATmega32 microcontroller interfacing. The ATmega32 controller is rich with
features like onboard 32kB in-System programmable flash, 1 KB EEPROM, 2KB SRAM, 10bit ADC (8 channel),
SPI bus inteface, TWI (compatible with I2C bus) interface, an USART, analog comparator, etc.
That's why I've selected it to load my kit with all those features. This M32 card is having an LCD inteface with
contrast adjustment, an RS232 port for connecting with PC, a connector for 8 analog voltage inputs to measure
by ADC, a Real Time Clock IC DS1307 from maxim with battery back-up, four general purpose keys, two keys
for generating interrupts and an LED.
The circuit can be powered by an easily available 12v DC adapter. The voltage regulator IC 7805 used to convert
the input into regulated 5v supply.
See below the kit in powered on condition and the schematic.

The PCB is completely home-made, using the etching technique with the Ferric Chloride chemical. If you want to
know how to make a PCB yourself from your layout, visit following webpage, it's really helpful:
http://electrons.psychogenic.com/modules/arms/art/10/pcb_howto.php
The schematic and layout of the M32_card shown here are prepared using EAGLE. It's a single layer board for
making the home-preparation easy. Check out the bottom layer and the layouts in the pics below:

The software for the ATmega32 controller is written using imageCraft AVR compiler. The software contains code
for LCD interface, use of RTC and communication with PC with RS232 port. Using the Hyper terminal in
windows, the functionality of the kit can be checked, as I've mentioned in my previous post of RTC_EEPROM
interface with ATmega128.
Sown below are the pics of RTC circuit in test and related screen shot of the hyper terminal while interacting with
the M32_Card

The complete source code files including new addition of ADC (check out Here) can be downloaded in zip format
from AVRfreaks forum where I've posted them.
to me if you have any problem in downloading these files)
You can download the datasheets here:
ATmega32 DS1307 MAX232
If any one is interested in making this kit at home, write to me. I'll send u the shcematic and layout files with the
program.
Do write your comments, guys!!!
--------

Design Caller ID using DTMF decoder MT8870


Hi friends,
one more circuit: DTMF decoder interface for designing Caller ID Unit. It's very simple circuit using DTMF decoder
MT8870 (or CM8870). As shown in the circuit, u'll receive an interrupt ( if NAND output is connected to INT of the
microcontroller) whenever u receive a call or make a call and then u can use yr program to read the digits coming out of
pin 11 to 14 of the MT8870. I designed the circuit with additional features like seperating received calls, missed calls,
dialled numbers along with telephone directory.
To determine whether number is dialled or received, u need to know whether receiver is on-hook or off-hook. following
simple circuit will give u that indication:
I had used microcontroller 8951 with16x2 LCD and Dallas nvRAM for storing numbers and names. The code is in
assembly language. It's really easy to make this one with lot of variations.

UART FUNCTIONS
***********************************
Hi friends,
This document provides functions for using UART on AVR controllers for communication with PC RS232 port. Ive
tested these functions using ATmega32, with little changes it can be adapted to other atmega devices as well.

Code:
//****************************************************************
//**** UART ROUTINES *******************
//****************************************************************
//Controller: ATmega32 (16MHz Crystal)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//****************************************************************

//***************************************************
//Function to initialize UART
//***************************************************
//UART0 initialize
// desired baud rate: 19200
// actual: baud rate:19231 (0.2%)(at 16MHz crystal)
// char size: 8 bit
// parity: Disabled

void uart0_init(void)
{
UCSRB = 0x00; //disable while setting baud rate
UCSRA = 0x00;
UCSRC = BIT(URSEL) | 0x06;
UBRRL = 0x33; //set baud rate lo
UBRRH = 0x00; //set baud rate hi
UCSRB = 0x98;
}

//**************************************************
//Function to receive a single byte
//*************************************************
unsigned char receiveByte( void )
{
unsigned char data, status;
while(!(UCSRA & (1<<RXC))); // Wait for incomming data
status = UCSRA;
data = UDR;

return(data);
}

//***************************************************
//Function to transmit a single byte
//***************************************************
void transmitByte( unsigned char data )
{
while ( !(UCSRA & (1<<UDRE)) ); //Wait for empty transmit buffer

UDR = data; //Start transmition


}

//***************************************************
//Function to transmit a string stored in Flash
//***************************************************

void transmitString_F(const unsigned char* string)


{
while (*string)
transmitByte(*string++);
}

//***************************************************
//Function to transmit a string from RAM
//***************************************************
void transmitString(unsigned char* string)
{
while (*string)
transmitByte(*string++);

LCD interfacing with ATmega32


*********************************************
This document discusses interfacing of an 16x2 intelligent LCD with ATmega32. The schematic is shown here:

Code:
The code is given here. Please note that if you have bought a new ATmega32 IC then you have to disable the JTAG
interface which is multiplexed with the PORTC pins. JTAG can be disabled by changing the fuse values while
programming, refer to datasheet for further details. If JTAG is not disabled, the LCD will remain blank. Alternatively,
you can connect LCD with PORTA, and change the code accordingly to replace PORTC with PORTA.
After loading the code into microcontroller, the LCD will display a message Hi, welcome! Have a nice Day. When the
key is pressed the message will change to Atmega32 Board Starters kit. The messages will toggle between this two
whenever the pushbutton is pressed.

//********************************************************

//*********** PROGRAM FOR LCD INTERFACING *************


//********************************************************
//Controller: ATmega32 (Crystal: 16 Mhz)
//Compiler: ImageCraft ICCAVR
//Author: CC Dharmani, Chennai
//********************************************************

// ************* LCD.h : Header file *************

void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void LCD_DisplayString_F(char row, char column, const unsigned char *string);
void LCD_Cursor(char row, char column);
void delay_ms(int miliSec);

#define ENABLE_LCD PORTD |= 0x80


#define DISABLE_LCD PORTD &= ~0x80

#define SET_LCD_DATA PORTD |= 0x20


#define SET_LCD_CMD PORTD &= ~0x20

#define pushButton1_PRESSED !(PINB & 0x02)


#define pushButton1_OPEN (PINB & 0x02)

//******************* lcd.c ****************************

#include <iom32v.h>
#include <macros.h>
#include "LCD.h"

void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x00;
PORTB = 0x00;
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0xF0;
PORTD = 0x00;
}

//call this routine to initialize all peripherals


void init_devices(void)
{
CLI(); //disable all interrupts
port_init();
LCD_init();

MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}

//******************* MAIN FUNCTION *******************


void main(void)
{
unsigned char PB_Status=0xff,Change_Display=0, Change_Display1=1;

init_devices();

while(1)
{
if(Change_Display != Change_Display1)
{
if(Change_Display==0)
{
LCD_DisplayString_F(1,1," Hi, Welcome! ");
LCD_DisplayString_F(2,1,"Have a nice Day");
}
else
{
LCD_DisplayString_F(1,1," ATmega32 Board ");
LCD_DisplayString_F(2,1," Starter's Kit ");
}
Change_Display1 = Change_Display;
}
CHECK_PB:
while(pushButton1_OPEN);// wait here until push
button1 is //pressed
delay_ms(20); // 20ms delay for key debouncing
// after key-pressed

if(pushButton1_OPEN) goto CHECK_PB;


while(pushButton1_PRESSED); //wait here till the
//pushbutton1 is kept pressed
delay_ms(50); // 50ms delay for key debouncing after
// key released
Change_Display = ~Change_Display;

}
}

//*********************************************************
//*********************** LCD Functions ***************
//*********************************************************

// *********************************
// *** Initialize the LCD driver ***
// *********************************
void LCD_init(void)
{
delay_ms(100); // wait for 100ms
LCD_WriteCommand (0x38); // 8 data lines
LCD_WriteCommand (0x06); // cursor setting
LCD_WriteCommand (0x0f); // display ON
LCD_WriteCommand (0x01); // clear LCD memory
delay_ms (10); // 10ms delay after clearing LCD
}

// **********************************************
// *** Write a command instruction to the LCD ***
// **********************************************
void LCD_WriteCommand (unsigned char Command)
{

SET_LCD_CMD; // Set LCD in command mode

PORTC = Command; // Load data to port

ENABLE_LCD; // Write data to LCD

asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}

// *****************************************
// *** Write one byte of data to the LCD ***
// *****************************************
void LCD_WriteData (unsigned char Data)
{
SET_LCD_DATA; // Set LCD in data mode

PORTC = Data; // Load data to port

ENABLE_LCD; // Write data to LCD

asm("nop");
asm("nop");

DISABLE_LCD; // Disable LCD


delay_ms(1); // wait for 1ms
}

// ************************************************************

// Display a string at the specified row and column, from FLASH


//*************************************************************
void LCD_DisplayString_F (char row, char column ,const unsigned char *string)
{
LCD_Cursor (row, column);
while (*string)
LCD_WriteData(*string++);
}

// ***************************************************
// *** Position the LCD cursor at "row", "column". ***
// ***************************************************
void LCD_Cursor (char row, char column)
{
switch (row)

{
case 1: LCD_WriteCommand (0x80 + column - 1); break;
case 2: LCD_WriteCommand (0xc0 + column - 1); break;
default: break;
}
}

// ********************************************************
// **** Function for delay of 1 msec (appx.) at 16Mhz *****
// ********************************************************
void delay_ms(int miliSec) //for 16 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)
{
asm("nop");
asm("nop");
}
}

4x4 Matrix Key-board Interfacing with ATmega32


This is a beginners project for interfacing 4x4 key-board with ATmega32. The LCD displays the value of the key which
ever has been pressed (0 to 9, A,B,C,D,E & F).

Schematic:

Code:
//*****************************************************************
// ******** 4X4 MATRIX KEY-BOARD INTERFACING *******
//*****************************************************************
//Controller: ATmega32 (Crystal: 16 Mhz)
//Compiler: ImageCraft ICCAVR
//Author: CC Dharmani, Chennai (India)
//Date: Aug 2008
//********************************************************
#include <iom32v.h>
#include <macros.h>
// *** LCD Functions declaration *** //
void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void LCD_DisplayString_F(char row, char column, const unsigned char *string);
void LCD_Cursor(char row, char column);
void delay_ms(int miliSec);
#define
#define
#define
#define
#define
#define

ENABLE_LCD PORTD |= 0x80


DISABLE_LCD PORTD &= ~0x80
SET_LCD_DATA PORTD |= 0x20
SET_LCD_CMD PORTD &= ~0x20
KB_PORT_OUT PORTB
KB_PORT_IN PINB

void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x0f; //Key-board port, higer nibble - input, lower nibble - output
PORTB = 0xff; //pull-up enabled for higher nibble
DDRC = 0xff;
PORTC = 0x00;
DDRD = 0xf0;
PORTD = 0x00;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
LCD_init();
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
//****************** MAIN FUNCTION *******************
void main(void)
{
unsigned char upperNibble, keyCode, keyPressed, i;
init_devices();
LCD_DisplayString_F(1,1," WELCOME ");
LCD_WriteCommand(0xc0); //moving LCD cursor to second row
while(1)
{
upperNibble = 0xff;
for(i=0; i<4; i++)
{
delay_ms(1);
KB_PORT_OUT = ~(0x01 << i);
delay_ms(1); //delay for port o/p settling
upperNibble = KB_PORT_IN | 0x0f;
if (upperNibble != 0xff)
{
delay_ms(20); //key debouncing delay
upperNibble = KB_PORT_IN | 0x0f;
if(upperNibble == 0xff) goto OUT;
keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << i));
while (upperNibble != 0xff)
upperNibble = KB_PORT_IN | 0x0f;
delay_ms(20); //key debouncing delay
switch (keyCode) //generating key characetr to display on LCD
{
case (0xee): keyPressed = '0';
break;
case (0xed): keyPressed = '1';
break;
case (0xeb): keyPressed = '2';

break;
case (0xe7): keyPressed = '3';
break;
case (0xde): keyPressed = '4';
break;
case (0xdd): keyPressed = '5';
break;
case (0xdb): keyPressed = '6';
break;
case (0xd7): keyPressed = '7';
break;
case (0xbe): keyPressed = '8';
break;
case (0xbd): keyPressed = '9';
break;
case (0xbb): keyPressed = 'A';
break;
case (0xb7): keyPressed = 'B';
break;
case (0x7e): keyPressed = 'C';
break;
case (0x7d): keyPressed = 'D';
break;
case (0x7b): keyPressed = 'E';
break;
case (0x77): keyPressed = 'F';
break;
default : keyPressed = 'X';
}//end of switch
LCD_WriteData(keyPressed);
OUT:;
}//end
}//end
}//end
}//end

of
of
of
of

if
for
while(1)
main()

//*********************** LCD Functions *****************************


// *********************************
// *** Initialize the LCD driver ***
// *********************************
void LCD_init(void)
{
delay_ms(100); // wait for 100ms
LCD_WriteCommand
LCD_WriteCommand
LCD_WriteCommand
delay_ms (10);
LCD_WriteCommand
LCD_WriteCommand
}

(0x38); // 8 data lines


(0x08); // display off
(0x01); // clear LCD memory
// 10ms delay after clearing LCD
(0x06); // cursor setting
(0x0f); // display ON

// **********************************************
// *** Write a command instruction to the LCD ***
// **********************************************
void LCD_WriteCommand (unsigned char Command)
{
SET_LCD_CMD; // Set LCD in command mode
PORTC = Command; // Load data to port

ENABLE_LCD; // Write data to LCD


asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}
// *****************************************
// *** Write one byte of data to the LCD ***
// *****************************************
void LCD_WriteData (unsigned char Data)
{
SET_LCD_DATA; // Set LCD in data mode
PORTC = Data; // Load data to port
ENABLE_LCD; // Write data to LCD
asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}
// *********************************************************************
// *** Display a string at the specified row and column, from FLASH ****
// *********************************************************************
void LCD_DisplayString_F (char row, char column ,const unsigned char *string)
{
LCD_Cursor (row, column);
while (*string)
LCD_WriteData(*string++);
}
// ***************************************************
// *** Position the LCD cursor at "row", "column". ***
// ***************************************************
void LCD_Cursor (char row, char column)
{
switch (row)
{
case 1: LCD_WriteCommand (0x80 + column - 1); break;
case 2: LCD_WriteCommand (0xc0 + column - 1); break;
default: break;
}
}
// ********************************************************
// **** Function for delay of 1 msec (appx.) at 16Mhz *****
// ********************************************************
void delay_ms(int miliSec) //for 16 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)
{
asm("nop");

asm("nop");
}
}

// ******** END OF SOURCE CODE FILE MATRIX_KB.C *********

BLINKING LED
***************************************
Hi friends, this is a beginners project of blinking an LED connected to AVR microcontroller ATmega32, as shown in
the schematic

Code:
Following code will make the Led blink every second (appx.) at 16MHz crystal. If you have bought new controller then
It will be set at internal 1MHz osc. (by default). So,if you dont change the fuse values to enable external crystal, the
LED will blink 16 times slower!!
//***************************************************
//************ BLINKING LED ***********************
//***************************************************
// Target : ATmega32
// Crystal: 16.000Mhz
// Compiler: ICCAVR
// Author: CC Dharmani, Chennai, India
//***************************************************

#include <iom32v.h>
#include <macros.h>

//----------------------------------------------void port_init(void)
{
PORTD = 0x00;
DDRD = 0x10;
}

//-----------------------------------------------void delay_ms(int miliSec) //1 ms delay (appx)for 16MHz crystal


{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)

{
asm("nop");
asm("nop");
}
}

//-----------------------------------------------//call this routine to initialize all peripherals


void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();

MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
//SEI(); //re-enable interrupts
//all peripherals are now initialized
}

//--------------- MAIN FUNCTION ------------void main()


{
init_devices();
while(1)
{
PORTD |= 0x10;

delay_ms(500);
PORTD &= ~0x10;
delay_ms(500);
}
}
//********************* END ***********************
Here is the same code written for AVR-GCC (winAVR) compiler:
//******* LED BLINKING PROGRAM *********
//Controller: ATmega32 (1Mhz or 16Mhz)
//Compiler: AVR-GCC (winAVR)
//Author: CC Dharmani, Chennai (INDIA)
//*************************************
//#define F_CPU 1000000UL
//use this if internal oscillator is used
#define F_CPU 16000000UL //use this when ext 16MHz crystal is used
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void port_init(void)
{
PORTD = 0x00;
DDRD = 0x10;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
cli(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
// sei(); //re-enable interrupts
//all peripherals are now initialized
}
int main()
{
init_devices();
while(1)
{
PORTD = 0x10;

_delay_ms(500);
PORTD = 0;
_delay_ms(500);
}
return(0);
}
//---------- END -------------

You might also like