Autor Tema: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC  (Leído 27573 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
(O todo lo que siempre quiso saber sobre el Servo y nunca se atrevió a preguntar)

Pero como decía Jack El Destripador: ¡Vayamos por partes!

Y para empezar un poco de teoria, que a ninguno de nosotros nos va a venir mal. Un Servomotor es un cacharro, entre otros muchos, que puede manejarse inyectándole un señal PWM.

Y si me preguntáis qué es esto os respondo que es un método de control que consiste en enviar un tren de pulsos, cada uno de ellos con un periodo de tiempo en alto, a 5V, y otro en bajo, a 0V; separados cada uno del siguiente un tiempo constante y que podemos variarle la respectivas duraciones que permanece en alto y bajo, o como su propio nombre indica: Pulse Width Modulation, que dicho para entendernos significa Modulación de Ancho de Pulso.

Un servo es un motor controlado por una electronica que lee el PWM y que se encarga de mover al motor dependiendo de lo que ha leído.

El servo, o mejor dicho la electrónica del servo colococa al motor en cada posición dependiendo del tiempo en que el pulso que le inyectamos permanece en alto. Si el tiempo que dura en estado alto dura exactamente 1.5 milisegundos entonces el Servo va y se coloca en el centro de su recorrido, si dura exactamente 0.5 milisegundos el servo retrocede desde el punto medio unos 90º y se coloca en su extremo izquierdo y si, por último, dura exactamente 2.5 milisegundos el servo avanza desde el punto medio unos 90º y se coloca en su extremo derecho. Al tiempo en que permanece en alto un pulso le llamamos Duty Cicle.

Con duraciones intermedias del tiempo en que permanece el pulso en alto, o Duty Cicle, el servo se posiciona en puntos intermedios de su recorrido.

Para que el servo responda correctamente a estos distintos Duty Cicles los pulsos deben llegarle al servo con una periodicidad, o frecuencia constante, uno tras otro, separados 20 milisegundos cada uno uno del siguiente, cada flanco de subida debe estar separado del siguiente flanco de subida los mismos 20 milisegundos; por lo tanto cada ciclo alto-bajo dura siempre exactamente 20 milisegundos y lo que variamos es la relación entre el tiempo que está en alto y en bajo.

Decir que los pulsos estan separados unos de otros 20 milisegundos es exactamente lo mismo que decir que se envían con una frecuencia de 50 Herzios, ya que 50 hz son 50 pulsos por segundo y por lo tanto 1000 milisegundos (que tiene un segundo) dividido entre 50 son exactamente eso: 20 milisegundos. O sea aplicamos la formula f (frecuencia en Herzios) = 1 / t (Periodo en Segundos).

En el fondo todo este asunto no es distinto de encender y apagar nuestro famoso led, que es algo por lo que empezamos todos cuando comenzamos a trastear con los PIC"s, pero controlando muy exactamente los tiempos durante los que que está encendido y apagado.

Esto podemos verlo de forma mas fácil y clara en la imagen esquema siguiente:



Ahora lo que tenemos que hacer es saber cómo podemos controlar estos tiempos en nuestro PIC para poner en alto (disparar el pulso) y en bajo (apagarlo) con la cadencia adecuada, siguiendo la tabla de tiempos descrita mas arriba.

Para ello voy a echar mano del socorrido TIMER0 del PIC que me va a servir de reloj para saber cuándo y durante cuánto tiempo tengo que tener mi pulso en alto. Como soy el mas listo de la clase he elegido un divisor, o preescaler, del TIMER0 de 1:16 (mas adelante os contaré el por qué de este divisor).

Asumiendo que tenemos nuestro PIC funcionando con un cristal de 4.00Mhz entonces el TIMER0 funcionando a 1:16 hace saltar la Interrupción por Desbordamiento de Timer, tambien conocida como RTCC, cada 4.096 milisegundos.

Esto es lo mismo que decir que TIMER0 tarda 4.096 milisegundos en contar desde 0 a 255 y que al llegar a 255 pasar de nuevo a 0 hace saltar la RTCC.

Esto significa que cada paso de contador del TIMER0, a lo que llamamos un tick de reloj, tarda 4.096 / 256 = 0.016 milisegundos. Esto me da una pauta bastante facil de calcular que consiste en que cada 5 RTCC completas tengo 5 * 4.096 = 20.48 milisegundos que es un poco más de lo que necesito, que son 20 milisegundos exactos:

Esto lo podemos conseguir contando 4 RTC"s completas, a 4.096 milisegundos cada una, y otra más un poco mas corta. No podemos hacer que la RTCC se acabe antes de la cuenta, pero si que podemos, y es lo que vamos a hacer, que empiece a contar un poco mas tarde, que no empiece a contar desde 0 sino desde 30: esto se explica porque 30 * 0.016 = 0.48 milisegundos menos que va contar esta última RTCC, al haber empezado desde un valor de 30 en lugar de 0, luego 4.096 - 0.48 = 3.616 milisegundos para la última RTCC.

Concluyendo: tengo 4 RTCC"s completas a 4.096 milisegundos y una capada a 3.616 luego 4 * 4.096 + 3.616 = 20 milisegundos. Lo que realmente voy a hacer es contar 1 RTC completa, 2 RTCC completas, 3 RTCC completas, 4 RTCC completas yy pongo el contador de TIMER0 a 30, y por fin 5 RTCC completas luego ya han pasado 20 milisegundos exactamente. Ya tenemos fijada la frecuencia que necesitamos.

A estas 5 RTCC"s les llamo flagRTCC que sólo voy a activar cuando se completen las 5 RTCC"s (4 completas y otra mas incompleta).

Además sabiendo que cada tick de reloj ocupa 0.016 milisegundos podemos traducir los tiempos de anchos de pulsos descritos anteriormente en ticks de nuetro reloj particular: así 0.5 milisegundos son lo mismo que esperar 31 ticks de reloj, 1.5 milisegundos equivalen a 93 ticks de reloj y 2.5 milisegundos son 155 ticks de reloj. (Recordad que llamamos tick de reloj al tiempo que tarda TIMER0 en contar 1 más).

La imagen anterior podemos ahora convertirla en esta siguiente en la que hemos cambiado los tiempos por RTCC"s y Ticks:



Como vemos en el cronograma superior: cada vez que se produce un super RTCC, de 4 RTC"s y pico a la que llamamos flagRTCC, ponemos en alto el PIN de la señal del Servo, debemos recordar que esto siempre va a ocurrir en el tránsito del contador TIMER0 entre los valores de 255 y 0, por lo que flagRTCC siempre va a coincidir con TIMER0=0.

Ahora entonces solo debemos esperar el número suficiente de ticks para volver a poner nuestro pin a bajo. Si deseamos que el Servo se posicione en su centro debemos mantener el PIN en alto durante 93 ticks de TIMER0 o, lo que es lo mismo, esperar 1.5 milisegundos para bajar el pulso.

La secuencia queda entonces de la siguiente manera:

- RTCC corre alocadamente, una tras otra, dedicandose exclusivamente a contar cuántas de ellas han pasado; si es la cuarta pone TIMER0 a 30 para que la quinta sea mas corta, si es la quinta pone en alto flagRTCC para lo que sea necesario y comienza de nuevo.

- En el programa principal detectamos que flagRTCC se ha activado así que lo desactivamos y ponemos en alto el PIN y marcamos, con flagSERVO1, que acabamos de activarlo.

- A continuación, y siempre que flagSERVO1 esté activado, comprobamos el valor de TIMER0 que si es mayor que el que deseamos, en nuestro caso 93, y cuando lo alcancemos ponemos a bajo el PIN y lo marcamos desactivando flagSERVO1. Y hemos acabado.

Cada 20 milisegundos activamos el pulso, y transcurridos 1.5 milisegundos lo desactivamos, que es exactamente lo que queríamos hacer.

El valor de TIMER0, con el comparamos para controlar la duración de cada pulso, la tenemos guardada en tSERVO1, que inicialmente cargamos con el número de ticks necesarios para colocar el Servo en su punto medio, ticks_PULSO_MEDIO. El valor de tSERVO1 lo podemos cambiar dinámicamente mediante la recepción de comandos a traves de la RS232.

De esta forma con los comandos "1", "2" y "3" podemos cambiar el valor de tSERVO1 a ticks_PULSO_MINIMO, ticks_PULSO_MEDIO y ticks_PULSO_MAXIMO respectivamente; y con los comandos "+" y "-" vamos incrementando o decrementando su valor. Con "r" le pedimos al PIC que nos envíe su valor actual.

Ahora solo nos quedaría implementar todo esto en un programa en C que queda de la siguiente forma:

<span class="texto_mini">Codigo:</span>[hr /
]

// servo_pwm_232

// Ejemplo con un servo FUTABA S3003
// Alimentación y pulsos a 5V
// Cuadro de Tiempos :
//    Periodo 20 ms (Frecuencia 50 Hz)
//    Ancho Pulso minimo 0.5 ms
//    Ancho pulso medio  1.5 ms
//    Ancho pulso maximo 2.5 ms
//    TMR0 a 1:16 -> 1 RTCC cada 4.096 ms
//                -> 1 Tick cada 0.096 / 256 = 0.016 ms
//                -> 20 ms = (4 x RTCC completas) + (1 * RTCC - 30 ticks)
//    Ancho Pulso minimo 0.5 ms ->  31 ticks de TMR0
//    Ancho pulso medio  1.5 ms ->  93 ticks de TMR0
//    Ancho pulso maximo 2.5 ms -> 155 ticks de TMR0

#include <16f876a.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

const int AJUSTE_FINO_DE_RTCC =  30;
const int ticks_PULSO_MINIMO  =  31;
const int ticks_PULSO_MEDIO   =  93;
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);
}




Descargar código <a href="http://picmania.garcia-cuervo.net/recursos/__servo_pwm_232.c" target="_blank">aqui[/url]

Como podéis ver en el comentario inicial del código, todo esto está montado para la familia de servos compatibles FUTABA S3003, HiTec HS-300 CW, HOBBICO COMMAND CS-51,   que son de los mas usados por los aficionados al Radiocontrol.

Para ajustar este código a otros servos solo hay que calcular el preescaler y los ticks necesarios para ajustarse a las caracteristicas de éste. Hay servos que funcionan a 400hz en lugar de 50hz y con anchos de pulso ligeramente distintos a los utilizados aquí. Es normal anchos de pulso en los extremos de 1.00 y 2.00 milisegundos respectivamente. El punto medio en 1.5 milisegundos es muy común.

Otro corolario de este ejemplito estriba en la posibilidad de manjear varios servos. Utilizando la misma estructura de PIN_SERVO1 y tSERVO1 podemos habilitar el control indistinto de tantos servos como deseemos, teniendo así PIN_SERVO2 y tSERVO2, PIN_SERVO3 y tSERVO3 ... etc controlando cada uno de ellos de forma absolutamente similar.

Espero que os guste.




P.D. Muchas gracias al amigo <a href="http://miarroba.com/foros/perfil.php?foroid=6510&id=1594220" target="_blank">dogflu[/url] por sus inteligentes y acertadas observaciones sobre la redaccion de este ejemplito.


« Última modificación: 03 de Noviembre de 2012, 07:08:44 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17482
    • MicroPIC
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #1 en: 15 de Enero de 2006, 01:51:00 »
Deberías escribir un libro llamado "Programación PIC para torpes"
Con tus explicaciones es imposible no entenderlo.
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado tougteno

  • PIC10
  • *
  • Mensajes: 31
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #2 en: 17 de Enero de 2006, 14:34:00 »
Que buena explicación RedPic! La veradad es que no tenia intensiones de leerlo, pero la corriente me fue llevandoGiño

Desconectado JRpropo

  • PIC10
  • *
  • Mensajes: 21
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #3 en: 28 de Febrero de 2006, 09:57:00 »
Hola Redpic,

MUY BUENA tu pagina WEB.
Estaba analizando como se pueden controlar varios servos con tu programa, pero de insertar mas rutinas para mas de un servo se rompería la concepción de 20mseg de frame para cada servo. Como modificarías tu programa para lograr al menos incluir 4 servos ?

También estoy un poco confundido cuando dices "El TIMER0 funcionando a 1:16 hace saltar la Interrupción por Desbordamiento de Timer, también conocida como RTCC, cada 4.096 milisegundos". Como sacas esta cuenta si el cristal es de 4MHz ?

Gracias,
JRpropo

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #4 en: 28 de Febrero de 2006, 10:09:00 »
Inicio del artículo de mi página Los Cristales y El Tiempo:

Cálculo de tiempos según el Cristal oscilador que usamos

   En la sección El Rincón del C dedicábamos un artículo al uso de la Interrupción RTCC, en el que mostrábamos una tabla de tiempos que tardaba el TIMER0 en dar una vuelta de manivela completa, que dependía del Preescaler seleccionado. Está tabla de tiempos adjuntaba como nota que el Cristal oscilador utilizado era de 4 Mhz.
 
 
   Sin embargo soy capaz de imaginar a cualquiera de vosotros, amables Picmaníacos, con los ojos cerrados metiendo la mano en vuestro saco de cristales. Sacando uno al azar. La probabilidad de que dicho cristal sea de 4 Mhz es calculable. Es directamente proporcional al numero de cristales de 4 Mhz que haya en vuestro saco e inversamente proporcional al número de otros tipos de cristales que tengáis en tan heterogénea mezcla. Una pequeña locura.
 
 
   ¿Que hacemos, entonces, si vais a utilizar un cristal cuyo valor este alejado, o muy alejado, de nuestros 4 Mhz de referencia? Pues fácil y sencillo como juego de chiquillo: Calculamos el Tiempo de RTCC en función del Cristal que vamos a usar, o sea el tema de este artículo.
 
 
   La primera fórmula que vamos a ver nos da el Tiempo que tarda RTCC en dispararse, sin Preescaler, comenzando TIMER0 en 00h y terminando en FFh, o sea desbordamiento completo:
 
 
Time = (256 * 4) / FOSC  (1)
 
donde Time es el tiempo en segundos (S) que tarda RTCC en saltar y FOSC es la frecuencia de oscilación de nuestro cristal en Hercios (Hz)
 
continúa ...

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #5 en: 28 de Febrero de 2006, 10:23:00 »
Para dos servos, por ejemplo, solo tienes que duplicar donde corresponda todo lo que aparezca con la palabra SERVO1 ...

Codigo:


...

#define PIN_SERVO1 PIN_B0
#define PIN_SERVO2 PIN_B1

...

int1 flagSERVO1 = 0;
int   tSERVO1     = ticks_PULSO_MEDIO;
int1 flagSERVO2 = 0;
int   tSERVO2     = ticks_PULSO_MEDIO;
...

      // DISPARO DEL PULSO PWM
      if(flagRTCC==1){
         flagRTCC=0;
         output_high(PIN_SERVO1);
         flagSERVO1=1;    
         output_high(PIN_SERVO2);
         flagSERVO2=1;    
      }
      // CONTROL DE ANCHO DEL PULSO PWM
      if(flagSERVO1==1){
         valTIMER0 = get_TIMER0();
         if(valTIMER0>tSERVO1){
            flagSERVO1=0;
            output_low(PIN_SERVO1);
         }  
      if(flagSERVO2==1){
         valTIMER0 = get_TIMER0();
         if(valTIMER0>tSERVO2){
            flagSERVO2=0;
            output_low(PIN_SERVO2);
         }  
      }

...

    // 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;
    case "a": tSERVO2=ticks_PULSO_MINIMO;
              break;
    case "b": tSERVO2=ticks_PULSO_MEDIO;
              break;
    case "c": tSERVO2=ticks_PULSO_MAXIMO;
              break;
    // Inc Dec Periodo
    case "m": if(++tSERVO2>ticks_PULSO_MAXIMO){
                tSERVO2=ticks_PULSO_MAXIMO;
              }
              break;
    case "n": if(--tSERVO2<ticks_PULSO_MINIMO){
                tSERVO2=ticks_PULSO_MINIMO;
              }
              break;

...

void eco_servos(void){
   printf("S1=%u S2=%u
",tSERVO1,tSERVO2);
}




Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado elesep

  • Colaborador
  • PIC10
  • *****
  • Mensajes: 42
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #6 en: 28 de Febrero de 2006, 23:22:00 »

Muy Bien explicado estoy seguro que va a ser de mucha ayuda para las personas que recien empiezan, y que puedan entender con facilidad, Ya que esta muy bien redactado.

Muy buen aporte

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #7 en: 01 de Marzo de 2006, 10:32:00 »
Gracias elesep por tus palabras de ánimo. Son la gasolina que mueve este motor. Rebotado

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Ojosdeluna

  • PIC10
  • *
  • Mensajes: 5
RE: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #8 en: 09 de Marzo de 2006, 03:21:00 »
Hola ! Sonrisa

      La explicacion que dio Redpic con los servos salvo mi proyecto de empezar con el pie inzquierdo mucahs gracias Sonrisa

     Sin embargo la parte donde dices el ciclo de trabajo y ello me dio la ideaRollEyes de poque no utilizar un PWM como el TL494 para controlar el ciclo de trabajo a una frecuencia dada por :
                                   fosc=1.1/RC
                          haciendo fosc=1/T tenemos que f=50 hz
                          y proponiendo .1microF tenemor una R de 220K
                          perfectamente  comercial si se desea ajustar.

     Asi tenemos una frecuencia constante y para variar los ciclos de trabajo podriamos utilizar un pic y un adc por resistencias, esto con el objetivo de que el programa del pic pueda ocuparse de otros mandos e instrucciones y solo escribir en un puerto la posicion, si el puerto se ocupada para otras cosas pues solo hacer una rutina para controlar un latch D o dispositivo a fin que almacene la posicion.

     Ocuparia mas espacio tal ves en una placa, pero podria entonces ocuparme de otras ciclos para hacer un programa tal ves mas complejo o que se ocupe de sensores o "x"  y dejar que la pocision dada en el latch lo haga de forma automatica no? Bueno es una idea jejejeAvergonzado

      Ahora dos preguntitas para redpic, el servo cambia de posicion a la izquierda al aplicarle pulsos de 1.5 ms 90 grados, pero 90 grados de su posicion actual (puede ke sea izquierda o derecha) o desde su posicion central? Y si ya llego a su pocicion digamos Izquierda y sigo aplicando los pulsos este seguira intentando llegar a la izquierda o se queda en esa posición?Rebotado

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #9 en: 05 de Noviembre de 2006, 09:41:34 »
Tal como ha descubierto el amigo Aitopes hay un error de transcripción en el código fuente de este ejemplo.

Pongo a continuación el código original:

Código: C
  1. // servo_pwm_232
  2.  
  3. // Ejemplo con un servo FUTABA S3003
  4. // Alimentación y pulsos a 5V
  5.  
  6. // Cuadro de Tiempos :
  7.  
  8. //    Periodo 20 ms (Frecuencia 50 Hz)
  9. //    Ancho Pulso minimo 0.5 ms
  10. //    Ancho pulso medio  1.5 ms
  11. //    Ancho pulso maximo 2.5 ms
  12.  
  13. //    TMR0 a 1:16 -> 1 RTCC cada 4.096 ms
  14. //                -> 1 Tick cada 0.096 / 256 = 0.016 ms
  15. //                -> 20 ms = (4 x RTCC completas) + (1 * RTCC - 30 ticks)
  16.  
  17. //    Ancho Pulso minimo 0.5 ms ->  31 ticks de TMR0
  18. //    Ancho pulso medio  1.5 ms ->  93 ticks de TMR0
  19. //    Ancho pulso maximo 2.5 ms -> 155 ticks de TMR0
  20.  
  21.  
  22. #include <16f876a.h>
  23. #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
  24. #use delay(clock=4000000)
  25. #use standard_io(b)
  26. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
  27.  
  28. #define PIN_SERVO1 PIN_B0
  29.  
  30. const int AJUSTE_FINO_DE_RTCC =  30;
  31. const int ticks_PULSO_MINIMO  =  31;
  32. const int ticks_PULSO_MEDIO   =  93;
  33. const int ticks_PULSO_MAXIMO  = 155;
  34.  
  35. int1 flagRTCC   = 0;
  36. int  contRTCC   = 0;
  37. int1 flagSERVO1 = 0;
  38. int  tSERVO1    = ticks_PULSO_MEDIO;
  39.  
  40. char Keypress=0x00;
  41.  
  42. void eco_servos(void);
  43.  
  44. #int_rda
  45. void rda_isr() {
  46.  
  47.    Keypress=0x00;
  48.    if(kbhit()){
  49.       Keypress=getc();
  50.    }
  51. }
  52.  
  53. #int_RTCC
  54. RTCC_isr(){
  55.  
  56.    ++contRTCC;
  57.    if(contRTCC==4){
  58.       set_TIMER0(AJUSTE_FINO_DE_RTCC);
  59.    }
  60.    if(contRTCC==5){
  61.       flagRTCC=1;
  62.       contRTCC=0x00;
  63.    }
  64. }
  65.  
  66. void main() {
  67.  
  68.    int ValTIMER0;
  69.  
  70.    setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
  71.  
  72.    enable_interrupts(int_rda);
  73.    enable_interrupts(global);
  74.  
  75.  
  76.    printf("\r\n\SERVO Commander\r\n\r\n");
  77.    eco_servos();
  78.  
  79.    set_TIMER0(0);
  80.  
  81.    enable_interrupts(INT_RTCC);
  82.  
  83.  
  84.    do {
  85.    
  86.       // DISPARO DEL PULSO PWM
  87.  
  88.       if(flagRTCC==1){
  89.          flagRTCC=0;
  90.          output_high(PIN_SERVO1);
  91.          flagSERVO1=1;    
  92.       }
  93.  
  94.       // CONTROL DE ANCHO DEL PULSO PWM
  95.       if(flagSERVO1==1){
  96.          valTIMER0 = get_TIMER0();
  97.          if(valTIMER0>tSERVO1){
  98.             flagSERVO1=0;
  99.             output_low(PIN_SERVO1);
  100.          }  
  101.       }
  102.    
  103.       // CONTROL DESDE LA RS-232
  104.      
  105.       if(Keypress!=0x00){
  106.          switch(Keypress){
  107.             // Periodos Prefijados
  108.  
  109.             case '1': tSERVO1=ticks_PULSO_MINIMO;
  110.                       break;
  111.             case '2': tSERVO1=ticks_PULSO_MEDIO;
  112.                       break;
  113.             case '3': tSERVO1=ticks_PULSO_MAXIMO;
  114.                       break;
  115.             case '+': if(++tSERVO1>ticks_PULSO_MAXIMO){
  116.                         tSERVO1=ticks_PULSO_MAXIMO;
  117.                       }
  118.                       break;
  119.             case '-': if(--tSERVO1<ticks_PULSO_MINIMO){
  120.                         tSERVO1=ticks_PULSO_MINIMO;
  121.                       }
  122.                       break;
  123.             case 'r': eco_servos();
  124.                       break;
  125.         }
  126.          
  127.          Keypress=0x00;
  128.       }
  129.  
  130.  
  131.    } while (TRUE);
  132.  
  133. }
  134.  
  135. void eco_servos(void){
  136.    printf("S=%u\r\n",tSERVO1);
  137. }
  138.  

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1796
    • IDEAA
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #10 en: 19 de Marzo de 2007, 15:27:38 »
Código: [Seleccionar]
   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);
         }   
      }
      }
   } while (TRUE);

estoy iniciandome con los servos y me base en esta rutina para hacer funcionar uno, pero sin haberlo llevado a la practica encuentro algo que no se si ira bien. en el bucle infinito, los primeros 20ms de funcionamiento no ocurrira nada, ya que flagRTCC es 0 y flagServo1 tambien, entonces no entrara en ninguno de los dos IF hasta que no ocurran 5 desbordamientos. esta claro que para esta aplicacion en concreto esto no plantea un problema, pero para otras cosas tal vez seria mejor declarar
Código: [Seleccionar]
int1 flagRTCC = 1asi el servo comenzara a moverse desde el primer ms, no? :-)

por cierto, un servo al que se le esta enviando constantemente un pulso igual al anterior, osea, se le dice que se mantenga quieto donde esta, y que no tiene nada que haga fuerza para quitarlo del sitio, tiene mucho consumo? porque por este motivo me planteo encender un servo solo cuando lo tengo que mover. y si no se le envia señal alguna, pero tiene Vcc? consume?
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1796
    • IDEAA
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #11 en: 29 de Marzo de 2007, 17:27:58 »
otra vez yo estoy molestando con el tema de los servos, aunque nadie me responda...  :(
me estaba preguntando yo, porque esperar al 5º rtcc para quitarle los ms que sobran si se le pueden quitar a todos los rtcc lo mismo sin tener que comprobar si estamos en la 4º rtcc o cosas asi...
lo que digo es que si queremos 20ms, simplemente contamos 5 rtcc de 4ms (en vez de 4 de 4.096ms y 1 de 3.616ms).
entonces en vez de sacarle 30 a la ultima habria que sacarle (30 ticks / 5 rtcc) 6 ticks de reloj a cada rtcc, que nos coincide casualmente para que las rtcc se produzcan cada 4ms EXACTOS  :mrgreen:

Código: [Seleccionar]
#int_RTCC
void RTCC_isr(void){

   contRTCC = contRTCC + 1;
   set_TIMER0(6);    //en vez de 6 podemos poner "ajuste_fino_RTCC" y declararlo como constante arriba... No te lo tomes a mal RedPic, es broma  :-)

   if(contRTCC==5){
      flag5RTCC=1;
      contRTCC=0;
   }
}

ahora, para que todo siga funcionando correctamente habria que hacer una pequeña modificacion que es:

Código: [Seleccionar]
valTIMER0 = get_TIMER0() - 6;
es decir, cuando necesitamos saber por que tick esta el timer le restamos los 6 ticks que le sumamos antes.
lo admito, es probable que muchos piensen que soy medio gilip.... o cosas asi por estar dandole vueltas a algo que ya esta solucionado, pero es que me gusta que las cosas sean redondas, simetricas, simples y etc...  :D
salu2 y espero que haya alguien que no piense que realmente soy $x#!&? y esto le resulte util
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #12 en: 30 de Marzo de 2007, 08:05:21 »
Querido Marttyn:

1º.- No molestas con este tema de los servos, ni con cualquier otro parecido siempre y cuando tenga que ver con la temática de este foro.  :mrgreen:

2º.- El que te respondan o no es como el tiempo meteorológico, unas veces llueve, otras hace sol y aún otras ocurren las dos cosas al mismo tiempo. Hay veces que un hilo se llena de post en segundos y otras que duerme el sueño de los justos durante meses. He vivido ambas situaciones y se lo que se siente cuando nadie te hace caso. Ten paciencia y discúlpalos, discúlpanos, por no atender todos los hilos, hay veces que no podemos o no queremos  entrar en todos los temas.  :mrgreen:

3º.- El tema de este hilo es un "Ejemplito". Así en diminutivo, escrito para ejemplificar cómo se podría controlar un servo con un PIC, no intentan sentar cátedra de cómo manejar un servo con un PIC. Imagino que habrá tantas formas como amigos se pongan a hacerlo, y la mayoría de ellas serán mas sólidas, eficaces, seguras y controladas que ésta que yo propuse en su día.  :mrgreen:

4º.- Este hilo en concreto lo abrí  cuando aún era un bisoño en esto de los PIC's y me propuse con ellos aprender y publicar lo que iba aprendiendo para que otros pudiesen compartir mis experiencias. Estoy seguro de que si hoy lo hiciese de nuevo lo haría de forma muy distinta. En aquel momento simplemente no sabía muy bien lo que estaba haciendo. Aunque funcionaba.  :mrgreen:

5º.- Estoy seguro que lo que planteas es cierto y supone una mejora sustancial a lo que yo hice en su día, te lo agradezco y considero que los amigos visitantes a partir de los post que has realizado tendrán un mejor conocimiento de qué hacer y cómo si desean controlar un servo desde un PIC.  :mrgreen:

6º.- Ya me ha salido otra de mis novelas. En vez de decirte: "Sí, Gracias" me tiro a explicarte todas las circunstancias ... y tal ... y tal ...  :mrgreen:

Venga. Continuamos.
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1796
    • IDEAA
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #13 en: 01 de Abril de 2007, 21:06:19 »
redpic lo que dije sobre que nadie hacia caso a mis post era por decir algo... realmente no me importaba. de hecho puse el post aun sabiendo que probablemente nadie me fuera a responder... al fin y al cabo era un hilo que se podia considerar "cerrado"
si alguien alguna vez quiere trabajar con servos, es de parada obligada este ejemplito tuyo. y el objetivo de mis posts es que alguno de esos curiosos que aprende de tu sabiduria pues tambien pueda aprender algo de mis pequeñas experiencias, que no son ni muy extensas ni muy elaboradas, pero que pueden aportar algo...  :-)
un saludo
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5388
    • Picmania by Redraven
Re: Ejemplito 16F876A: Controlando un SERVO con el PIC desde nuestro PC
« Respuesta #14 en: 02 de Abril de 2007, 02:34:03 »
Claro que sí Marttyn.   :P

Y de nuevo te agradezco tus aportes. Y si te parece bien podrías montar un post con el ejemplo completo que incluya tus correcciones y avances. Así nuestros amigos y visitantes tendrían disponible mas "jugo de cerebro" disponible.

Esto es lo que me gusta del foro, que es una cosa compartida, que entre todos hacemos que crezca día a día.  :)

Un saludo.


Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania


 

anything