DC MOTOR CONTROL By IR-Remote using PWM AtMega8
Note:-click to-AtMega 8 datasheet
Introduction
To control the speed of DC motor where precision and protection are
essence, we use a technique called PWM (pulse width modulation) to
control the speed of DC motor.We can achieve speed control of DC motor using mechanical or electrical
techniques but they require large size hardware to implement but Micro controller based system provides easy way to control the speed of DC motor.We will use ATmega8 controller to produce PWM wave. By varying the width
of this PWM wave, we can control the speed of DC motor. In ATmega8 controller,
timer1 and timer2 have PWM mode.
PWM Based DC Motor Speed Control using Microcontroller Circuit
Principle:
The heart of this project is ATmega8 controller. These controllers
consist of 2 PWM modes. Now we will see how to generate
PWM wave
using timer2 PWM mode.
Before writing the program to the PWM mode we need to know
the register
description of all the registers that are used for PWM mode.
TCCR2 (Timer Counter Control Register):
In Timer 2, we have different modes like CTC mode, normal mode,
phase
correct PWM mode, Fast PWM
mode,etc.Among all of these modes, we have to select FastPWM mode.
From the above figure, it is clear that
For Fast PWM mode,
WGM21=1 WGM20=1
To select PWM mode
TCCR2 |= (1<<WGM21)| (1<<WGM20);
Again in PWM mode we have two modes one INVERTING and
other is NON –
INVERTING.
To select non-inverting mode,
COM21=1 COM20=0
TCCR2 |= (1<<COM21);
To select inverting mode,
COM21=1, COM20=1
TCCR2 |= (1<<COM21)| (1<<COM20);
After that we have to select prescaler value.
CS22
CS21
CS20
Description
0
0
0 No clock
source
0
0
1 clk/1
0
1
0 clk/8
0
1
1 clk/32
1
0
0
clk/64
1
0
1
clk/128
1
1
0
clk/256
1
1
0
clk/1024
To set the prescaler to 8,
CS22=0
CS21=1 CS20=0
TCCR2|= (1<<CS21);
OCR2 (Output Compare Register):
OCR2 register
contains an 8 bit value that is continuously compared with counter value.
PWM Program:
//********************************************************
// *********** PWM DC MOTOR CONTROL with IR *************
//********************************************************
//Controller: ATmega8 (1MHz internal Crystal)
//Compiler: ICCAVR
//Author: bidyut das, Chennai
//Date: FEB 2013
//********************************************************
//this program uses two of the three PWM channels (OC1A & OC1B)
//of the ATmega8, for controlling speed & direction of DC motor
//The remote of Sony TV was used for sending IR codes
#include <iom8v.h>
#include <macros.h>
#include "PWM_main.h"
//*********************************************************************
// Initializing functions for ports, timer0 & timer1
//*********************************************************************
void port_init(void)
{
PORTB = 0x00;
DDRB = 0x06; //PWM pins OC1A & OC1B defined as outputs
PORTC = 0x00;
DDRC = 0x20; //LED for IR detection indication
PORTD = 0x00;
DDRD = 0x01; //LED, for testing purpose
}
//timer0 init
void timer0_init(void)
{
//8-bit timer for measuring delay between IR pulses
TCCR0 = 0x03; //CLK / 64
TCNT0 = 0; //reset the timer
}
//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;
}
/**************************************************************************
* Interrupt Service Routine for INT0
* Executed whenever a remote code is detected
**************************************************************************/
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{
unsigned char count, code, address;
unsigned int IR_input;
TCNT0 = 0;
while(!(PIND & 0x04));
count = TCNT0;
if(count < 30) //to verify start pulse (2.4 ms long)
{
delay_ms(20);
ENABLE_INT0;
return;
}
PORTC |= 0x20;
IR_input = read_IR ();
code = (unsigned char) ((IR_input & 0xff00) >> 8);
address = (unsigned char) (IR_input & 0x00ff);
motorControl ( code, address );
PORTC &= ~0x20;
delay_ms(250);
}
//*********************************************************************
//Function to read IR message from the detector
//Return value contains code in upper byte and address in lower byte
//*********************************************************************
unsigned int read_IR (void)
{
unsigned char pulseCount=0, code = 0, address = 0, timerCount;
unsigned int IR_input;
while(pulseCount < 7)
{
while(PIND & 0x04);
TCNT0 = 0;
while(!(PIND & 0x04));
pulseCount++;
timerCount = TCNT0;
if(timerCount > 14)
code = code | (1 << (pulseCount-1));
else
code = code & ~(1 << (pulseCount-1));
}
pulseCount = 0;
while(pulseCount < 5)
{
while(PIND & 0x04);
TCNT0 = 0;
while(!(PIND & 0x04));
pulseCount++;
timerCount = TCNT0;
if(timerCount > 14)
address = address | (1 << (pulseCount-1));
else
address = address & ~(1 << (pulseCount-1));
}
IR_input = (((unsigned int)code) << 8) | address;
return(IR_input);
}
//****************************************************************************
//Function to control motor speed & direction depending onthe IR code rceived
//Argumets are the code and address values received from IR detector
//****************************************************************************
void motorControl (unsigned char code, unsigned char address)
{
static unsigned char counter, dir, dir1;
if (address != 1) //detect only TV remote, other signals rejected
return;
if((code == 16) || (code == 17)) //Channel+ or Channel- button is pressed
{
if(code == 16) //Channel+
dir = 0;
else //Channel-
dir = 1;
if(dir != dir1) //change direction
{
STOP_MOTOR;
delay_ms(500);
if(dir == 0)
set_FORWARD;
else
set_REVERSE;
START_MOTOR;
dir1 = dir;
}
}
if(code == 18) //Volume- button pressed
{
if(counter >= COUNTER_UPPER_LIMIT) //if speed is already maximum, don't do anything
counter = COUNTER_UPPER_LIMIT;
else
counter += STEP_SIZE; //increase speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
if(code == 19) //Volume+ button pressed
{
if(counter <= COUNTER_LOWER_LIMIT) //if speed is already minimum, don't do anything
counter = COUNTER_LOWER_LIMIT;
else
counter -= STEP_SIZE; //reduce speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
if(code == 9) //'0' button pressed
{
OCR1A = COUNTER_LOWER_LIMIT;
OCR1B = COUNTER_LOWER_LIMIT;
STOP_MOTOR;
}
if(code == 0) //'1' button pressed
{
OCR1A = COUNTER_LOWER_LIMIT;
OCR1B = COUNTER_LOWER_LIMIT;
TCCR1A = 0x81;
START_MOTOR;
}
}
//************************************************************
//*** call this routine to initialize all peripherals
//************************************************************
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer0_init();
timer1_init();
MCUCR = 0x02;
GICR = 0x40;
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 FUNCTION *************
//*******************************************************
void main(void)
{
init_devices();
while(1); //infinite loop, waiting for interrups from IR detector
}
//****************************** END ***************************************
Circuit Diagram:
Model Car