Saturday, August 24, 2013

Speed Control and RPM Measurement of DC Motor Using Microcontroller (Program Code Included) - Engineering Projects



This project aims to measure the RPM and controls the speed of motor. There is a wide range of cheap low-voltage motors available, running at maximum no-load speeds ranging from 3600 RPM to 18,000 RPM or more. Torque may be anything between 3g-cm for the cheaper versions and over 60g-cm for the slightly more expensive motors. Many applications require slower speeds with correspondingly greater torque, and there are several different plastic gearboxes available for the model maker to use. There are also motor-driven devices such as cooling fans and water pumps that can be controlled   by this project. If controlling motors is of no interest to you, perhaps you might like to use the circuit for controlling the brightness of a filament .In this D.C. Motor controller project, it is possible to control the speed of a motor by simply wiring a resistor in series with it. Apart from the inefficiency of such a system, there is the need for a heavy-duty variable resistor (potentiometer).  A typical d.c. motor requires several hundred milliamps to drive it. If the motor is taking say 300mA and the variable resistor is dropping say 3V, the power dissipated  in the resistor is 0•9W. The typical variable potentiometer is rated at only 0•25W, so something much more robust is required costing three or more times as much required. Another factor is that motors do not run well on less than their full rated voltage. They fail to start turning when current is switched on and have a tendency to stall when extra load is applied. The motor speed can be controlled from 30rps to 180 rps. It measures revolutions per minute in rpm mode from 2000 rpm to 15000 rpm. Another factor is that motors do not run well on less than their full rated voltage. They fail to start turning when current is switched on and have a tendency to stall when extra load is applied.
ICs working on +5v are
1.         ATMEGA 16
2.         MOC7811
The motor works on +5v.
Hardware Design
The circuit is designed using ATMEGA family of microcontroller .The required clock is generated internally. The reset will contain the resistance. The speed is controlled using PWM techniques. PWM pulse is the on-off (low or high pulse) given to the motor driver circuit. The MOSFET (IRFZ44) is used for driving the DC Motor. The optical sensor will be used for sensing the speed. The output of the optical sensor will be given to the microcontroller The RPM will be displayed on the 16X2 LCD. Input voltage is varied by potentiometer of 10KΩ. This voltage is applied to pin no.A0 of Microcontroller. By varying the value of potentiometer we are controlling the Speed of DC motor.  Microcontroller used is of atmega family. We have used atmega 16. The input voltage from pot is in analog form but microcontroller needs it to be in digital form. So we give this voltage at port pin A because port A is input to Analog to Digital Converter (ADC). ADC converts this voltage into 10 bit digital data. It is stored in ADC register. From this value we can calculate the ON&OFF period as below
If input data = 100
As it is 10 bit ADC & register inside are only 8 bits, we have to divide ADC output by 4 to get Ton.
Ton = 100%4 = 25
Toff = 255-25 = 230     as register is 8 bit
After calculating Ton & Toff, we are checking the status of pin 4(OCO).
If pin 4 = logic ‘1’ then Ton is loaded in timer register.
If pin 4 = logic ‘0’ then Toff is loaded in timer register.
This will generate the Pulse Width Modulation signal at pin 4(OCO). This PWM signal is given to the MOSFET (IRFZ44). We are using MOSFET to drive the motor. For controlling the speed of motor, motor is connected at the drain terminal of the MOSFET.PWM signal from microcontroller is applied to the MOSFET. Depending on the gate voltage, MOSFET will produce the drain current. This drain current is used to control the speed of the motor. For measurement of speed of DC motor, we are using the optical sensor (MOC 7811). It is selected because it gives +5v when one rotation is complete. This sensor is connected across the motor. The output of sensor is connected to pin 16(INT0) of the microcontroller. For this Clear Timer ON compare Match mode (TCL) is used. We are counting number of pulses in 0.5 second. Using timer & counter the RPM & RPS are calculated as follows
RPS = 2*(0.5 sec)*count
RPM = 2*60*(0.5 sec)*count
RPM & RPS values are displayed on LCD
LCD we have used is 16x2. This LCD has 8-bit parallel interface. It is possible to use all 8 bits plus 3 control signals or 4 bits plus the control signals. It requires +5V to operate. It is connected to port C & D of microcontroller. It acts as an output to microcontroller. It uses ASCII values to display the characters.
ALGORITHM
i.          Initialization.
ii.          Defined functions.
iii.         Initialize Port A as input Port.
iv.        Initialize Port B as output Port.
v.         Scan the analog input coming from the potentiometer.
vi.        Convert this analog input into digital form.
vii.        Calculate ‘ON’ & ‘OFF’ period.
viii.       Load the count depending on status of pin OCo .
1.         If OCo = 1, load Ton as count value.
2.         Else, load Toff as count value.
ix.        Count the pulses on the pin INTo for 0.5 seconds.
x.         Calculate RPS & RPM as follows
1.         RPS=2*0.5*count value.
2.         RPM=2*0.5*60*count value.
xi.        Display RPS & RPM on LCD.
xii.        Repeat the procedure from step 5.

PROGRAM CODE
//ADC
#ifndef INTERNAL_ADC_H
#define INTERNAL_ADC_H
void adc_init(void);
void adc_chan0(void);
#endif
//LCD
fndef lcd_H
#define lcd_H
#define line1 0x80
#define line2 0xC0
#define EN 7
#define RW 6
#define RS 5
#define RW_INIT ()    {PORTD|= (1<<RW); PORTD&=~ (1<<RS); DDRC&=PORTC&=~ (1<<7) ;}
void lcd_config(void);
void lcd_init(void);
void lcd_en_tgl (void);
void lcd_cmd(unsigned char letter);
void lcd_char(unsigned char letter);
void lcd_nibble(unsigned char nib,unsigned char rs);
void lcd_clr_line(unsigned char line);
void lcd_string(unsigned char *senpoint, unsigned char line);
lcd_single_char(unsigned char *senpoint,unsigned char line,unsigned char position);
#endif

//ADC
#ifndef INTERNAL_ADC_C
#define INTERNAL_ADC_C
#include "internal_adc.h"
#include <avr\io.h>
void adc_init(void)
{
     adc_chan0 ();         //Aref,internal turned off,right adjust,channel 0 selected
     ADCSRA=0x86;   //single conversion with conversion disabled ps =64
     return;
}
void adc_chan0(void)
{
     ADMUX&=0x00;    //select adc0 channel (temperature 1)
     ADCSRA=0xC6;
}
#endif
//SPEED CONTROL & SPEED MEASUREMENT
#include <avr\io.h>
#include <util\delay.h>
#include <avr\interrupt.h>
#include "lcd.h"
#include "internal_adc.h"
#define FCPU = 1000000UL
#define JTAG_DISABLE()     {MCUCSR|=0x80;MCUCSR|=0x80;}//JTAG disabled
static unsigned char t_on=0,t_off=0;
static unsigned int pulse_count,pulse_buff;
void calculate(unsigned int data,unsigned char *t_value,unsigned char line);
unsigned int adc_scan(void);
void pwm_init(void);
void intrpt0_init(void);
void timer1_init(void);
ISR (INT0_vect)
{
SREG=0x00;
pulse_count++;
SREG=0x80;
return;
}

ISR (TIMER0_COMP_vect)
{
SREG=0x00;                          //disable global interrupt
if(bit_is_set(PINB,3))
OCR0=t_on;
else
OCR0=t_off;
SREG=0x80;              //enable global interrupt
return;
}

ISR (TIMER1_OVF_vect)      //0.5 second timer1
{
SREG=0x00;
pulse_buff=pulse_count;   //pulse_buff*2 gives rps , pulse_buff*2*60 gives rpm
                                              pulse_count=0;
TCNT1H=0xE1;
TCNT1L=0x7A;
SREG=0x80;
return;
}
void main(void)
{
unsigned char proj_str[2][16] = {"  Motor control  ","SpeedMeasurement"};
unsigned int m_value;
unsigned char data_str[16];
JTAG_DISABLE();
DDRA=0x00;                          //port a as i/p
PORTA=0x00;                        //high impedance
DDRB=0xFF;                          //set port B as o/p
lcd_init();
adc_init();
intrpt0_init();
timer1_init();
pwm_init();
lcd_clr_line(1);
lcd_clr_line(2);
lcd_string(proj_str[0],1);
lcd_string(proj_str[1],2);
_delay_ms(2000);
lcd_clr_line(1);
lcd_clr_line(2);
while(1)
{
adc_chan0();
m_value=adc_scan();
calculate(t_on,data_str,2);      //display rps
lcd_clr_line(2);
lcd_string(data_str,2);
calculate(pulse_buff*120,data_str,1);    //display rpm
lcd_clr_line(1);
lcd_string(data_str,1);
t_on=m_value/4;                     //load t_on and t_off values
t_off=255-t_on;
_delay_ms(1);
}
}
unsigned int adc_scan(void)                          
{
while(!bit_is_set(ADCSRA,4));
ADCSRA|=(1<<ADIF);
return ADC;
}
void calculate(unsigned int data,unsigned char *t_value,unsigned char line)
{
unsigned int temp;
t_value[0]=(data/10000)+0x30;
temp=(data%10000);
t_value[1]=(temp/1000)+0x30;
temp%=1000;
t_value[2]=(temp/100)+0x30;
temp%=100;
t_value[3]=(temp/10)+0x30;
t_value[4]=(temp%10)+0x30;
if(line==1)
{
            t_value[5]='r';
            t_value[6]='p';
            t_value[7]='m';
}
if(line==2)
{
            t_value[5]='r';
            t_value[6]='p';
            t_value[7]='s';
}
t_value[8]=0;
return;
}
void pwm_init(void)
{
TCCR0=0x1B;            //CTC mode, toggle OCO (pin4),prescalar divide by 64
TIMSK|=(1<<1);         //set interrupt for o/p compare
SREG=0x80;              //start global interrupt
TCNT0=0x00;             //counter set to zero
return;
}

void intrpt0_init(void)
{
MCUCR|=0x03;          //interrupt0 falling edge detect
GICR|=0x40;              //interrupt detect enable
SREG=0x80;              //start global interrupt
return;
}
void timer1_init(void)
{
//0.5 second timer
//timer 1 and timer 0 share same pre scalar
//so timer 1 is working with 64 pre scalar
TCNT1H=0xE1;
TCNT1L=0x7A;
TIMSK|=0x04;            //timer0 interrupt enable
TCCR1A|=0x00;
TCCR1B|=0x03;         //pre scalar (counter starts)
SREG=0x80;              //start global interrupt
return;
}
//LCD  Interfacing
#ifndef lcd_C
#define lcd_C
#include <avr\io.h>
#include <stdio.h>
#include <util\delay.h>
#include "lcd.h"
void lcd_config(void)
{
DDRD=0b11100000;
DDRC=0b11110000;     //lower nibble of uC port is connected to higher nibble of lcd
PORTD&=~(1<<RW);
return;
}
void lcd_init(void)
{
lcd_config();
_delay_ms(30);           // wait after power up
lcd_nibble(0x03,0);     / send 03h 3 times to initialize
lcd_en_tgl();
_delay_ms(5);
lcd_en_tgl();
_delay_us(160);
lcd_en_tgl();
_delay_ms(5);
lcd_nibble(0x02,0);     // enable 4 bit mode
_delay_us(160);
lcd_cmd(0x28);           //set 4-bit mode and 2 lines @ 5x7
_delay_us(160);
lcd_cmd(0x10);           //cursor move & shift left
_delay_us(160);
lcd_cmd(0x06);           //entry mode = increment
_delay_us(160);
lcd_cmd(0x0C);          //display on - cursor blink on
_delay_us(160);
lcd_cmd(0x01);                       //clear display ram
_delay_ms(2);
return;
}
void lcd_en_tgl (void)
{
PORTD|=(1<<EN);
PORTD&=~(1<<EN); //Enable pin
return;
}
void lcd_cmd(unsigned char letter)
{
// Command Function
//The RS is set to 0 to signify this is a command
            unsigned char temp;             // temp Variable
temp=letter;                    //move letter to temp
temp=temp>>4;                   //shift temp to right by 4
lcd_nibble(temp,0);             //send out higher nibble
temp=letter;                    //move letter to temp
temp=temp&0x0F;                
lcd_nibble(temp,0);             //send out lower nibble
_delay_us(10);
return;
}
void lcd_char(unsigned char letter)
{
//TData Function
//The RS is set to 1 to signify this is a command
unsigned char temp;             // temp Variable
temp=letter;                    //move letter to temp
temp=temp>>4;                   //shift temp to right by 4
lcd_nibble(temp,1);             //send out higher nibble
temp=letter;                    //move letter to temp
temp=temp&0x0F;                
lcd_nibble(temp,1);             //send out lower nibble
_delay_us(10);
return;
}
void lcd_nibble(unsigned char nib,unsigned char reg_sel)
{
//unsigned char i,x;
if(reg_sel)
PORTD|=(1<<RS);           // Set RS Pin (defined in header file)
else
PORTD&=~(1<<RS);
nib=(nib<<4);
PORTC=nib;
_delay_us(5);
lcd_en_tgl();                   // Toggle E pin (defined in header file)
RW_INIT();
while(bit_is_set(PINC,7));       //busy check
lcd_config();                            //reconfigure lcd i/o pins
return
}
void lcd_clr_line(unsigned char line)
{
// clear line command.
    char tline;                          // The line to clear variable
    char x;                                // loop variable
 if(line==1)                          // Set the variable value based on line
        tline=0x80;                       // 1 = Line 1
    if(line==2)
        tline=0xC0;                     // 2 = Line 2
            lcd_cmd(tline);          // Send command to jump to beggining of line (1/2)
    _delay_us(160)
for(x=0x00;x<0x14;x++)
{                                                   // Loop through all 20 chars of line (even tho 16 are viewabl
        lcd_char(0x20);                  // Send Blank Character
        _delay_us(160);
    }

    lcd_cmd(tline);                      // Go back to beggining of line
    _delay_us(160);
return;
}
void lcd_string(unsigned char *senpoint, unsigned char line)
{
    if(line==1)
        lcd_cmd(line1);
    if(line==2)
        lcd_cmd(line2);
    while(*senpoint != '\0')            // While we havent seen a \0 (esc) go on
            {
                        lcd_char(*senpoint);            // Send 1st char to our char function
                        senpoint++;                     // Send next
            }
return;
}
lcd_single_char(unsigned char *senpoint,unsigned char line,unsigned char position)
{
            unsigned char pos;
            pos=position;
            lcd_cmd(0x03);           //return cursor to home position
            if(line==1)
                        lcd_cmd(line1);
            if(line==2)
                        lcd_cmd(line2);
                        while(pos!=0)      //first position or home position is 0 and last position is 15
                        lcd_cmd(0x14);           //move to right
                        pos--;
                        }
            while(*senpoint!='/0')
            {
            lcd_char(*senpoint);                // send the character to be displayed
            senpoint++;
            }
            return;
}
#endif


4 comments:

  1. it is a nice project to be understood and will you post the simulation circuit diagram for better understanding.

    ReplyDelete
  2. plz upload simulation of this project

    ReplyDelete
  3. pease upload simulation of thi. thanks :)

    ReplyDelete