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

SERVOS: controlling more than 3 servo motors using any PIN

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

Joined: 27 Apr 2012
Posts: 50
Location: Brazil

View user's profile Send private message

SERVOS: controlling more than 3 servo motors using any PIN
PostPosted: Wed Apr 24, 2013 1:40 pm     Reply with quote

Hi everyone. I was need control various servos motors but the PIC 18F4550 has just 3 PWM's, then I create this library and test to create various PWM's using TIMER 0 and 4 MHz (if you need change it, change on library) on any PIN that you want. (sorry my bad english, I'm from Brazil).

The use was very simple, as you can see below:

#include <18F4550.h>
#fuses HS
#use delay(clock=4000000)

#include "aev_servo.c"

void main(){ 
   // declaration of variables PWM's (all must to be integer)
   int pwm1, pwm2, pwm3;

   // setup all pwm's that you'll use
   pwm1 = pwm_setup(830, PIN_E0);   // returns the index of the PWM (the first is 0)
   pwm2 = pwm_setup(590, PIN_E1);   // returns 1 (second)
   pwm3 = pwm_setup(950, PIN_C0);   // returns 2 (third)
   // init the pwm's
   // update value from pwm2 (PIN_E1) after 10 seconds
   pwm_update(pwm2, 600);
   while(1){ }

///////////////// METHODS ///////////////////////
// pwm_setup ( int16 DUTY_CYCLE, int16 PIN)
// setup the PIN will use PWM
// pwm_update( int PWM, int16 NEW_DUTY_CYCLE)
// change the duty cycle from a created PWM
// pwm_init()
// initialize the PWM's
// pwm_stop()
// stop the PWM's

The aev_servo.c library is below:

// Criado por:
// Vinicius Nunes Lage
// UFOP - Universidade Federal de Ouro Preto
// Engenharia de Controle e Automaçao
// Turma 09.1
// Ouro Preto, BRASIL
// Última modificação: 24/04/2013
// Created by:
// Vinicius Nunes Lage
// UFOP - Federal University of Ouro Preto
// Automation Engineer
// Class 09.1
// Ouro Preto, Brazil
// Last modification: 24/04/2013

#ifndef MAX_PWM
   #define MAX_PWM 10

int atual_pwm=0, i=0;

struct _PWM{
   int16 duty_cycle;
   int16 pin;
   int16 duty_escada;

int vet_aux_pos_struct[MAX_PWM], vet_pos_struct[MAX_PWM];

// ordena os valores de angulos recebidos
void Ordenar_Seleccao(struct _PWM *V, int N){
   int k, kk, pos_menor;
   struct _PWM aux;
   int aux2;
   for (k=0; k < N-1; k++){
      pos_menor = k;
      for (kk = k+1; kk < N; kk++)
         if (V[kk].duty_cycle < V[pos_menor].duty_cycle) pos_menor = kk;
         // troca os  valores das posicoes k com pos_menor
         if (pos_menor != k) {
            aux          = V[pos_menor];
            V[pos_menor] = V[k];
            V[k]         = aux;
            aux2                          = vet_aux_pos_struct[pos_menor]; 
            vet_aux_pos_struct[pos_menor] = vet_aux_pos_struct[k];
            vet_aux_pos_struct[k]         = aux2;


void set_duty_escada(){
   int i;
   PWM[0].duty_escada = PWM[0].duty_cycle;   
   for(i=1; i<atual_pwm; i++)
      PWM[i].duty_escada = PWM[i].duty_cycle - PWM[i-1].duty_cycle;

int pwm_setup(int16 duty_cycle, int16 pin){     
      PWM[atual_pwm].duty_cycle = duty_cycle;
      PWM[atual_pwm].pin = pin;
      vet_aux_pos_struct[atual_pwm] = atual_pwm;

void set_vet_pos(){
   int i;
   for(i=0; i<atual_pwm; i++){
      vet_pos_struct[ vet_aux_pos_struct[i] ] = i;

void pwm_init(){
   if(atual_pwm > 1) Ordenar_Seleccao( PWM, atual_pwm );   
   if(atual_pwm > 0){
      // calcula os duty_escada's
      // queremos uma frequencia de 50Hz, ou seja, 20ms!
      // (20/4) 5MHz / 16 -> 312500Hz / 50 = 6250 LOGO
      // 65536 - 6250 = 59286 (valor inicial)
      setup_timer_0( RTCC_INTERNAL | RTCC_DIV_16 );
      enable_interrupts( INT_TIMER0 );
      enable_interrupts( GLOBAL );

void pwm_stop(){
   disable_interrupts( INT_TIMER0 );

void pwm_update(int id_pwm, int16 duty_cycle){
   PWM[ vet_pos_struct[id_pwm] ].duty_cycle = duty_cycle;


// define qual timer irá usar (interrupção)
// por padrão usa o timer0

void pwm_intTimer(){

      int i;
      // todos para nivel alto
      for(i=0; i<atual_pwm; i++)
         output_high( PWM[i].pin );
      delay_us( PWM[0].duty_cycle );
      output_low( PWM[0].pin );
      // vai baixando o nivel em escada
      for(i=1; i<atual_pwm; i++){     
         delay_us( PWM[i].duty_escada );
         output_low( PWM[i].pin );         

This program uses:
RAM: 7%
ROM: 5%

Please test and if you found any bug, please tell me!
Thanks a lot ;)[/b]

Last edited by opvini on Thu Apr 25, 2013 12:00 pm; edited 1 time in total

Joined: 27 Apr 2012
Posts: 50
Location: Brazil

View user's profile Send private message

PostPosted: Thu Apr 25, 2013 11:58 am     Reply with quote

NOTE: you can calibrate the 0 degrees and 180 degrees from the servo whenever you insert or remove one servo. For example, if you work with 3 servos, it has one zero and one 180. If you work now with 4 servos, it has another zero and another 180 becouse onde servo motor more or less interfere directly in the processing by timer 0, so, always works with the maximum amount of the servo motors in the program.
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