Servo motor, Serial COM and 8051

In this project I control the angular position of a servo motor by using the serial communication ability of the 8051 microcontroller. To state it a bit more simply ..I control the angle by which the shaft of the servo motor rotates by pressing keys on my laptop. This project might be helpful to you, if you are planning to build a robotic arm someday and want to control it using your computer.

List of things I am using here:

  • 8051 microcontroller board.
  • A Servo motor.
  • Connecting wires.
  • Computer (..obviously :P)

The connections are really very simple. Choose any of the 32 input/output pins available on your microcontroller board and connect it to signal wire of the servo motor.

A servo motor has just three wire. One for Vcc, one for GND and a signal wire. They are generally colour coded. On the motor which I have, the colour codes are as follows:

  • Red – Vcc
  • Brown – GND
  • Yellow – Signal

In case you have any confusion regarding the colour codes for your motor,  it is always a good idea to just google the model of your motor and clear your doubt.

Once you are done with these connections, thats it  .. now all that needs to be done is to program the microcontroller.

In case you have used an Arduino board before, you might know that there already exists a library for controlling the Servo motor which makes the task trivial. But in the case of 8051 the it is a bit more complicated. Its easy but some math needs to be done.

The position of the servo motor depends on the width of the pulses that it receives on the signal wire.And these pulses need to have a time period of approximately 20ms. After doing some research on the web i found the “on” time of the pules required for various positions(.. applicable to my servo).

  • 0.388 ms – 0 degrees
  • 1.25ms – 90 degrees
  • 2.14ms -180 degrees

Next we need to create a loop that runs for a fixed amount of time and depending upon what is the width of the pulses required we can run it multiple number of times. The following code accomplishes it.

To give an example of how i use this code, say I want to set the angular position of the servo to 0 degrees. In that case i need to provide the pulses with the width of 0.388 ms.So i do it this way.

  • Set the output 1
  • Call set_timer(8) 8 * 50 = 400usec = 0.4ms ~0.388ms
  • Set the output 0
  • Call set_timer(400 – 8) // because 400* 50us = 20000us = 20ms.

And since the calling function is itself inside a loop that goes on forever unless you receive a character serially, we are able to provide the pulses every 20ms on the signal line that sets the servo at angular position zero.

The following function receives the angle that needs to be written on the servo and calls the set_timer() function shown above from within.

0,90 & 180 are the constants denoting different angles.

RI = 0 when no data is received  on the serial line and RI = 1 when data has been received successfully. So once data is received, it breaks out from the loop and exits to return to the main() function, as the write_pos() was called from main.

Now in the main function we do all the initializations, like setting the baud rate etc needed for serial communication.

To decide what value needs to be put in TH1 for a particular baud rate there is the following formula if the mode is 1:

TH1 = 255 – ((Crystal freq / 384)/baudrate).

Thats it then..when you load this program onto the microcontroller you ll be able to control the position of servo motor using the keys ‘1’, ‘2’ and ‘3’ on your keyboard.Check out the video here

Here is the final code:

//Servo motor position control using serial    communication

#include <reg52.h>
#include <stdio.h>

void write_pos(int position);
void set_timer(int x);

sbit servo_signal1 = P1^0;

int main (void){

unsigned char ch;

SCON = 0x50; //
TMOD = 0X22; //
TH1 = 244;   //
TR1 = 1;     //
TI = 1;      //
RI = 0;      //

while(!RI);
ch = SBUF;
RI = 0;

printf(“%c “,ch);
while (1){

switch(ch){
case ‘1’:
write_pos(0); // Set Servo position to 0 degrees
break;
case ‘2’:
write_pos(90); // Set Servo position to 90 degrees
break;
case ‘3’:
write_pos(180); // Set Servo position to 180 degrees
break;
default:
while(!RI); // wait till you get a valid input
RI = 0;

}
ch = SBUF;
printf(“%c “,ch);

}

}

void write_pos(int position){
int msec;
switch(position){
case 0:
msec = 8;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);}
RI = 0;
break;
case 90:
msec = 25;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);}
RI = 0;
break;
case 180:
msec = 40;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);
}
RI = 0;
break;
default:
;
}
}

void set_timer(int x){

int i;
// To run the loop given below once it takes approx 50us
// Since I have already used the timer 1 for serial communication, I use
// the timer 0 to give PWM signal to the servo motor.
for(i=0;i<x;i++)
{
TMOD=0x22;
TH0=0x0FF;
TL0=0x0D1;

TR0=1;
while(TF0==0);
TF0=0;
TR0=0;
}
}

Advertisements

, , , , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: