# Control de servo Futaba S3003 con CCS



## DMag00 (Feb 17, 2009)

Antieriormente; ya habia sido asesorado por wilfretronic; al que agradezco su ayuda para este proyecto.
Mi problema es el siguiente;

Tengo el siguiente codigo; 


```
#include "C:\Proyectos con Proteus y MPLab con LCD\Programas para PCB en PIC C compiler CCS\Circuito de prueba para un 16F876A\Programa para servo Futaba S3003 con CCS\Pic16F876A_01_2.h"
#use delay (clock=4000000)                //Fosc=4Mhz
#byte PORTA=5
#byte PORTB=6
#byte PORTC=7
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)

//////////////////////////////////////////////
//Variables externas y funciones
//////////////////////////////////////////////
void retardo (unsigned int32 y);
void pulso(unsigned int pulso_alto);
unsigned int32 high=0,low=0,ajustar=0; 
unsigned int mover_a=0;
//////////////////////////////////////////////
//Programa inicial
//////////////////////////////////////////////
void main(void)
{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   set_tris_a(63);                     //Todo el Puerto A como entrada
   set_tris_b(255);                    //Todo el PUERTO B como entrada
   set_tris_c(0);            //Todo el PUERTO C como salida
  while(1) 
   { 
   if(PORTA==33)               //Si A0 y A5 estan en 1
         {
              mover_a=PORTB;         //Guardar valor de PORTB en mover_a
              delay_us(5);         //Retardo de 5 microsegundos
              ajustar=mover_a;      //Pasar el valor mover_a hacia ajustar
                                //por seguridad pasa de int a int32
         }
    if(PORTA==0&&ajustar>=0&&ajustar<=180)
      {pulso(ajustar);}                        //Llamar funcion para generar pulso        
   } 
} 
///////////////////////////////////////////////////

///////////////////////////////////////////////////
//==========    Funcion retardo    ================ 
//=================================================
void retardo (unsigned int32 y)                 
 { 
  unsigned int32 z;     //Varible contador
  for(z=1;z<=y;z++)     //Realizar retardo de 10us "y" veces
   {                  
   delay_us(10);        //Retardo de 10 microsegundos
   }
 }
////////////////////////////////////////////////
 
////////////////////////////////////////////////
//==========    Funcion pulso    ================ 
//===============================================
void pulso(unsigned int pulso_alto )
{
    high=pulso_alto+30;              //Calcula tiempo en alto "high"
                                     //   30 = 0 grados (constante)
                                     //   40 = 1 grado
                                     //   210 = 180 grados
    low=2000-high;                   //Calcula tiempo en bajo
                                     //**High+low=(2000x10us)= 50Hz o 20 ms
    bit_set(PORTC,0);                //Activo el PIN 1 del puerto C 
    retardo(high);                   //Llamar funcion de retardo
    bit_clear(PORTC,0);              //Limpiio el PIN 1 del puerto C 
    retardo(low);                    //Llamar funcion de retardo          
}
///////////////////////////////////////////////////

///////////////////////////////////////////////////
```


el cual he simulado con proteus VSM y creado por PIC C Compiler CCS,

El proyecto de simulacion ha sido adjuntado

El problema es que en Proteus funciona de maravilla; pero al grabar el *.hex al PIC ya no funciona correctamente, es decir, yo doy la combinación binaria por el puerto B no mayor o igual a 180 y la señal es sacada por el RC0 a una frecuencia de 50 HZ, y no es asi.

Creo que el error esta en el tipo de variables que uso; para lo que estoy pidiendo ayuda, segun yo puede ser el retardo a 10 us o el incremento de la trancisión de alto a bajo en la funcion pulso. además que el servo comenzaba a vibrar, pero ya he corregido esto o al menos no se nota(vibraba porque la señal de control obligaba al servo a ir más alla de 180 grados, y las vibraciones, eran golpes con el tope que posee el servo), incluso logre mover el servo de 0 grados a 180, pero la varible "ajustar" solo puede tomar un valor menor o igual a 42 (es decir 0= 0 grados y 42 = 180 grados); esto no lo entiendo; por favor alguien que me ayuda a comprender porque mi simulación en proteus con el anterior programa si funcionaba y al cargarlo al PIC ya no lo hacia de la forma correcta. aunque como repito yo creo que son las variables.

Le hice algunas modificaciones para que funcionara al menos como lo necesito cambiando la constante de 2000 a 500.
Es poco codigo asi que espero sea comprendido con la menor explicación.


```
#include "C:\Circuito de prueba para un 16F876A\Programa para servo Futaba S3003 con CCS\Pic16F876A_01_1.h"

#use delay (clock=4000000)                //Fosc=4Mhz
#byte PORTA=5
#byte PORTB=6
#byte PORTC=7
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)

//////////////////////////////////////////////
//Variables externas y funciones
//////////////////////////////////////////////
void retardo (unsigned int32 y);
void pulso(unsigned int pulso_alto);
unsigned int32 high=0,low=0,ajustar=0; 
unsigned int mover_a=0;
//////////////////////////////////////////////
//Programa inicial
//////////////////////////////////////////////
void main(void)
{

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   set_tris_a(63);                     //Pin RA0,RA3 como entradas
   set_tris_b(255);                    //Todo el PUERTO B como entrada.
   set_tris_c(0);            //Todo el PUERTO C como salida
  while(1) 
   { 
   if(PORTA==33)               //Si A0 y A5 estan en 1
         {
              mover_a=PORTB;         //Guardar valor de PORTB en mover_a
              delay_us(1);         //Retardo de 5 microsegundos
              ajustar=mover_a;      //Pasar el valor mover_a hacia ajustar
                                //por seguridad pasa de int a int32
         }
    while(PORTA==0&&ajustar>=0&&ajustar<=180)
      {pulso(ajustar);}                        //Llamar funcion para generar pulso        
   } 
} 
///////////////////////////////////////////////////

///////////////////////////////////////////////////
//==========    Funcion retardo    ================ 
//=================================================
void retardo (unsigned int32 y)                 
 { 
  unsigned int32 z;     //Varible contador
  for(z=1;z<=y;z++)     //Realizar retardo de 10us "y" veces
   {                  
   delay_us(10);        //Retardo de 10 microsegundos
   }
 }
////////////////////////////////////////////////
 
////////////////////////////////////////////////
//==========    Funcion pulso    ================ 
//===============================================
void pulso(unsigned int pulso_alto )
{
    high=pulso_alto+10;              //Calcula tiempo en alto "high"
                                     //   30 = 0 grados (constante)
                                     //   40 = 1 grado
                                     //   210 = 180 grados
    low=500-high;                   //Calcula tiempo en bajo
                                     //**High+low=(2000x10us)= 50Hz o 20 ms
    bit_set(PORTC,0);                //Activo el PIN 1 del puerto C 
    retardo(high);                   //Llamar funcion de retardo
    bit_clear(PORTC,0);              //Limpio el PIN 1 del puerto C 
    retardo(low);                    //Llamar funcion de retardo          
}
///////////////////////////////////////////////////

///////////////////////////////////////////////////
```

Ahora. Lo que necesito es que al recibir una combinación binaria por el puerto B, el servomotor Futaba S3003 se desplace segun sea el valor por RC0; cabe mencionar que la aceptación de dicho valor es controlado por RA0 y RA1.

Por favor y gracias.

cualquier duda o aclaración estoy a sus ordenes Dmag00


----------



## DMag00 (Mar 8, 2009)

por favor; aun sigo esperando ayuda, gracias


----------



## cristian_elect (Mar 8, 2009)

Usa pwm.


----------



## cristian_elect (Mar 8, 2009)

Oye los delay_us(int16) soportan hasta 65ms ya pe dale asi en la funcion pulso. Este un retaso que te corrige los retardos en tu programa.
pulso_alto=pulso alto*10;
pulso_bajo=20000-pulso_alto; // 20000us=20ms
bit_set(PORTC,0);
delay_us(pulso_alto);
bit_clear(PORTC,0);
delay_us(pulso_bajo);
claro que las variables pulso_alto y pulso_bajo deben esta en unsigned int16 o long.


----------



## mvrt (May 27, 2010)

Hola, necesito un driver para usar el servo futaba s3003 con un dsPIC30F3010, alguien me podria ayudar???es bastante urgente
gracias!


----------



## mendek (Abr 26, 2012)

que tal foro, esta vez mi duda es como controlar el servomotor futaba s3003 con un pic16f84a ya que hasta ahora solo e logrado ubicarlo en -90° y +90° pero no e podido ubicarlo en 0°, según tengo entendido que para ubicarlo en esa posición tengo que mandarle un pulso de 1520us y al hacerlo se ubica un tanto a la izquierda pero no en el centro, no se si conozcan alguna formula para ubicarlo en tal posición y así saber el ancho del pulso o alguna otra forma


----------



## holanda (May 6, 2012)

hola DMag00

apenas comienzo a programar en CCS, antes programaba en picbasic y he querido controlar un servo, en picbasic era muy fácil con la funcion "pulseout" pero en CCS aun no he encontrado la forma, no se si de favor pudieras subir tu simulación en proteus de como hiciste las conexiones para controlar el servo, gracias saludos.


----------



## angeldemx (May 7, 2012)

Hola DMag00 y los otros compañeros con dudas sobre el control de servos, les puedo ayudar con sus proyectos pero primero sugiero que que usen este programa para el control del servo.

este ya esta funcionando al 100%:

y solo agregues la función que necesites.

Aclaro solo funciona para los pic16f877 y 876 para migrarlo a otro servo tienen que buscar la direcciones el el datasheet del micro al que quieran migrar el programa:

#byte trisb=0x86
#byte portb=0x06
#byte trisc=0x87
#byte portc=0x07

ya que para los otros micros cambian la direcciones.


```
#include <16f877a.h>                   
#fuses  XT,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP       

#use delay(clock=4000000)              

#byte trisb=0x86
#byte portb=0x06
#byte trisc=0x87
#byte portc=0x07

#include <lcd.c>                       
//#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0XA0, slow , FORCE_HW)

#bit  Bit_PWM0 =  PORTC.0              //Bit 0 puerto B Salida modulación 0
        
             


void main (void);             
void Generador_pwm (void);   

int8 control_PWM=0;
int8 PWM0=0;
unsigned int8 mover_a;

#int_Timer0

void generacion_pwm(){
   
   control_PWM++;                //Incremento cada rebose del timer0
  
   if (control_PWM==0){          //inicio del ciclo con todos los pulsos pwm a 1
      Bit_PWM0=1;      
      
   }
   //Finalizará el pulso de modulación según el valor del correspondiente pwm
   if (control_PWM==PWM0) Bit_PWM0=0;
   
   
   set_timer0(255);                    //Carga del contador
}

void main(){

   trisc=0x00;
   set_tris_b(0xff);
   
   pwm0=0;                      
   
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);         
   enable_interrupts(INT_TIMER0);    
   enable_interrupts(GLOBAL);        
   lcd_init();             
     
   while (true){
   
               mover_a=input_b();    //leyendo puerto b
               pwm0=mover_a;        //estado del puerto B (numero decimal de la combinación puerto B) 
               lcd_gotoxy(5,1);
               printf(lcd_putc,"El numerito es");
               lcd_gotoxy(1,2);
               printf(lcd_putc,"%i",mover_a);  // muestra en lcd la cifra en decimal puerto b
               delay_ms(100);
               lcd_gotoxy(1,2);
               printf(lcd_putc,"\f");              // borra lcd
          
               
       }
}
```
Se puede  modificar el código para que tu lo ajustes es para un solo servo, por lo que veo esta programación es mas simple, ya tengo hambre  ya me voy a comer.

No dudes en preguntarme si tienes alguna duda.

fuente: http://robotypic.blogspot.mx/2010/11/control-de-8-servos-con-pic-16f876a_13.html


saludos desde Irapuato, Guanajuato.


----------



## holanda (May 7, 2012)

hola angeldemx

gracias por subir el codigo y la simulacion en proteus, te lo agradezco habia buscado la forma de controlar un servo en CCS pero siempre me encontraba con codigos algo dificil de entender y largos y este se ve mas sencillo para estudiarlo e ir entendiendo cada parte, gracias saludos.


----------



## angeldemx (May 7, 2012)

Saludos holanda, me alegra que les sirva ya saben, estamos para ayudar y compartir.


----------

