# Control de servomotor por puerto serie.



## Adolfoe (Jul 17, 2009)

Estoy haciendo un programa para un Ball & Beam con webcam
todo el procesamiento de los datos se hace desde el PC y se envía por el puerto serie a 9600bauds con  intervalos de aprox. 29ms.

El programa de la pc le envía al PIC un string indicandole el valor en us que debe permanecer en alto el PWM y el caracter "/" como indicador del fin. ej
"1600/" indica 1600us.

El pic usa la instruccion atof para convertir el string a un valor y luego simplemente usa timers para generar el pwm a 50Hz.

Cuando yo envío pocos datos de manera manual  al PIC el programa funciona bien, pero cuando conecto el programa en c++ para que envíe los datos de forma automática. El servomotor comienza a vibrar, es decir funciona pero da muchos saltos.

Observando el PWM en el osciloscopio se ve que el PWM en ocasiones se vuelve inestable y cuenta a valores mas allá de los limites definidos

Yo sospecho que esto se debe a que en ocasiones la interrupción del TIMER genera conflictos con la interrupción del puerto serie RDA

voy a añadir el codigo esta den CCS C.

Espero que me puedan ayudar, o en su defecto sugerirme algun código mas adecuado para controlar el servo por RS-232. Gracias.


```
#include "pwm_timers.h"
#include <stdlib.h>
//Byte de configuracion del TIMER 1
#byte t1con=0x10
#byte tmr1l=0x0e
#byte tmr1h=0x0f


//Variables globales para la recepcion de datos por rs-232
int16 duty_new;
char dato[5];//variable con los caracteres ascii
int i; //contador de datos
int rec;//rec indica que se ha recibido un nuevo dato;

//Variables globales para generar el PWM
int16 dutyl,dutyh;
int flag;//bandera para indicar en que parte del ciclo se encuentra, en el alto o en el bajo

#int_RDA
void  RDA_isr(void) 
{ dato[i]=getc();
  i++;
  if(dato[i-1]==0x2f){
      dato[i-1]=0x00;
      duty_new=atof(dato);
      dutyl=65536-duty_new;
      dutyh=45536+duty_new;
      for(i=0;i<5;i++) dato[i]=0;
      i=0;
//      rec=1;//bandera de recibido
  }
}

#int_TIMER1
void  TIMER1_isr(void) 
{  t1con=t1con&0b11111110;//apaga el timer1
   output_toggle(PIN_A2);
   if(flag==0){ 
      set_timer1(dutyh);
      enable_interrupts(INT_RDA);
   }
   if(flag==1){ 
      set_timer1(dutyl);
      disable_interrupts(INT_RDA);
   }
   flag=!flag;
   t1con=t1con|0x01;//encender el timer1
}
```


----------



## karl (Jul 17, 2009)

hola!

no se programar pics en C, pero se algo sobre las rutinas de interrupción, cuando el pic llama a una interrupción, apaga la bandera que controla el hacerle caso a las mismas, con lo que si se genera un llamado secundario (como mencionas), en el que se acabe el tiempo para mantener alto la salida del servo por ejemplo, el PIC lo va a ignorar, y cuando terminas tu rutina, regresa al modo inicial y vuelve a entrar en la interrupcion, ahora por el timer.

Te sugeriria que escogieras un compromiso, por ejemplo, implementar la rutina de transmisión por software y la rutina de control de servos por firmware, de esa forma puedes ignorar los comandos cuando tengas que apagar el servo, o que añadas una rutina de "enable" a tu computadora y tu PIC, de tal forma que cuando el PIC tenga que controlar al servo bloquee la transmisión de la computadora.


----------

