Arduino - Motor speed control pwm

Friday, December 23, 2016

This article will show how to control motor speed by PWM

Hardware needed:
1. Motor with encoder
2. H-bridge L298N
3. Arduino pro mini

Connected them together:
Result bellow looks not perfect in shape, but it works well
How to connect them?

(1) Connect encoder to Arduino
This encoder has pulse A, B -> connect to Arduino, don't forget connect power for it. So there will be totally 4 wires connected from motor encoder to Arduino.
     Arduino pin 2 <-> Encoder pulse A
     Arduino pin 3 <-> Encoder pulse B
     Arduino VCC <-> Encoder power
     Arduino GND <-> Encoder GND

(2) Connect to H-bridge module
H-bridge normally is used to control motor speed, direction -> let's google it to see how it works. In this article, H-bridge uses chip L298N.
This module will have direction signal (3 wires): 1 for "Forward", 1 for "Backward", 1 for "Enable". Arduino will output signal to direction signal to control direction of motor (through "Forward", "Backward" signal), to control speed of motor (through "Enable" signal):
     Arduino pin 4 <-> H-bridge "forward"
     Arduino pin 5 <-> H-bridge "backward"
     Arduino pin 6 <-> H-bridge "Enable"
Of course the H-bridge PCB will have output to Motor, this will be connected to Motor. Also power source for it, this power is used for chip L298N, also motor. This case, it is about 12VDC.
Note that, there is another cable: GND (ground) cable from Arduino -> it needs to be connected for sending signal from Arduino to H-bridge PCB (this GND cable is used to make the base for signal from Arduino)

Code works:

const byte pin_a = 2;   //for encoder pulse A
const byte pin_b = 3;   //for encoder pulse B
const byte pin_fwd = 4; //for H-bridge: run motor forward
const byte pin_bwd = 5; //for H-bridge: run motor backward
const byte pin_pwm = 6; //for H-bridge: motor speed
int encoder = 0;
int m_direction = 0;
int sv_speed = 100;     //this value is 0~255
double pv_speed = 0;
int timer1_counter; //for timer

void setup() {
  attachInterrupt(digitalPinToInterrupt(pin_a), detect_a, RISING);
  // start serial port at 9600 bps:
  //--------------------------timer setup
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
  //--------------------------timer setup

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only


In part 1, variables are declared. Next is set pulse A, pulse B of encoder as input; output for "forward", "backward", "PWM" signal
Let's go inside meaning:
attachInterrupt(digitalPinToInterrupt(pin_a), detect_a, RISING);
This code is used to detect rising edge of pulse A encoder.
Encoder of motor is kind of disk, compacted with IR sensor, then output pulse A and B which is 90dg oppositely. In case run forward, rising edge of pulse A, B will be at 0 logic. In case run backward, rising edge of pulse A, B will be at 1 logic. By this, motor direction can be detected.
In the code, every time at rising edge of pulse A, an interrupt routine (name: detect_a()) will be called. In part 2 of code, sum of encoder will be calculated, and direction of motor also detected.
Next of the code is declare about UART communication -> this will be used to print out result for User
Next is timer set up -> in sort, this timer is configured at 0.5sec -> means that every 0.5sec, timer1 is ticked -> program will come to timer1 interrupt routine (in part 2). Timer1 is used to calculated motor speed

void loop() {
    digitalWrite(pin_fwd,0);        //run motor backward
    digitalWrite(pin_bwd,1);        //run motor backward
    analogWrite(pin_pwm,sv_speed);  //set motor speed
    Serial.print("speed (rpm) is : ");
    Serial.print(pv_speed);         //Print speed value to Computer
    Serial.print("  --  ");
    Serial.print("Direction = ");

void detect_a() {
  m_direction = digitalRead(pin_b);
ISR(TIMER1_OVF_vect)        // interrupt service routine - tick every 0.5sec
  TCNT1 = timer1_counter;   // set timer
  pv_speed = 60*(encoder/200.0)/0.5;
 Part 2 is continued of program.
At first, motor will be set to run backward. Then set PWM pulse to control motor speed (Google it to see how PWM control speed):
In this case, PWM pulse width is controlled by variable sv_speed, now sv_speed=100 of 255 (max) ~ 39%
Next of code is print result to UART port
Let's see 2 interrupt routine:
Encoder interrupt: as explain in part 1, every time at rising edge of encoder pulse A, this routine is called -> sum encoder, and read motor direction
Interrupt timer1 routine: every 0.5s, this routine is called -> calculate motor speed. In this case, motor encoder 1 revolution has 200 pulse.

Joint 2 parts of code. Compile it and download to Arduino -> Open serial port in Arduino IDE to see result (Tool > Serial Monitor).
The total code can be downloaded here (Google share)


At first, motor speed is 0 rpm (we turn off 12VDC power for H-bridge)
Then, 12VDC power is supplied for H-bridge, motor is running, speed is increasing
If motor shaft is touched (has some load), motor speed will decreased.

No comments:

Post a Comment


Search This Blog

Most Reading

Google+ Followers