Friday, January 30, 2015

DC Motor Speed and Direction Controller

Working with DC motor is quite simple and helpful in our life, we can find this type of motors wherever you go. Here we are going to show how to control DC Motor speed and direction using Microchip PIC16F877A microcontroller.
Related Topics:
Arduino DC Motor Control 1 
H-Bridge Circuit 
PIC Microcontroller Timer1 Module

DC Motor speed and direction controller using PIC16F877A circuit:
The PIC16F877A is equipped with CCP module which generates PWM signal. The pwm helps us to control the speed of our dc motor.
We have to know that dc motors can't connected directly to the microcontroller, we have to connect our motor to a bridge circuit and this bridge is connected to the mcu. The bridge circuit used in this project is basically constructed of 4 mosfets 2 N-type and 2 P-type. This bridge allows us to control the direction of the dc motor.
The H-Bridge circuit schematic is shown below:
h bridge dc motor
As we see on the H-bridge picture there are 3 inputs: IN1, IN2, and PWM. IN1 and IN2 for controlling the direction of the motor as below:
IN1 = 1; IN2 = 0 : motor is off,
IN1 = 1; IN2 = 0 : CW direction,
IN1 = 0; IN2 = 1 : CCW direction,
IN1 = 1; IN2 = 1 : not allowed,
Note that IN1 and IN2 must not be ones at the same time which may make short circuit.
PWM for controlling the speed of the motor by varying the pwm signal duty cycle.
The complete circuit of this project is shown on the following picture:
dc motor speed control direction control pic16f877a circuit mikroc

In the circuit there are 3 push buttons, one for stop, cw direction, and ccw direction connected to RB0, RB1, and RB2 respectively. Also there is a potentiometer connected to AN0 in order to read the analog value and generate its corresponding pwm.
The H-Bridge square contains the bridge shown before and it uses 12V power supply.
The tow LEDs for indicating the direction of the motor.
DC Motor speed and direction controller using PIC16F877A mikroC Code:
The compiler used is MikroC for PIC and the code is as below.
The rule of using timer1 interrupt is to read the analog value every 100ms.

//DC Motor Speed and Direction Controller
//Used microcontroller: PIC16F877A @ 12MHz
//Written by: BENCHEROUDA Okba
//http://www.elecnote.blogspot.com
//electronnote@gmail.com
//Use at your own risk
 
 unsigned char  m;
 unsigned   dt, dt0;
 void Interrupt(){
  if (TMR1IF_bit){        //Timer1 Interrupt occured
    TMR1IF_bit = 0;
    TMR1H         = 0x6D;
    TMR1L         = 0x84;
  dt = ADC_Read(0);
  }
}
 void cw(){         //CW direction
 while(1){
 PORTB = 8;
 PORTD = 1;
 if (dt != dt0) {
  dt0 = dt;
  dt0 = dt0 >> 2;
  PWM1_Set_Duty(dt0);
  PWM1_Start(); }
  if (Button(&PORTB, 0, 100, 0)) {
   PWM1_Stop();
   break;}
  }
 }
 void ccw(){           //CCW direction
 while(1)   {
 PORTB = 16;
 PORTD = 2;
 if (dt != dt0) {
  dt0 = dt;
  dt0 = dt0 >> 2;
  PWM1_Set_Duty(dt0);
  PWM1_Start();   }
  if (Button(&PORTB, 0, 100, 0)){
   PWM1_Stop();
   break; }
  }
 }
 void InitTimer1(){        //Timer1 Interrupt initialize
  T1CON         = 0x31;
  TMR1IF_bit    = 0;
  TMR1H         = 0x6D;
  TMR1L         = 0x84;
  TMR1IE_bit    = 1;
  INTCON        = 0xC0;
}

void main() {
 ADCON1 = 14;                // Configure AN0 as analog
 CMCON  = 0X07;             //Disable comparators
 PORTB = 0; 
 TRISB = 0X07;
 PORTD = 0;
 TRISD = 0;
 InitTimer1();
 PWM1_Init(10000);
 for(m = 0; m < 6; m++){
  PORTB.F3 = ~ PORTB.F3;
  PORTB.F4 = ~ PORTB.F4;
  delay_ms(500);}
 while(1){
  PORTB = 0;
  PORTD = 0;
  if (Button(&PORTB, 1, 100, 0)){
  PWM1_Start();
  cw();          }
  if (Button(&PORTB, 2, 100, 0)){
  PWM1_Start();
  ccw();         }
 }
}