Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Driving a servo motor

Status
Not open for further replies.

Wingmax

New Member
In this post I will demonstrate how to connect and drive a servo motor.
The brain of the servo motor is the input pulse width. The pulse width determines the servo motor's drive position.

A servo motor only has 3 wires, usually red, black and white. Red and black are +ve and ground connections, and white
is the drive connection. Usually a pulse width of 1 mS will make the servo motor to drive from one far end, and 2 mS
to the other end (180 degree). A 1.5 mS will be for middle position. However, bear in mind that every servo motor is different. You have to adjust the pulse
width accordingly.

servo1.jpg

So, all we need to do to drive the servo motor is to generate a pulse train with pulse width (PWM) of 1 mS to 2mS.

There are many ways to generate Pulse Width Modulation (PWM). We can use 555 or 556 chip, or use software with microcontroller. I like to use micro because it's versatile and it can be used as a central system.
It can be used to detect input signal and outputs waveforms to drive a motor.

There are different ways to generate PWM by sofware. We can use delay routine, Timer0, Timer0 and Timer1,
interrupt, or PWM in CCP module in some PIC micro.

I will start with the easiest method, ie, by delay routine. Please refer to block diagram and program code.

View attachment serveDelay_C.txt

Program code is for Hitec C compiler, and the delay routine can be downloaded from Hitec site. This motor drives more
than 180 degree.
The micro used is 16f84A.



To produce the pulse width:
PortB.1 is set high, delay for the required time duration then set low,and delay for 15 mS.
This process is repeated for 50 times. This method of producing PWM is not very accurate, but the pulse period for
the motor is not that critical, so this method works.
The program will make the servo motor to go to the far right, back to the middle and to the far left.
Because it takes bit longer to go to the far right when first starts, so it takes 50 pulses.

Next time I will use Timer0 method........
 
Last edited:
A servo motor only has 3 wires, usually red, black and white. Red and white are +ve and ground connections, and white
is the drive connection. Usually a pulse width of 1 mS will make the servo motor to drive from one far end, and 2 mS
to the other end (180 degree). A 1.5 mS w

Not to pic at this, but a small edit, white should be black, the image is correct. Would also suggest checking the specific servo's data sheet to make sure, read they are easy to damage if hooked up wrong.
 
HarveyH42 said:
A servo motor only has 3 wires, usually red, black and white. Red and white are +ve and ground connections, and white
is the drive connection. Usually a pulse width of 1 mS will make the servo motor to drive from one far end, and 2 mS
to the other end (180 degree). A 1.5 mS w

Not to pic at this, but a small edit, white should be black, the image is correct. Would also suggest checking the specific servo's data sheet to make sure, read they are easy to damage if hooked up wrong.


My apology. It should be red for +ve, black for ground, and white for drive connection. As shown on my diagram. However, I couldn't draw white line as it won't show up on white background. This is based on my experience and usually this is the case. But of course, always check the specs.
Sorry if I caused any problem for any body regarding this. :D
 
I should apologize, I didn't mean to be critical. This is a good thing. You can edit your own past posts and correct typing errors. Figured you were going to keep adding more to this thread.

Anyway, I've got some interest in micros and servos, but I'm using AVR, and was going to try BASIC (just started learning a few weeks ago).
 
HarveyH42 said:
I should apologize, I didn't mean to be critical. This is a good thing. You can edit your own past posts and correct typing errors. Figured you were going to keep adding more to this thread.

Anyway, I've got some interest in micros and servos, but I'm using AVR, and was going to try BASIC (just started learning a few weeks ago).

The error has been fixed. Thanks for spoting the error.
I will be adding more new threads regarding different methods of generating pulses.
 
Last edited:
HarveyH42 said:
Anyway, I've got some interest in micros and servos, but I'm using AVR, and was going to try BASIC (just started learning a few weeks ago).
Hi Harvey,

If it helps, here's a relatively simple high performance low overhead 8-channel Servo demo' I posted on the Swordfish BASIC Forum awhile ago. Perhaps it will provide ideas for using a similar module on AVR?

PORTB outputs a servo pulse for the Servo(0) through Servo(7) array element "on times" and the Servo(8 ) array element is used for the period "off time" (20000 usecs minus the cumulative servo "on times").

Have fun. Mike

Code:
{ 
**************************************************************** 
*  Name    : K8LH_Soft_Servo.BAS                               * 
*  Author  : Mike McLaren, K8LH                                * 
*  Notice  : Copyright (c) 2007 Micro Applications Consultants * 
*          : All Rights Reserved                               * 
*  Date    : 11/28/07                                          * 
*  Version : 1.0 "untested"                                    * 
*  Notes   : Uses CCP1 "compare" mode for 8 servos on PORTB    * 
*          : 1-usec resolution, extended 600-2400 usec pulses  * 
**************************************************************** 
} 
 
Device = 18F452 
Clock = 8 
 
{ 
**************************************************************** 
*  Servo(0)..Servo(7) elements hold 600..2400 usec "on times"  * 
*  Servo(8) = period "off time" (20000 - cumulative on times)  * 
**************************************************************** 
} 
Dim Servo(9) As Word            ' 8 servo and 1 period elements 
Dim TMR1 As TMR1L.AsWord        ' promote to 16 bit TMR1H:L 
Dim CCPR1 As CCPR1L.AsWord      ' promote to 16 bit CCPR1H:L 
Dim CCP1IF As PIR1.2            ' the CCP1 interrupt flag bit 
Dim Servx As Byte               ' servo bitmask (only 1 bit hi) 
Dim n As Byte                   ' servo array index 
 
{ 
**************************************************************** 
*  K8LH Hi-Rez Soft 8-channel PORTB 'compare' Servo Algorithm  * 
**************************************************************** 
} 
Interrupt Soft_Servo() 
  LATB = Servx                  ' output new Servo pulse bit 
  CCPR1 = CCPR1 + Servo(n)      ' setup next compare interrupt 
  CCP1IF = 0                    ' clear CCP1 interrupt flag 
  Servo(8) = Servo(8)- Servo(n) ' adjust end-of-cycle off time 
  Servx = Servx << 1            ' and prep for next channel 
  Inc(n)                        ' increment servo array index 
  If n = 9 Then                 ' if end of 20 msec period 
    n = 0                       ' reset array index 
    Servo(8) = 20000            ' reset 20 msec period element 
    Inc(Servx)                  ' reset Servo shadow to Servo 1 
  EndIf 
End Interrupt 
 
{ 
**************************************************************** 
*  Init Ports and Variables                                    * 
**************************************************************** 
} 
Sub Init() 
   LATB = 0                     ' all PORT B servo outputs '0' 
   TRISB = 0                    ' set PORT B all outputs 
   ADCON1 = 15                  ' all digital I/O (no analog) 
 
   For n = 0 To 7               ' preload the Servo array 
     Servo(n) = 1500            ' mid-range 1500 usec position 
   Next                         ' 
   Servo(8) = 20000             ' Servo period = 20 msecs 
   n = 0                        ' init ISR array index 
   Servx = %00000001            ' init PORT B servo output mask 
 
   TMR1 = 0                     ' clear 16 bit TMR1H:L pair 
   CCPR1 = 1000                 ' first "compare" interrupt 
   T1CON = %00010000            ' pre 2, post 1, 1 usec 'ticks' 
   CCP1CON = %00001010          ' setup CCP1 "compare" mode 
 
   PIR1 = 0                     ' clear peripheral int flags 
   PIR2 = 0                     ' 
   PIE1 = 0                     ' clear peripheral int enables 
   PIE2 = 0                     ' 
 
   PIE1.2 = 1                   ' enable CCP1 interrupts 
   INTCON.6 = 1                 ' enable peripheral interrupts 
   T1CON.0 = 1                  ' turn on Timer 1 
   Enable(Soft_Servo)           ' set GIE, enable interrupts 
End Sub 
 
{ 
**************************************************************** 
*  Main Program                                                * 
**************************************************************** 
} 
Init 
Repeat 
Until 0 = 1
 
Last edited:
why trun to far right only ?

i test your program in by using pic16f877a, as you say this program will make that motor to far right then back to middle then to far left, why the motor after trun to far right then direct stop there ?
:confused: :confused:
 
antkids said:
i test your program in by using pic16f877a, as you say this program will make that motor to far right then back to middle then to far left, why the motor after trun to far right then direct stop there ?
:confused: :confused:


Your program codes are not the same as mine, so you will not get the same result.
Also your crystal is 20Mhz, much faster than mine.

According to your codes , your mistake is you use decimal point.
If you check the delay function, you'll find that there are limits of the delay.e.g delay(x)
x must not > 255.

My motor can go as low as 500uS. I can't use 0.5 mS and I can't use 500uS. That's why I used
DelayUs(250) twice.

Hope these help. :)
 
Thank for replay !!!
I am using your program code to test servo motor, because i'm using PIC16F877A and my crystal is 20MHz, so what i should change in your program code ?

I try to change "#define XTAL 4000000" to "
#define XTAL 20000000" but the result also same, after move to right just stop there. Why like this ? I also try to change the delay time but the result also same.

May i add you as friend in hotmail ? Because I can easily ask you the question ?
 
antkids said:
Thank for replay !!!
I am using your program code to test servo motor, because i'm using PIC16F877A and my crystal is 20MHz, so what i should change in your program code ?

I try to change "#define XTAL 4000000" to "
#define XTAL 20000000" but the result also same, after move to right just stop there. Why like this ? I also try to change the delay time but the result also same.

May i add you as friend in hotmail ? Because I can easily ask you the question ?

Can you show us your codes?
 
Below are my program code :

#include <pic.h>
#include "delay.c"
#include "delay.h"

__CONFIG(WDTDIS & XT & UNPROTECT);

#define XTAL 20000000 //crystal frequency- 20MHz


main()

{
int i;
TRISC = 0; //PortC is output.

for (i = 0; i < 50; i++) //Send 50 pulses with width 600 uS
{
PORTC = 1; //Pulse high for 600uS
DelayBigUs(600); //since delayUs (x); x<255 so i change to delaybigus
PORTC = 0; //Pulse low for 20mS
DelayMs(20);
}
DelayMs(100); //Pause for 100mS

for (i = 0; i < 50; i++) //Send 50 pulses with width 1.5mS
{
PORTC = 1;
DelayMs(1); //Pulse high for 1.5mS
DelayBigUs(500);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

for (i = 0; i < 50; i++) //Send 50 pulses with width 2ms
{
PORTC = 1;
DelayMs(2);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

while (1); //Stops here, do nothing.

}

why send 50 pulses? why motor trun to right then stop there ? Acctually this program code is same as you post on forum, I just change something only.
What meaning of " __CONFIG(WDTDIS & XT & UNPROTECT); "
I'm using PIC16F877A, 20Mhz crystal.
 
antkids said:
Below are my program code :

#include <pic.h>
#include "delay.c"
#include "delay.h"

__CONFIG(WDTDIS & XT & UNPROTECT);

#define XTAL 20000000 //crystal frequency- 20MHz


main()

{
int i;
TRISC = 0; //PortC is output.

for (i = 0; i < 50; i++) //Send 50 pulses with width 600 uS
{
PORTC = 1; //Pulse high for 600uS
DelayBigUs(600); //since delayUs (x); x<255 so i change to delaybigus
PORTC = 0; //Pulse low for 20mS
DelayMs(20);
}
DelayMs(100); //Pause for 100mS

for (i = 0; i < 50; i++) //Send 50 pulses with width 1.5mS
{
PORTC = 1;
DelayMs(1); //Pulse high for 1.5mS
DelayBigUs(500);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

for (i = 0; i < 50; i++) //Send 50 pulses with width 2ms
{
PORTC = 1;
DelayMs(2);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

while (1); //Stops here, do nothing.

}

why send 50 pulses? why motor trun to right then stop there ? Acctually this program code is same as you post on forum, I just change something only.
What meaning of " __CONFIG(WDTDIS & XT & UNPROTECT); "
I'm using PIC16F877A, 20Mhz crystal.

I haven't had much success with DelayBigUs() before, so I don't know if it's OK.

You're using different PIC, so try use this in your Configuration word:
__CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS);

don't forget it's double underscore before the CONFIG.
If this configuration word isn't set correctly, program won't work properly.

Hope this will work.
 
Thanks for your help!!!
After change the code, the result also same. just keep trun in 1 direction that is form left to right. I have change the time but it also get the same result. Why like this ?? The code problem ? Below are the code :

#include <pic.h>
#include "delay.c"
#include "delay.h"

__CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS);

#define XTAL 20000000 //crystal frequency- 20MHz


main()

{
int i;
TRISC = 0; //PortC is output.

for (i = 0; i < 50; i++) //Send 50 pulses with width 600 uS
{
PORTC = 1; //Pulse high for 600uS
DelayUs(300); //since delayUs (x); x<255 so i change to delaybigus
PORTC = 0; //Pulse low for 20mS
DelayMs(20);
}
DelayMs(100); //Pause for 100mS

for (i = 0; i < 50; i++) //Send 50 pulses with width 1.5mS
{
PORTC = 1;
DelayMs(1); //Pulse high for 1.5mS
DelayBigUs(500);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

for (i = 0; i < 50; i++) //Send 50 pulses with width 2ms
{
PORTC = 1;
DelayMs(2);
PORTC = 0;
DelayMs(20);
}
DelayMs(100);

while (1); //Stops here, do nothing.

}
 
This should be a simple program. It shouldn't be that hard. :confused:
I got a feeling the configuration word hasn't been set correctly. The code on my chip definitely works. Only differences are we used different chip, crystal and delay function.

Also you haven't included DelayBigUs in your #include section. Wonder why you haven't got errors when you compiled the codes.
 
What about the fuse bits? I really don't know a lot about PIC, still little better than a beginner with AVR. But on my setup, burning the program is one thing, and setting the fuses is another. On the AVR, there are several choices that involve the clock (well 2 that I've used and understand). One divides the clock by 8. If PIC has a similar fuse, then the timing in your program wouldn't be set up right. Servos are all about the timing.
 
I sucess make the motor move, is my broad problem.
Thank for your help.
If got problem, hope you can help me again !!
 
HarveyH42 said:
What about the fuse bits? I really don't know a lot about PIC, still little better than a beginner with AVR. But on my setup, burning the program is one thing, and setting the fuses is another. On the AVR, there are several choices that involve the clock (well 2 that I've used and understand). One divides the clock by 8. If PIC has a similar fuse, then the timing in your program wouldn't be set up right. Servos are all about the timing.

The fuse is done in the Configuration word(or fuse)- internal osc, XTL etc.
The clock is specified in #define XTAL frequency.
 
Sorry !! need your help again !!
What is mean of ""__CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS) "" and ""#define XTAL 20000000"" . This must be define ? Inside your code, why Send 50 pulses ??
 
I thought you got it working?

The __CONFIG(.....) is to configure the microcontroller you use. You have to declare this whether you use C or asm. It just to specify what type of osc you use, disable watch dog timer etc. May be you should do some research on the internet. The #define XTAL, you've done it in your program. just to specify the speed of the crystal you use. In your case, it's 20M.

The reason I use 50 pulses is because the shaft has to rotate from on end to the other end. So at lease 30 pulses is required. 50 pulses just to ensure it has enough time to reach to the other end.

If all you want is just to drive the servo motor, then may be it's a bit waste to use 16F877?
 
Ya ! I sucess make it work.
Thank for help !! :) :) :) :) :)
Acctually I'm doing a robot, control servo motor is one part of my robot, so uisng a pic16f877a is ok cause many port can use and can add more fuction.
If my robot is sucess build it, I send you the vedio clip about my robot !!!
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top