# Manejar servos en C



## angeldemx (May 7, 2012)

Hola 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 de servos.

Este programa maneja 8 servos pero lo modifique para que maneje solo 1

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 lo ajustes a tus necesidades, por lo que experiencia esta programación es mas simple y efectiva.

No dudes en preguntarme si tienes alguna duda.

fuente: RobotyPic: Control de 8 servos con PIC


archivo isis para proteus simulación:

Ver el archivo adjunto 72354

saludos desde Irapuato, Guanajuato.


----------



## panchoreyes (Oct 29, 2012)

```

```
hola a todos. tengo que hacer un control de un servo motor a traves del hiperterminal, controlando la velocidad, posicion y velocidad de respuesta. no tengo muy claro como hacerlo se que se puede hacer un pwm con los "cpp" pero no entendi el funcionamiento. bueno les subo el programa para que me digan como voy y ver si me ayudan a terminarlo de antemano gracias.


```
#include <16F877A.h>
#use delay(clock = 4000000)      //Cristal de 4 MHz//
#include <lcd.c>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)   //CONFIG USART //

#fuses XT, NOWDT, NOLVP, NOBROWNOUT   //Programación de bits de Configuración//

#byte pa=0x05
#byte pb=0x06
#byte pc=0x07
#byte pd=0x08

char trama[5];
char per,motor,control,valor,n1,n2,n3;
int num1,num2,num3,grados,x,y;

#int_RDA        //Rutina para el servicio de Interrupción por Recepción de Trama//
            //(Las funciones de interrupción no pueden tener ningún parámetro)//
void RDA_isr(){
gets(trama);
disable_interrupts(GLOBAL);
lcd_putc('\f');
lcd_putc("Recibido");
lcd_putc('\f');
per=trama[0];     //Guarda el periférico a ocupar
motor=trama[1];   //Guarda el número de motor a comandar
n1=trama[2]; //Guarda el control que se le aplicará al motor
n2=trama[3];
n3=trama[4];
num1=trama[2]-48;/Transforma a entero
num2=trama[3]-48;
num3=trama[4]-48;
grados=num1*100 + num2*10 +num3;/valor del grado 
x=grados+1350;
y=x/900;
if (per!='M'){
   lcd_putc("Periférico \nDesconocido");
   PA=0;
   PB=0;
}
else{
   if (motor=='1'){
     
  PA=0b00001;
     delay_ms(y);
     PA=00000;
       PA=0b00001;
     delay_ms(y);
     PA=00000;
     
         
         printf(lcd_putc,"Motor1 girando \n %d",grados);
      }
      
     
   
   else if (motor=='2'){
      PB=0b00001;
     delay_ms(y);
     PB=00000;
     printf(lcd_putc,"Motor2 girando \n %d",grados);
   }
      else{
         PB=0;
         lcd_putc('\f');
         lcd_putc("Comando \nDesconocido");
      }   
   }
   
}


void main(){

   set_tris_a (0x00);
   set_tris_b (0x00);
   set_tris_c (0xB8);
   PA=0;
   PB=0;
   PC=0;
   
 

   lcd_init();
   lcd_putc('\f');
   lcd_putc("Listo");
   delay_ms(1000);
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA);
   lcd_putc('\f');
   while(1)
   enable_interrupts(GLOBAL);
}
```


----------



## panchoreyes (Nov 1, 2012)

necesito hacer lo mismo fuente: http://robotypic.blogspot.mx/2010/11...6f876a_13.html pero mandar las ordenes serialmente. lo he intentado pero nose que estoy haciendo mal es mas ni siquiera me da el pwm en el pin. de los intentos que he hecho subo el ultimo intento

```
#include <16F877A.h>
#use delay(clock = 4000000)      //Cristal de 4 MHz//
#include <lcd.c>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)   //CONFIG USART //

#fuses XT, NOWDT, NOLVP, NOBROWNOUT   //Programación de bits de Configuración//

#byte pa=0x05
#byte pb=0x06
#byte pc=0x07
#byte pd=0x08
#byte trisa=0x85
#byte trisb=0x86
#byte trisc=0x87
char trama[5];
char per,motor,cien,diez,uno;
int16 centenas,angulo;               //variable para las centenas del ángulo
   int decenas,unidades;         //Variable para las decenas y unidades del ángulo

#int_RDA        //Rutina para el servicio de Interrupción por Recepción de Trama//
            //(Las funciones de interrupción no pueden tener ningún parámetro)//
void RDA_isr(){
gets(trama);
disable_interrupts(GLOBAL);
lcd_putc('\f');
lcd_putc("Recibido");
per=trama[0];     //Guarda el periférico a ocupar
motor=trama[1];   //Guarda el número de motor a comandar
cien=trama[2]; //Guarda el control que se le aplicará al motor
diez=trama[3];
uno=trama[4];
centenas=cien-84;
decenas=diez-84;
unidades=uno-84;
angulo=(centenas*100)+(decenas*10)+unidades; 
if (per!='M'){
   lcd_putc("Periférico \nDesconocido");
   
}
else{
   if (motor=='1'){
      if (cien=='D'){
         set_pwm1_duty(90);
         lcd_putc('\f');
         lcd_putc("Motor 1 \nDerecha");
      }
      else if (cien=='I'){
         PA=1;
         lcd_putc('\f');
         lcd_putc("Motor 1 \nIzquierda");
      }
      else{
         PA=0;
         lcd_putc('\f');
         lcd_putc("Comando \nDesconocido");
      }   
   }
   else if (motor=='2'){
      if (cien=='D'){
         PB=1;
         lcd_putc('\f');
         lcd_putc("Motor 2 \nDerecha");
      }
      else if (cien=='I'){
         PB=2;
         lcd_putc('\f');
         lcd_putc("Motor 2 \nIzquierda");
      }
      else{
         PB=0;
         lcd_putc('\f');
         lcd_putc("Comando \nDesconocido");
      }   
   }
   else {
      PA=0;
      PB=0;
      lcd_putc('\f');
      lcd_putc("Motor \nDesconocido");
   }
}
}

void main(){

SETUP_TIMER_2(t2_div_by_1,224,1);
setup_ccp1(ccp_pwm);
setup_ccp2(ccp_pwm);
   set_tris_a (0x00);
   set_tris_b (0x00);
   set_tris_c (0xB8);
   PA=0;
   PB=0;
   PC=0;
   lcd_init();
   lcd_putc('\f');
   lcd_putc("Listo");
   PB=1;
   delay_ms(1000);
   PB=0;
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA);
   lcd_putc('\f');
   while(1)
   enable_interrupts(GLOBAL);
}
```
este solo lo hice con el fin de ver si es que me daba el pwm en el pin c1 ojalas me puedan ayudar de antemano gracias


----------



## panchoreyes (Nov 2, 2012)

este es mi ultimo intento y para variar falle de nuevo les subo el programa y el cto para que me digan que hago mal.
gracias.

```
#include <16f877a.h>                   //archivo para control del pic 16f876a

#fuses XT,NOWDT,NOPROTECT,NOLVP        //protecciones
#use delay(clock=4000000)              //frecuencia de reloj 4 MHz

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

#define use_portb_lcd TRUE             //Configuración puerto b control lcd
#define use_portb_kbd TRUE             //Configuración puerto b control teclado
#include <lcd.c>                       //archivo para control del lcd

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)   //CONFIG USART //


#bit  Bit_PWM1 =  PORTC.1             //Bit 1 puerto B Salida modulación 1
#bit  Bit_PWM2 =  PORTC.2              //Bit 2 puerto B Salida modulación 2


/********************** Prototipos de las funciones ***************************/

void main (void);             //función principal
void generacion_pwm (void);   //genera señales moduladas para control de servos
void presentacion (void);     //mensaje de presentación

/********************** Variables para generación PWM *************************/

int8 PWM1=0,PWM2=0; //Valores de las señales PWM
int8 control_PWM=0;

/******************************************************************************/
/******************* FUNCIÓN GENERACIÓN MODULACIONES PWM **********************/

#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_PWM1=1;
      Bit_PWM2=1;
     
   }
   //Finalizará el pulso de modulación según el valor del correspondiente pwm

   if (control_PWM==PWM1) Bit_PWM1=0;
   if (control_PWM==PWM2) Bit_PWM2=0;
  
   
   set_timer0(255);                    //Carga del contador
}
   
/******************************************************************************/
/************************* PRESENTACIÓN LCD ***********************************/

void presentacion (){

   lcd_putc("\f   Introduce   \n");  
   lcd_putc(" num. de servo ");  
}

/******************************************************************************/
/******************** FUNCIÓN PRINCIPAL ***************************************/

 #int_RDA      
void main(){

  char trama[3];
  char x,angulo,control;
  
  gets(trama);
  x=trama[0];     //Guarda el periférico a ocupar
angulo=trama[1];   //Guarda el número de motor a comandar
control=trama[2]; //Guarda el control que se le aplicará al motor
                          //Valor ASCII de la tecla pulsada
   int tecla;                    //Valor numérico de la tecla pulsada
   int servo;                    //Número de servo
   int16 vangulo;                 //Ángulo del servo
   int16 centenas;               //variable para las centenas del ángulo
   int decenas,unidades;         //Variable para las decenas y unidades del ángulo
   int pwm;                      //valor de la modulación por teclado
   
   trisc=0xB6;                   //Puerto C como salida de datos
   
  
   pwm1=7;                      //Impulso de 0,8 msg de pwm1 posición 0º
   pwm2=7;                      //Impulso de 0,8 msg de pwm2 posición 0º
  
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32); //Configuración interrupción generación PWM

   enable_interrupts(INT_TIMER0);    //Habilitación interrupción generación pwm
   enable_interrupts(GLOBAL);        //Habilitación de las interrupciones
   
   port_b_pullups(TRUE);   //Habilitación resistencias pullups puerto b
   lcd_init();             //Inicialización del lcd
  // kbd_init();             //Inicialización del teclado
   
   presentacion ();        //Muestra mensaje de inicio en lcd
   
   while (true){
       
                          //En "x" valor ASCII de la tecla pulsada

      if (x!=0&&x!='0'&&x!='3'&&x!='*'&&x!='#'){ //Si se pulsa tecla numérica 0 a 7 ...
         servo=x-48;            //Valor ASCII se pasa a valor numerico de servo
         printf(lcd_putc,"\fServo = %d\n", servo); //...muestra el valor pulsado
         lcd_putc("Introduce angulo");
         
       //  while (x!='*'){            //Espera a introducir ángulo y aceptar con *
         //   x=kbd_getc();
            tecla=angulo-48;
            if (x!=0&&x!='*'&&x!='#'){    //Solo se toman los valores numéricos
               //A cada tecla pulsada se desplaza posición decimal y se muestra
               centenas=decenas;
               decenas=unidades;
               unidades=tecla;
               printf(lcd_putc,"\f Angulo = %ld%d%d\n", centenas, decenas, unidades);
               lcd_putc(" * para aceptar");
            }
         }
       
       vangulo=(centenas*100)+(decenas*10)+unidades; 
       if (vangulo>180) vangulo=180;    //No acepta valores >180º
       pwm=(vangulo/13)+7;             //Ajuste modulación en función del valor introducido
       centenas=decenas=unidades=0;   
       
       //Según número de servo introducido se le aplica el ángulo elegido
       switch(servo){
       
       case 1: pwm1=pwm; break;
       case 2: pwm2=pwm; break;
       
       }
       printf(lcd_putc,"\fServo  %d\n", servo);
       printf(lcd_putc," Angulo  %ld", vangulo);
       delay_ms(200);
       presentacion();
      }
   }
```


----------



## hvictorm (Mar 15, 2013)

buenas tardes estoy empezando a programar en pic16f877A o 18f542 y a utilizar el lenguaje c compiler   y hasta el momento e creado varios programas para mover los servos  a 15º,10º y 20º pero no me queda llevo ya 2 meses y no me quedan no se en que estoy mal estos son los códigos que me han funcionado a medias. Espero que alguien me pueda apoyar por favor.

este código lo encontré en internet y lo e modificado muchas veces y no puedo hacer que funcione como lo necesito.

codigo 1:

```
#include <16f877a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#define PIN_SERVO1 PIN_B0
#define PIN_SERVO2 PIN_B1
#define PIN_SERVO3 PIN_B3
const int AJUSTE_FINO_DE_RTCC =  30;
const int ticks_PULSO_MINIMO  =  -105;
const int ticks_PULSO_MEDIO   =  105;
const int ticks_PULSO_MAXIMO  = 155;

int1 flagRTCC     = 0;
int   contRTCC    = 0;
int1 flagSERVO1 = 0;
int   tSERVO1     = ticks_PULSO_MEDIO;
char Keypress   =0x00;

void eco_servos(void);
void ajusta_servo(void);

#int_rda
void rda_isr() {
   Keypress=0x00;
   if(kbhit()){
      Keypress=getc();
   }
}

#int_RTCC
RTCC_isr(){
   ++contRTCC;
   if(contRTCC==4){
      set_TIMER0(AJUSTE_FINO_DE_RTCC);
   }
   if(contRTCC==5){
      flagRTCC=1;
      contRTCC=0x00;
   }
}

void main() {

   int ValTIMER0;

   setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
   enable_interrupts(int_rda);
   enable_interrupts(global);
   printf("
SERVO Commander

" );
   eco_servos();
   set_TIMER0(0);
   enable_interrupts(INT_RTCC);
   do {
      // DISPARO DEL PULSO PWM
      if(flagRTCC==1){
         flagRTCC=0;
         output_high(PIN_SERVO1);
         flagSERVO1=1;    
      }
      // CONTROL DE ANCHO DEL PULSO PWM
      if(flagSERVO1==1){
         valTIMER0 = get_TIMER0();
         if(valTIMER0>tSERVO1){
            flagSERVO1=0;
            output_low(PIN_SERVO1);
         }   
      } 
      // CONTROL DESDE LA RS-232
      if(Keypress!=0x00){
           ajusta_servo();   
         Keypress=0x00;
      }
   } while (TRUE);
}

void ajusta_servo(void){

  switch(Keypress){
    // Periodos Prefijados
    case "1": tSERVO1=ticks_PULSO_MINIMO;
              break;
    case "2": tSERVO1=ticks_PULSO_MEDIO;
              break;
    case "3": tSERVO1=ticks_PULSO_MAXIMO;
              break;
    // Inc Dec Periodo
    case "+": if(++tSERVO1>ticks_PULSO_MAXIMO){
                tSERVO1=ticks_PULSO_MAXIMO;
              }
              break;
    case "-": if(--tSERVO1<ticks_PULSO_MINIMO){
                tSERVO1=ticks_PULSO_MINIMO;
              }
              break;
    // Dame Periodo actual
    case "r": eco_servos();
              break;
  }
}

void eco_servos(void){
   printf("S=%u
",tSERVO1);
}
```
este es otro
codigo 2:


```
#include <16F877A.h>
#use delay(clock=4000000,RESTART_WDT)
#byte port_b=6
#org 0x1F00, 0x1FFF {}//para proteger el código
//del cargador
main()
{
port_b=1;
set_tris_b(0x00); // todo el puerto B como salida
while(1)
{
if(input(PIN_A0))
rotate_left(&port_b,1);
else
rotate_right(&port_b,1);
delay_ms(100);
}
}
```
codigo 3:


```
#include <16f877a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#DEFINE SERVO_1
#DEFINE SERVO_2
#DEFINE SERVO_3
# define BIT0 0b00000001;
 # define BIT1 0b00000010; 
 # define BIT2 0b00000100;
#BYTE PORT_B1=6
#BYTE PORT_B0=6
#BYTE PORT_B2=6
 VOID MAIN()
{
   PORT_B1=BIT1;
PORT_B1=BIT2;
PORT_B1=BIT0;
WHILE(1)
{
IF((PIN_A0))
ROTATE_LEFT(&PORT_B1,1);
ELSE
ROTATE_RIGHT(&PORT_B1,1);
delay_ms(100);
}
}
unsigned long int valor;
void main  (timer1){

set_tris_c(0);
setup_timer_2(T2_DIV_BY_16, 124, 16);// El periodo de la
//señal PWM de 2 ms.
setup_ccp1(CCP_PWM); // Configura CCP1 en modo PWM
valor=125;
set_pwm1_duty(valor);// La anchura del pulso de .5 ms. (CT=
//25%)

}
unsigned long int valor
main void ()
{
set_tris_c(0);
setup_timer_1(T1_DIV1_BY1_14, 110, 14);// El periodo de la
//señal PWM de 2 ms.
setup_ccp2(CCP_PWM); // Configura CCP2 en modo PWM
valor=111;
set_pwm1_duty(valor);// La anchura del pulso de .5 ms. (CT=
//25%)

}
unsigned long int valor;
main (void)
{
set_tris_c(0);
setup_timer_3(T3_DIV_BY_10, 100, 10);// El periodo de la
//señal PWM de 2 ms.
setup_ccp3(CCP_PWM); // Configura CCP3 en modo PWM
valor=101;
set_pwm3_duty(valor);// La anchura del pulso de .5 ms. (CT=
//25%)

}
```


----------



## D@rkbytes (Jun 27, 2015)

@angeldemx No ha ingresado nuevamente al Foro desde 12/05/2012, pero yo puedo responder a tu pregunta.

*setup_timer_0(mode);* Hace referencia a la configuración de Timer 0
Éstos parámetros se encuentran en la ayuda del compilador; PIC C Compiler de CCS.
*RTCC_INTERNAL*. Establece que se usará sincronización de reloj interna.
*RTCC_EXT_L_TO_H*. Establece que se usará sincronización externa por el pin *T0CKI* ("Timer 0 Clock Input")
Y que el evento ocurrirá por flanco de subida (L To H - Low To High - "Rising Edge")
*RTCC_EXT_H_TO_L*. Igual al anterior pero ahora el evento se producirá por flanco de bajada (H To L - High To Low - "Falling Edge")

El siguiente parámetro establece el factor de división para el prescaler y se separa usando el símbolo "*|*"
Puede ser uno de los siguientes:
*RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256*

El número final es el divisor que usará el Timer en el prescaler para ajustarse a la frecuencia de trabajo.

Como complemento a la configuración del Timer 0, se usa: *set_timer0(value);*
En "_*value*_" se especifica el valor con el que se cargará el Timer 0 para obtener la temporización requerida.

Ahora, para que termines de comprender y saber que valores se deben establecer, es necesario que leas la hoja de datos y veas las fórmulas que ahí se exponen para configurar el Timer 0.

Suerte.


----------



## FARFAN21 (Mar 11, 2018)

Hola. ¿Qué tal?
Podrían ayudarme con un programa para controlar 5 servos con un teclado matricial de 4x4 y visualizar los grados del servo en una LCD?

Este es el programa que tengo, he intentado con el PIC18F4550, pero hasta ahorita no he podido lograr que de señal a los servos.

Les dejo es programa.

```
#include <18f4550.h>
#device ICD = TRUE
#device ADC=10            
#use delay (clock=48000000)
#use i2c(Master,Fast=100000, sda=PIN_c6, scl=PIN_c7,force_sw)
#include <i2c_Flex_LCD.h> 
#include <kb4x4.h> //LIBRERIA DE TECLADO
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG,ICSP1 // configura fuses
#zero_ram

#USE FAST_IO(D)
#use standard_io(C)

#byte trisa=0xf90
#byte trisb=0xf91
#byte trisc=0xf92
#byte trisd=0xf93

#byte porta=0xf82
#byte portb=0xf83
#byte portc=0xf84
#byte portd=0xf85

#define use_portb_kbd TRUE     
#define use_portc TRUE       //Configuración puerto b control teclado

#build(reset=0x02000,interrupt=0x02008)
#org 0x0000,0x1FFF {}

#bit  Bit_PWM0 =  PORTD.0              //Bit 0 puerto C Salida modulación 0
#bit  Bit_PWM1 =  PORTD.1              //Bit 1 puerto C Salida modulación 1
#bit  Bit_PWM2 =  PORTD.2              //Bit 2 puerto C Salida modulación 2
#bit  Bit_PWM3 =  PORTD.3              //Bit 3 puerto C Salida modulación 3
#bit  Bit_PWM4 =  PORTD.4              //Bit 4 puerto C Salida modulación 4
#bit  Bit_PWM5 =  PORTD.5              //Bit 5 puerto C Salida modulación 5
#bit  Bit_PWM6 =  PORTD.6              //Bit 6 puerto C Salida modulación 6
#bit  Bit_PWM7 =  PORTD.7              //Bit 7 puerto C Salida modulación 7

/********************** Prototipos de las funciones ***************************/
void main (void);             //función principal
void generacion_pwm (void);   //genera señales moduladas para control de servos
void presentacion (void);     //mensaje de presentación

/********************** Variables para generación PWM *************************/
int8 PWM0=0,PWM1=0,PWM2=0,PWM3=0,PWM4=0,PWM5=0,PWM6=0,PWM7=0; //Valores de las señales PWM
int8 control_PWM=0;
/******************************************************************************/
/******************* FUNCIÓN GENERACIÓN MODULACIONES PWM **********************/
#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;     
      Bit_PWM1=1;
      Bit_PWM2=1;
      Bit_PWM3=1;
      Bit_PWM4=1;
      Bit_PWM5=1;
      Bit_PWM6=1;
      Bit_PWM7=1;
   }
   //Finalizará el pulso de modulación según el valor del correspondiente pwm
   if (control_PWM==PWM0) Bit_PWM0=0;
   if (control_PWM==PWM1) Bit_PWM1=0;
   if (control_PWM==PWM2) Bit_PWM2=0;
   if (control_PWM==PWM3) Bit_PWM3=0;
   if (control_PWM==PWM4) Bit_PWM4=0;
   if (control_PWM==PWM5) Bit_PWM5=0;
   if (control_PWM==PWM6) Bit_PWM6=0;
   if (control_PWM==PWM7) Bit_PWM7=0;

   set_timer0(255);                    //Carga del contador
}

/******************************************************************************/
/************************* PRESENTACIÓN LCD ***********************************/
void presentacion (){
   lcd_clear();  //Clear Display
   printf(LCD_PUTC,"\1%s","Introduce");
   printf(LCD_PUTC,"\2%s"," num. de servo ");
}

/******************************************************************************/
/******************** FUNCIÓN PRINCIPAL ***************************************/
void main(){

  //set_tris_c(0b00000000);  // Configura PIN_C1 como salida

   int x;                        //Valor ASCII de la tecla pulsada
   int tecla;                    //Valor numérico de la tecla pulsada
   int servo;                    //Número de servo
   int16 angulo;                 //Ángulo del servo
   int16 centenas;               //variable para las centenas del ángulo
   int decenas,unidades;         //Variable para las decenas y unidades del ángulo
   int pwm;                      //valor de la modulación por teclado

   set_tris_d(0b00000000);  // Configura PIN_C1 como salida
   trisc=0xf00;                   //Puerto C como salida de datos

   pwm0=7;                      //Impulso de 0,8 msg de pwm0 posición 0º
   pwm1=7;                      //Impulso de 0,8 msg de pwm1 posición 0º
   pwm2=7;                      //Impulso de 0,8 msg de pwm2 posición 0º
   pwm3=7;                      //Impulso de 0,8 msg de pwm3 posición 0º
   pwm4=7;                      //Impulso de 0,8 msg de pwm4 posición 0º
   pwm5=7;                      //Impulso de 0,8 msg de pwm5 posición 0º
   pwm6=7;                      //Impulso de 0,8 msg de pwm6 posición 0º
   pwm7=7;                      //Impulso de 0,8 msg de pwm7 posición 0º

  setup_timer_0(T1_INTERNAL|T0_DIV_32|T0_8_BIT);         //Configuración interrupción generación PWM
   enable_interrupts(INT_TIMER0);    //Habilitación interrupción generación pwm
   enable_interrupts(GLOBAL);        //Habilitación de las interrupciones
   port_b_pullups(TRUE);   //Habilitación resistencias pullups puerto b
  lcd_init();             //Inicialización del lcd
   kbd_init();             //Inicialización del teclado

   presentacion ();        //Muestra mensaje de inicio en lcd

   while (true){

      
      x=kbd_getc();                    //En "x" valor ASCII de la tecla pulsada
      if (x!=0&&x!='9'&&x!='8'&&x!='*'&&x!='#'){ //Si se pulsa tecla numérica 0 a 7 ...
         servo=x-48;            //Valor ASCII se pasa a valor numerico de servo
         printf(lcd_putc,"\fServo = %d\n", servo); //...muestra el valor pulsado
          printf(LCD_PUTC,"\2%s","introduce angulo");

        
         while (x!='*'){            //Espera a introducir ángulo y aceptar con *
            x=kbd_getc();
            tecla=x-48;
            if (x!=0&&x!='*'&&x!='#'){    //Solo se toman los valores numéricos
               //A cada tecla pulsada se desplaza posición decimal y se muestra
               centenas=decenas;
               decenas=unidades;
               unidades=tecla;
               printf(lcd_putc,"\f Angulo = %ld%d%d\n", centenas, decenas, unidades);
                printf(LCD_PUTC,"\2%s","* para aceptar");
            }
         }

       angulo=(centenas*100)+(decenas*10)+unidades;
       if (angulo>180) angulo=180;    //No acepta valores >180º
       pwm=angulo;             //Ajuste modulación en función del valor introducido
       centenas=decenas=unidades=0; 

       //Según número de servo introducido se le aplica el ángulo elegido
       switch(servo){
       case 0: pwm0=pwm; break;
       case 1: pwm1=pwm; break;
       case 2: pwm2=pwm; break;
       case 3: pwm3=pwm; break;
       case 4: pwm4=pwm; break;
       case 5: pwm5=pwm; break;
       case 6: pwm6=pwm; break;
       case 7: pwm7=pwm; break;
       }
       printf(lcd_putc,"\fServo  %d\n", servo);
       printf(lcd_putc," Angulo  %ld", angulo);
       delay_ms(200);
       presentacion();
      }
   }
}
```


----------

