Home > Electronic Tutorials > Microcontroller Tutorials > PIC 16F877A Project Tutorial > DC Motor Output

PIC16F877A Microcontroller Project Tutorial

DC Motor Output

Normally, you will use an H bridge for motor control. There are many internet articles about H bridges if you want to learn how they work.

Materials

  • Circuit from “Introduction to the PIC16F877A”
  • DC motor
  • H bridge chip
  • Wire

Circuit

Depends on the type of H bridge. I have used an old SN754410 quadruple half-h driver to run 2 motors at once. I also used a custom H bridge circuit board designed by club president Don Crouse. See the data sheet.

Important: whenever you change the direction, you should set all motor signal lines to 0 (output_low). This prevents short circuits.

Code & Notes

I will not include an entire program here, because each H bridge model has different rules for motor control. The datasheet will tell you how to set the signal lines.

There are two major types of output signals on most H bridges.

The first signal turns the motor on or off. It is often called the “Enable Pin”. Whenever you want to turn the motor on, respectively off, type output_high(MOTOR_ENABLE_PIN); and output_low(MOTOR_ENABLE_PIN);

The second type are the signals indicating which direction the motor should turn, whether the motor free runs, and whether the motor brakes. Send 0 or 1 to those control signals: output_high(MOTOR_DIRECTION_PIN_1), for example.

A simple illustration:

Direction Pin Enable Pin Results
0 (output_low)1 (output_high) One direction
1 (output_high)1 (output_high)Other direction
X (doesn’t matter) 0 (output_low) Free run (slow down & stop)

Some H bridges will only let you set the motor direction. In that case, you brake by reversing the motor direction for a short time. Beware: the current draw can spike if you do this, and the PIC might black out. But sometimes sudden direction reversal is OK; you will have to see for yourself.

If you have set the signals to make the motor go left, it will keep going left until you explicitly tell it to stop (or go right).

It is a good idea to write functions like “forward”, “backward”, “left”, “right”, “stop”. That way you can just call the function & not have to worry about the details.

Below are code excerpts from motor control for SN754410 H bridge, controlling 2 motors. Your motor control code will NOT be the same, because you will use a different H bridge or have different needs. But it will be similar to this.

#define LEFT_CONTROL_2A PIN_C2 //2A
#define LEFT_CONTROL_1A PIN_C1 //1A
#define LEFT_MOTOR PIN_D1 //1,2EN
#define RIGHT_MOTOR PIN_D2 //3,4EN
#define RIGHT_CONTROL_4A PIN_D5 //4A
#define RIGHT_CONTROL_3A PIN_D4 //3A
int going_forward; //current motion
int going_backward;
int going_left;
int going_right;
int going_hard_left;
int going_hard_right;


//brake by reversing motor direction, then turn motors off
void halt(){
  if (going_forward)
     backward();
  else if (going_backward)
     forward();
  else if (going_left)
     right();
  else if (going_right)
     left();
  else if (going_hard_left)
     hard_right();
  else if (going_hard_right)
     hard_left();
  delay_ms(50);   //reverse direction for 50 ms, enough to make robot stop
                         //but not long enough to make it start moving in opposite direction
  resetMotorControl();
}

void forward(){
  resetMotorControl();
  output_high(LEFT_CONTROL_1A);
  output_high(RIGHT_CONTROL_3A);
  output_high(LEFT_MOTOR);
  output_high(RIGHT_MOTOR);
  going_forward=1;
}

void backward(){
  resetMotorControl();
  output_high(LEFT_CONTROL_2A);
  output_high(RIGHT_CONTROL_4A);
  output_high(LEFT_MOTOR);
  output_high(RIGHT_MOTOR);
  going_backward=1;
}

//run only 1 motor for gentler turn
void right(){
  resetMotorControl();
  output_high(RIGHT_CONTROL_3A);
  output_high(RIGHT_MOTOR);
  going_right=1;
}

//run only 1 motor for gentler turn
void left(){
  resetMotorControl();
  output_high(LEFT_CONTROL_1A);
  output_high(LEFT_MOTOR);
  going_left=1;
}

//run one motor forward and one backward for sharper turn
void hard_left(){
  resetMotorControl();
  output_high(LEFT_CONTROL_1A);
  output_high(RIGHT_CONTROL_4A);
  output_high(LEFT_MOTOR);
  output_high(RIGHT_MOTOR);
  going_hard_left=1;
}

//run one motor forward and one backward for sharper turn
void hard_right(){
  resetMotorControl();
  output_high(LEFT_CONTROL_2A);
  output_high(RIGHT_CONTROL_3A);
  output_high(LEFT_MOTOR);
  output_high(RIGHT_MOTOR);
  going_hard_right=1;
}

//Set all pins to H-bridge low to prevent short circuits
//Reset "current motion" flags
void resetMotorControl(){
  output_low(LEFT_MOTOR);
  output_low(RIGHT_MOTOR);
  output_low(LEFT_CONTROL_1A);
  output_low(LEFT_CONTROL_2A);
  output_low(RIGHT_CONTROL_3A);
  output_low(RIGHT_CONTROL_4A);
  going_forward=0;
  going_backward=0;
  going_left=0;
  going_right=0;
  going_hard_left = 0;
  going_hard_right = 0;
  delay_us(20);
}

Special Topic: PWM

Now you know how to run the motor at full speed. But a situation might arise where you want half speed, or ¾ speed, etc. In that case, you can send a PWM signal to the H bridge enable pin. There are many internet articles about PWM if you want to learn how it works.

To use PWM in motor control, replace output_high(MOTOR_ENABLE_PIN) with set_pwm1_duty(x) . Make sure that the “enable pin” wire goes into the PIC pin CCP1 or CCP2. Those are the only pins that can have PWM signal.

PWM code excerpt:

setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(CCP_PWM); //set pin CCP1 as a PWM pin instead of a regular I/O pin
setup_ccp2(CCP_PWM); //set pin CCP2 as a PWM pin instead of a regular I/O pin
while(true){
  //if setting duty cycle (set_pwm1_duty), only give values between 0-255
  //0 means the PWM signal is always at 0. 128 means it is 1 half the time & 0 the other half
  //leading to an averaged "1/2 power" signal. 255 means it is 1 all the time, motor full speed
  set_pwm1_duty(255); //enable pin for motor 1: PIC pin CCP1
  set_pwm2_duty(255); //enable pin for motor 2: PIC pin CCP2
  delay_ms(3000); //full speed for 3 seconds
  set_pwm1_duty(128);
  set_pwm2_duty(128);
  delay_ms(3000); //half speed for 3 seconds
  set_pwm1_duty(0);
  set_pwm2_duty(0);
  delay_ms(3000); //motors off for 3 seconds
}

//Use PWM in your DC motor control code to change the speed that the robot goes forward/backward/left/right

//call forward(255); to go forward at full speed. Call forward(128); to go forward at half speed.
void forward(int speed){
  resetMotorControl();
  output_high(LEFT_CONTROL_1A);
  output_high(RIGHT_CONTROL_3A);
  set_pwm1_duty(speed); //wire from PIC pin CCP1 to right motor enable pin
  set_pwm2_duty(speed); //wire from PIC pin CCP2 to left motor enable pin connected to
  going_forward=1;
}

Notes

If you want to use higher voltage DC motors, or run motors at high speeds, you might have to construct a special circuit to deal with the extra current draw, heat, high voltage batteries, etc. DC motors have their own set of issues to deal with, which is beyond the scope of this tutorial.

Note: To report broken links or to submit your projects please send email to Webmaster

Discover

     more......