Control de 8 servos con PIC

Este proyecto consiste en el control de 8 servos por el puerto c del pic. En la interacción para el control de los servos se emplea un teclado numérico y un lcd, ambos controlados por el puero b del PIC.
Esquema control 8 servos con pic

En su funcionamiento, el pic pide introducir el número del servo a controlar. Posteriormente solicita el ángulo de orientación deseado para ese servo ( de 0º a 180º). El valor se acepta con la tecla “*” y el programa vuelve a mostrar un mensaje de presentación para un nuevo control. Si el ángulo introducido es superior a 180º, el pic toma por defecto 180º.
Para la generación de las señales moduladas de control de los servos (bit_pwmx), se emplea la subrutina de interrupción por rebose del timer 0. La orientación de cada servo se establece con el valor que se carga en la variable pwmx, donde x es el número de servo correspondiente. Con cada llamada a la subrutina de generación de la señal por mediación de la interrupción del timer 0, se incrementa la variable control_pwm que comparandose con el valor en pwmx, decide si debe o no cortar alguno de los pulsos de modulación de los servos.



   control_pwm++;   
        
   if (control_pwm==0) bit_pwm0=1; 
   if (control_pwm==pwm0) bit_pwm0=0; 
 
Cuando la variable control_pwm, incrementandose en cada rebose del timer0, llega a su máximo valor y pasa a ser 0, todas las señales moduladas comienzan un nuevo ciclo.

Gráficas control servos con pic

Para interpretar los valores numéricos de varias cifras a partir de números simples introducidos por teclado, primero espera a que se pulse una tecla
x=kbd_getc();
el valor obtenido está en codificación ASCII por lo que habrá que pasarlo a su valor numérico decimal
tecla=x-48;
si se ha pulsado una tecla se descartan las pulsaciones en # y * puesto que solo se necesitan números
if (x!=0&&x!='*'&&x!='#'){
y conforme se van pulsando números el último pulsado será las unidades y los anteriores van pasando a decenas y centenas
centenas=decenas;
decenas=unidades;
unidades=tecla;
conforme se van introduciendo números simples se va mostrando el número completo por pantalla lcd
printf(lcd_putc,"\f Angulo = %ld%d%d\n", centenas, decenas, unidades);
y finalmente se guarda en una única variable el número completo resultante de todos los números simples
angulo=(centenas*100)+(decenas*10)+unidades;


////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                    CONTROL DE 8 SERVOS CON PIC   //
//                                                                            //
//                         (c) RobotyPic                               //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#include <16f876a.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
#include <kbd.c>                       //archivo para control del teclado

#bit  Bit_PWM0 =  PORTC.0              //Bit 0 puerto C Salida modulación 0
#bit  Bit_PWM1 =  PORTC.1              //Bit 1 puerto C Salida modulación 1
#bit  Bit_PWM2 =  PORTC.2              //Bit 2 puerto C Salida modulación 2
#bit  Bit_PWM3 =  PORTC.3              //Bit 3 puerto C Salida modulación 3
#bit  Bit_PWM4 =  PORTC.4              //Bit 4 puerto C Salida modulación 4
#bit  Bit_PWM5 =  PORTC.5              //Bit 5 puerto C Salida modulación 5
#bit  Bit_PWM6 =  PORTC.6              //Bit 6 puerto C Salida modulación 6
#bit  Bit_PWM7 =  PORTC.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_putc("\f   Introduce   \n");
   lcd_putc(" num. de servo ");
}

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

void main(){

   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
 
   trisc=0x00;                   //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(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){
    
      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
         lcd_putc("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);
               lcd_putc(" * para aceptar");
            }
         }
    
       angulo=(centenas*100)+(decenas*10)+unidades;
       if (angulo>180) angulo=180;    //No acepta valores >180º
       pwm=(angulo/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 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();
      }
   }
}

En la simulación bajo proteus se comprueba el cambio en el tiempo de las señales de control de los servos individualmente en función del valor del ángulo introducido.