CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to

Robot Serial Servo Driver for Continuous Rotation Servos

Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Arizona Chris

Joined: 20 Dec 2014
Posts: 69
Location: Arizona

View user's profile Send private message Visit poster's website

Robot Serial Servo Driver for Continuous Rotation Servos
PostPosted: Mon Mar 14, 2016 9:30 pm     Reply with quote

Hi all, this will be the first of several uploads on serial servo chips. This one uses the ultra cheap 12F629 and while it has no UART, we can still produce a very useable serial servo chip by using a few simple tricks....

Here is my CCS-C based update on our servo driver chips, which is used to control a continuous rotation servo. For many years we have used this exact technique in our smaller robots, such as the PICbot series with great success. The basic concept is this - A modified continuous servo works by rotating one way at 1ms, the other way with 2ms and somewhere in between around 1.5ms pulse input the servo completely stops. But this must be a very accurate pulse - Even 5-10us off and the motor will slowly rotate. Thus the need for accuracy precludes using timers in the PIC even with a 10MHz crystal which did not roll over fast enough (100us) and even presetting them was not accurate enough. Here is how I accomplished it.


A serial byte is sent from the main processor, in this case a PIC16F887 microcontroller which sets the speed of each motor in 5 steps. Small home robots do not need an infinite variation on their speeds, only Fast Forward, Half speed Forward, Stop, Idle and two reverse speeds. The faster speeds allow them to travel toward a distant goal rapidly and then they can slow to half to approach their goal. Stop holds the motors still and Idle turns off all pulses to the motors so they dont draw large amounts of current when the robot is at rest.

The Program:

We first generate the blanking period of approximately 20ms by using the "TIMEOUT" parameter in the 232 setup. This does two things, first it looks for the serial input signal for the entire blanking period which is 85% of the pulse cycle. Then it times out and ends the low period. The pulse is generated accurately with the delay_us( ) function, standard in CCS. This is VERY accurate and allows us to stop the motor at the required pulse width.

Since there is no UART in this inexpensive device, we use a programming trick to always get the data in - I send the data from the main processor twice, separated by 10ms. This absolutely guarantees one of the two will land in the blanking interval. So 85% of the time it gets received on the first send, then 15% of the time is for sure. This time difference is so fast, it has no effect on the movements of the robot.

Before I post the code, here is my web page devoted to this project with schematics, photos of the devices and all code:

Now to send a 9600 baud byte to the servo chip from the main processor, you first set up the serial out like this:

#use rs232(baud=9600, xmit=Pin_B4, bits=8, parity=N,STREAM=SERVO1) //LEFT

To send the actual signal serially this is the command you can send,
using this table for speeds:

//Motor speed function table - Left Motor only, right is reversed:
// 0 - No Data in - turn on=low output, after that stays previous setting.
// 1 - STOP (1528uS) This will vary per motor!
// 2 - HALF FWD (1580)
// 3 - FULL FWD (2000us)
// 4 - HALF REV (1476)
// 5 - FULL REV (1000us)
// 6-255 - STOP (1528uS)

Sending the code:


void CSEND(void)  {     //This sends data out serially to the motor chip.
   for (n=0;n<=1;n++) {   //send several times
     fputc(SR,SERVO1);    //send data to servo 1
     fputc(SL,SERVO2);    //send data to servo 2
     delay_ms(10);   }   //space between bursts of data

Here is the PIC12F629 code:


//Chris Schur
//(Program Name):  12F629 - Robot Serial Servo Pod chip
//Date:  3/3/16

//I/O Designations ---------------------------------------------------
// A0 (GPIO0):  X
// A3 (GPIO3):  SERIAL DATA INPUT (can ONLY be input)

//Include Files:
#include <12F629.h>  //Normally chip, math, etc.  used is here.
//Directives and Defines:
#use delay(crystal=10MHz)
#use fast_io(A)
#use rs232(baud=9600, rcv=Pin_A3, bits=8, parity=N,TIMEOUT=15)
//Note: the "disable_ints is critical, turns off constant barrage of interrupts
//during the aquisition of data in the get command so timing is not affected.
#define LED Pin_A2  //status LED
#define SERVO Pin_A1  //Servo Motor PWM

//*******Global Variables (put before main and Interrupts to make ***********
//available everywhere):*****
int16 PW = 0;
int8 S = 0;     
//************* Functions/Subroutines, Prototypes:*************************
//*********** ----- Main Program     ****************************************
void main(void) {
   // Set TRIS I/O directions, define analog inputs, compartors:
        //(analog inputs digital by default) 
   //Initialize variables and Outputs:  --------------------------------------
      //variables used ONLY within main (local):
//---Initial Values---------------------------------------------------

//MAIN LOOP: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
while (true)   {
//Motor speed function table:
// 0 - No Data in
// 1 - STOP (1528uS) This will vary per motor!
// 2 - HALF FWD (1580)
// 3 - FULL FWD (2000us)
// 4 - HALF REV (1476)
// 5 - FULL REV (1000us)
// 6-255 - STOP (1528uS)

switch(S) {
case 0:  //NO DATA - dont change previous value!
case 1:  //STOP
         PW = 1528;
case 2:   //HALF FWD (200-16)
         PW = 1580;
case 3:  //FULL FWD  (200-20)
         PW = 2000;
case 4:  //HALF REV
         PW = 1476;
case 5:  //FULL REV
         PW = 1000;
default: //STOP - no power
      }  //hctiws
//Now generate pulse - 20ms low first:
S = getc();  //next generate 20ms delay using time out on RS232

if (S < 6)  {
//generate pulse if S is 0 - 5 only
if (PW < 500)
   }  //elihw
} //niam

Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group