TODOPIC

Mecatrónica => Robótica => Mensaje iniciado por: Marttyn en 08 de Mayo de 2007, 00:22:52

Título: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 08 de Mayo de 2007, 00:22:52
me he basado en el codigo de redpic para controlar un servo (PWM por soft) con un potenciometro...
el codigo funciona, lo he publicado en la seccion de lenguaje C, pero el fallo es que el servo no se queda quieto cuando no estoy tocando el potenciometro
me he metido en esta seccion porque supongo que aqui estareis los grandes "sabedores" de este tema y podreis ayudarme mejor...
el codigo es muy simple, es este:
Código: [Seleccionar]
//--- Constantes ---
#define SERVO        PIN_A0   //linea de control por PWM para el servo

#define ADC          1        //canal adc que se usa para los ojos
//------------------

#use delay(clock=4000000)
#use standard_io(a)

//--- Variables ---
int1 flag5RTCC = TRUE;           //indica si se completaron 5 RTCC
int1 flag50mS = FALSE;           //indica si ocurrio interrupcion de timer1
int1 flagPulso_Alto = FALSE;
int8 Posicion = 93;         //donde se posiciona el servo segun la lectura del adc
int8 ContRTCC = 0;               //contador de RTCC
//-----------------

//--- Funciones ---
void Calcular_Posicion_Ojos(void);
//-----------------

#int_TIMER0
void TIMER0_isr(void){        //timer que cuenta 20mS
//Timer de 8 bits --> 256 = 1 RTCC
//Pescaler de 1:16
//1 tick cada 16 uS = 0.016mS
//1 RTCC cada 4.0mS (256 - 6 Ticks)
//5 RTCC = 20mS

   ContRTCC = ContRTCC + 1;
   set_TIMER0(6);

   if(ContRTCC == 5){
      flag5RTCC = TRUE;
      ContRTCC=0;
   }
}

#int_TIMER1
void TIMER1_isr(void) {       //timer que cuenta 50mS
//Timer de 16 bits --> 65536 = 1 RTCC
//Pescaler de 1:1
//1 tick cada 1 uS
//1 RTCC cada 50mS (65536 - 15536 Ticks)

   set_TIMER1(31072);
   flag50mS = TRUE;
}

void main(void) {
   int8 ValTMR0;

   //configuracion del PIC
   
   set_adc_channel(ADC);

do {


//>-----------------------Movimiento del servo--------------------------------->

      //--- Calcula posicion servo segun lectura adc ---
      if(flag50mS == TRUE){
         Calcular_Posicion();
         flag50mS = FALSE;
      }
      //------------------------------------------------
     
      //--- Dispara pulso PWM cuando se completan 5 RTCC ---
      if(flag5RTCC == TRUE){
         flag5RTCC = FALSE;
         output_high(SERVO);
         flagPulso_Alto = TRUE;
      }
      //----------------------------------------------------
     
      //--- Baja pulso PWM cuando corresponda ---
      valTMR0 = get_TIMER0() - 6;
     
      if((flagPulso_Alto == TRUE) && (valTMR0 > Posicion)){  //baja el pulso en el tiempo correspondiente a Posicion
         output_low(SERVO);
         flagPulso_Alto = FALSE;
      }
      //-----------------------------------------

//<----------------------------------------------------------------------------<

} while(true);
}

void Calcular_Posicion(void){
   int16 ValorADC;
   ValorADC = read_adc();
   Posicion = 31 + (int16)((int16)(ValorADC * 124) / 255);
}

no he puesto la configuracion de mi pic porque vale cualquiera que tenga dos timers... yo personalmente uso el 12F683 para mover un servo o el 16F88 para mover 2 servos

supongo que la respuesta a mi problema debe ser generar PWM por soft, que al haber interrupciones mas lo que demora en ejecutarse cada instruccion hace que el PWM no sea de 50hz exactos y eso provoque el  tambaleo constante...
se puede solucionar?
incluso mejor, hay algun integrado que se encargue de controlar servos y pueda ser manejado con un microcontrolador?
no es que necesite presicion con esto... pero el servo moviendose constantemente lo unico que hace es un monton de ruido, gastarme las pilas y calentarme el 7805  :5]
que puedo hacer?
salu2

--------- EDITO ----------
El problema ya esta resuelto gracias a una aportacion de Nocturno. El codigo funcionando y otras cosas interesantes sobre esto estan mas adelante en este hilo.
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 11 de Mayo de 2007, 18:19:23
Yo tambien tengo una rutina para controlar un servo por el ADC, con el 16F88, y algunas veces hace un poco de ruido el servo, y es por culpa del potenciometro
que queda en una posicion inestable, y produce variaciones en la lectura del ADC.
Te recomiendo que visualices los valores del ADC a ver si son la causa. En el caso de que sea asi mira la zona muerta de tu servo, creo que suele estar de 5 a 10uSeg., y filtra las lecturas del ADC para que no varien dentro de este margen.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 11 de Mayo de 2007, 21:33:30
hmmm  :?
nunca habia comunicado un micro con el PC, pero lo intentare para ver que me cuenta el adc... lo que si, el pot lo filtro con un condensador del pin del pic a masa de 0.1uf. crei que eso me solucionaria la impresicion del pot...
lo que no entiendo muy bien es que es la zona muerta del servo
gracias dogflu por tu ayuda  :P
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 12 de Mayo de 2007, 04:25:38
Visualizas el adc con un muestreo suficientemente rapido para ver si hay variaciones o muestras valores maximos y minimos, lo pasas a tiempo y si las variaciones estan muy cerca o superan a la zona muerta del servo, este vibrara. Esta zona es un tiempo del duty cycle en el que el servo puede que no responda y por lo tango no se desplace a la posición siguiente inmediata.

El periodo de la señal de control del servo no tiene que ser muy exacto, ya que aquí si se permite una tolerancia de varios mSeg.
Pero las variaciones en la parte de señal del duty cycle solo se permite si es igual o inferior a la zona muerta del servo, mejor menor.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 12 de Mayo de 2007, 12:38:26
pero si te fijas en mi codigo, tomo la muestra del adc cada 50ms...
pero que raro... le di la orden para que se quedara quieto en una posicion sin leer el adc y si que sabe quedarse quieto en esa posicion...
debes tener razon con lo del adc... pero no entiendo como, si las muestras son cada 50ms  :?
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 12 de Mayo de 2007, 13:35:43
jejejeee, lo de tomar la muestra rapido era para saber el grado de variacion del adc.

cuanto mas espaciadas tomes las muestras menos se movera, pero claro perderas ese tacto o control del servo con el pot.
en mi caso tomaba las muestras cada 100mSeg. y cuando cogia una zona no estable del pot. seguia con la mania de moverse..
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 12 de Mayo de 2007, 15:12:22
y entonces cual es la solucion? he intentado filtrar la señal del pot con condensadores mas grandes, pero es lo que tu dices, pierde sensibilidad al tacto y no se soluciona el problema...  :x
que me propones?
salu2
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 12 de Mayo de 2007, 17:02:56
Pues nose no he llegado todavia a ese punto.
si hay diferencia entre la medicion anterior y la actual activaria un contador, que se hace reset cada vez que se cambia de valor el ADC, si al termino del contador procederia al cambio de posicion. Como los antirrebores de las teclas.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 12 de Mayo de 2007, 17:16:08
:cry:
me lo temia....
esa es la solucion que pense yo tambien, pero no la puse en practica xq la verdad no me apetecia ponerme a hacer el codigo para eso... pero bueno, visto que no encuentro mas soluciones tendre que ponerme a trabajar en ello.
alguien mas que haya hecho algo asi tiene alguna solucion? :(
gracias dogflu
salu2
Título: Re: mi servo no se queda quieto
Publicado por: Duende_Azul en 12 de Mayo de 2007, 19:21:50
y que tal si en lugar de tomar una muestra, tomas 10, las promedias y ese valor se lo envias al servo?
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 13 de Mayo de 2007, 00:53:07
pues no es mala idea... y me parece mas simple de implementar que un "antirebotes" para el POT  :)
lo probare y os digo que tal
salu2
Título: Re: mi servo no se queda quieto
Publicado por: vicent en 13 de Mayo de 2007, 16:10:23
A mi se me ha ocurrido lo mismo que a duende_azul.
Me pasó una vez con un sensor de temperatura, alguien me comentó que hiciera un promedio y mostrara el reloj y se estabilizó mucho.

Un saludo. Au.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 14 de Mayo de 2007, 21:05:46
estaba por ponerme a ello... lo de promediar 10 resultados....
lo iba a hacer de la manera tipica, sumar 10 resultados y despues dividirlos entre 10... vamos lo tipico, pero me doy cuenta que si por ejemplo tengo 9 resultados de "100" y uno de "99" la suma va a ser 999, y el promedio 99.9, y si le aplico "ROUND" (en C) lo que hace es truncar.... con lo que se  queda en 99... y si luego tengo 9 resultados "100" y uno "101", el promedio sera 100.1, que al trucar me dara 100... y nuevamente a vibrar....
hay alguna funcion que realmente redondee a la antigua usansa? (por encima de 0.5 sube, y por debajo trunca)
todo esto lo estoy diciendo desde la teoria...
lo probare a ver que tal, pero aun asi creo que se podra atenuar aun mas la vibracion del servo si pudiera redondear  :mrgreen:
acepto sugerencias en C  :-)
salu2
Título: Re: mi servo no se queda quieto
Publicado por: Carli en 14 de Mayo de 2007, 21:18:26
Como ex-aeromodelista he tenido dicho problema con servos Futaba y los solucionaba limpiando el potenciometro que esta dentro del mismo y colocandole un poco de grasa, a veces las pistas del potenciometro al ser "raspadas" por los patines del mismo desprenden un poco de suciedad y hace que el servo tome un valor erratico del potenciometro y tiemble.

Lo mismo es si el potenciometro no se centra siempre en el mismo lugar, es el potenciometro sucio o juego en los engranajes.

Espero les sirva mi aporte, y sino a segir con el codigo!!!!!!!

Suerte.
Título: Re: mi servo no se queda quieto
Publicado por: Nocturno en 16 de Mayo de 2007, 01:47:29
hay alguna funcion que realmente redondee a la antigua usansa? (por encima de 0.5 sube, y por debajo trunca)

Hay un viejo truco que te servirá, mira:
NúmeroRedondeado = Truncar ( NúmeroConDecimales + 0.5 )

Haz algunas pruebas y verás cómo funciona como quieres.
Título: Re: mi servo no se queda quieto
Publicado por: RedPic en 16 de Mayo de 2007, 02:37:04
Muy bueno el truco, Manolo.

Carli, tambien como ex-aeromodelista he llegado a golpearme la frente contra el marco de la puerta con los Servos Locos Que Atacan de Nuevo.

Yo era aficionado a las maquetas volantes y me tiré a montar un HE-111 (Heinkel 111, Cazabombardero aleman de la II GM, bimotor, con planos de vuelo elipticos alabeados, una preciosidad de verdad) y quería montar un control de potencia para intentar igualar la tracción de los dos motores glow de .40 que calzaba. El tema era poder fijar un régimen de vueltas distinto para cada motor pero comandados ambos por una única señal de gas, de forma que ambos tuviesen el mismo empuje efectivo.

Mi bisoñez y desconocimiento hizo que tuviese que abandonar el proyecto porque no era capaz de mover los servos con la suficiente estabilidad, y lo picos erráticos que daban hacían que un motor o el otro pegasen unos saltos o caidas bruscas de potencia con lo que peligraba enormemente la integridad física del aparato.

En fin, algún día retomaré el asunto.  :mrgreen:



Título: Re: mi servo no se queda quieto
Publicado por: ESTECA55 en 16 de Mayo de 2007, 23:48:38
Valla, somos varios los ex-aeromodelistas!!

Por ahí tengo guardado 9 servos, incluyendo uno de los grandotes que venían antes de 15 kilos de empuje, ahora los de mas kilos son del mismo tamaño que los comunes. También tengo un receptor y un trasmisor de 6 canales (el 6XA de futaba programable), además de unos 5 aviones y dos motores un .15 y un .61. En fin, ideales para juntar tierra en estos momentos. Tengo ganas de desempolvar los servos, conseguir algunos mas y armarme algún robotito, espero poder ponerme con eso pronto.

Saludos
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 12 de Junio de 2007, 21:00:33
 :cry: :evil: :z) :8} :cry: :evil: :z) :8} :cry: :evil: :z) :8} :cry: :evil: :z) :8} :cry: :evil: :z) :8}

probe todo lo conocido (por mi, claro) pero no soy capaz de hacer que el servo no vibre!!!

os cuento todas las pruebas que hice:

conclusiones a las que llegue:

otras pruebas y sus resultados:

a partir de ahora centrare mis esfuerzos en aprender a usar el PWM que traen algunos pics, y no por soft.
ya vere si da el resultado que espero... y sino estuve mirando por internet probadores de servos y encontre este (http://www.rc-cam.com/servotst.htm) pero el tio no se como usara el pot, ya que lo tiene configurado como resistencia variable y no como divisor de tension... entonces no se como entendera el pic las variaciones...
tambien encontre un probador de servos basado en un 555 (en la pagina de pablin), y funciona PERFECTO, el servo no vibra ni nada... pero a este circuito no hay manera simple de controlarla desde un pic... a menos que el pot del 555 lo sustituya por un potenciometro digital (los tiene microchip, pronto me hare con algunos samples  :mrgreen:) y el adc del pic leyera un pot externo que regulara yo... el adc lo convierte y lo comunica al pot digital y este a su vez controla el 555... un follon, pero si funcionara me valdria...

llegados a este punto, hice un monografico sobre todo lo que NO SIRVE para el servo vibre menos... pero tal vez le aporte algo a alguien...
ya sabeis, si podeis aportar algo a mis innumerables (o mejor dicho: CANTIDAD de innumerables) horas de trabajo, prueba y error, pues serian de muchisima ayuda
salu2 para to2
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 14 de Junio de 2007, 17:49:22
Pues..... en el BOT controlado por RF uso cinco servos y dos motores AC, y te puedo asegurar que no vibran.
Al principio si vibraban, y era por un pequeño conflicto de interrupciones al leer el puerto serie y controlar los servos
al mismo tiempo, pero al final quedaron perfectos, asi que tendras que depurar tu Soft... :mrgreen:
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 14 de Junio de 2007, 18:14:14
He estado probando el servo en la EBasic deshabilitando el ADC, y refrescándolo a una posición fija de forma permanente, y esporádicamente se escucha un tic... esta placa esta programada para que funcione a 8 megas... y la del Bot por RF va  a 20Mhz... puede que eso afecte.... o puede también que no apreciara yo ese efecto.... de todas formas cuando coja algo de tiempo probare la rutina de los cinco servos...
Título: Re: mi servo no se queda quieto
Publicado por: Giovanny en 15 de Junio de 2007, 01:46:28
hola a todos, hace mucho no visitaba el foro, y me encuentro con temas muy interesantes a mi vuelta..  :-/
bueno, me gustaria ayudar a solucionar este problem, y para ello hize una simulacion en proteus del control de posicion de  3 servomotores (futaba), de acuerdo a la variacion de 3 potenciometros, con lo cal he obtenido buenos resultados en la practica,(no vibran). Aunque los potenciometros juegan un papel importante, yo personalmente uso pot lineales, los logaritmicos siempre me molestan y terminan volviendome loco..  :D :D
El soft, lo hice en CCS, y tambien es un pwm emulado. 

este ejemplo, lo hize en un pic16f877a, porque lo tenia a la mano, los invito a que prueben el .hex, y si obtienen el resultado esperado, con gusto subo el .C . marttyn, por ahora espero que te funcione, ya que con el mismo soft levemente modificado (sin pots y con algunos algoritmos de fuzzy logic) controle exitosamente un bot hexapodo con 12 servomotores de marca futaba y hobbyco. 
Título: Re: mi servo no se queda quieto
Publicado por: Giovanny en 15 de Junio de 2007, 01:49:40
olvide decir que se usa un cristal de 4M, Saludos. :lol: :lol:
Título: Re: mi servo no se queda quieto
Publicado por: Giovanny en 15 de Junio de 2007, 01:56:25
he aqui el archivo de proteus, como lo olvide!!.. ;) hasta pronto
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 15 de Junio de 2007, 14:25:09
 :( y yo que estaba a punto de hacer la prueba con un cristal de 20mhz, xq pense que se acabarian los problemas, y ahora tu me dices que lo has hecho a 4mhz y funciona bien...
aunque ahora que lo pienso... MEJOR! prefiero que funcione a 4mhz  :)
quise ver la simulacion del proteus, pero tienes una version mas reciente de este y no me deja abrir el archivo. aunque de poco me habria servido, ya que no tengo ningun pic 16F877 para ponerlo en practica... (me huele a proximo pedido de samples  :D)
te importaria subir el .C? asi lo adapto al 12F683 o a algun pic que tenga en mi poder? me gustaria hacer la prueba
gracias a ambos por las respuestas, espero que pueda solucionar esto pronto... aunque eso no quita que me ponga a averiguar como funciona el PWM x hard... aunque por lo que vi hasta ahora no se si se podra hacer funcionar a 50hz
un saludo!
Título: Re: mi servo no se queda quieto
Publicado por: J1M en 15 de Junio de 2007, 15:53:05
Marttyn, creo que el problema lo resolverías con el promediado que te ha comentado Duende_Azul, y el truncamiento que te dice Nocturno, pero en vez de tomar diez muestras y promediar, haz una pila FIFO de promediado, tendría el efecto de un control derivativo, es decir, como ponerle un condensador. Con esto harías que el sistema sea mas estable al ruido que viene de la resistencia del servo. Sería algo así:

- tomas un valor, lo pones en la posición uno de la pila, sumas el contenido de la pila (de momento solo tiene ese valor) y divides entre el número de valores que contiene para obtener el valor de la salida.
- tomas otro valor, desplazas el contenido de la pila una posición a la derecha (como tenía un solo valor, ese pasaría a la posición dos) y pones el valor tomado en primer lugar, sumas el contenido de la pila y divides entre el número de valores que contiene para obtener el valor de la salida.
- tomas otro valor (van tres), desplazas el contenido de la pila una posición a la derecha y pones el valor tomado en primer lugar, sumas el contenido de la pila y divides entre el número de valores que contiene para obtener el valor de la salida.

y así sucesivamente... te lo pongo gráficamente

- 1er paso: (se captura el valor 10)

pila: [10][0][0][0][0]

salida: trunca(pila(:)/tamaño_pila) = 10


- 2o paso: (se captura el valor 11)

[11][10][0][0][0]

salida: trunca(pila(:)/tamaño_pila) = 10

- 5o paso: (se captura el valor 10, antes se capturó el 11 y el 10)

[10][10][11][11][10]

salida: trunca(pila(:)/tamaño_pila) = 10

- 6o paso: (se captura el valor 10, se pierde el 10 inicial...)

[10][10][10][11][11]

salida: trunca(pila(:)/tamaño_pila) = 10

A partir de aquí como el 6o paso, es decir, se pierde el primero que se tomó, por eso la idea de la pila FIFO. El algoritmo este se suele utilizar precisamente para el problemilla que tienes, suaviza la señal de salida, como es lógico, cuanto mayor sea la pila, mayor suavizado lo que significa que el servo se meneará menos, pero será menos sensible a cambios. Tendrás que hacer pruebas para determinar el tamaño de esa pila, ya que dependerá un poco también de tu tiempo de muestreo.


saludos!
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 15 de Junio de 2007, 18:02:45
dogflu, me acabo de leer todo el post del bot controlado por RF y no hay ni una sola mencion sobre servos  :5]
aunque mirando el lado positivo, aprendi algunas cosas sobre RF  :mrgreen:
j1m, con respecto a lo de promediar el adc, yo lo hice asi: leia el adc 10 veces en un lapso de 50ms (1 vez cada 5ms), sacaba el promedio y comenzaba de nuevo. es decir, tenia un valor cada 50ms, que es el que usaba para la pocicion del servo. el resultado: lo mismo que no promediar... aun asi probare lo que me comentas de la pila fifo a ver que tal...
por cierto, no creais que el servo se mueve BRUTALMENTE! es una vibracion pequeñita, pero genera mucho ruido y me calienta el 7805
salu2
Título: Re: mi servo no se queda quieto
Publicado por: jfh900 en 15 de Junio de 2007, 18:21:13
Yo estoy haceindo pruebas con el ADC y si la precisión es muy grande, al valor de la componente continua se superpone el ruido que toma el potenciometro como si fuera una antena. Para evitarlo, tal y como me comento PicMouse es conveniente poner un condensador de 0.1 uF de tántalo en la patilla central y masa (si no tienes pon uno cerámico), procurar que las patillas del potenciometro sean lo mas cortas posibles y si estan apantallados los cables mejor. Y por último y mas importante disminuye la precisión del ADC dejalo en 8 bits y cuando utilices la tensión de control para manejar el servo utiliza un solo decimal, el resto de decimales que utilices de más estarán fluctuando debido al ruido.

Un saludo.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 15 de Junio de 2007, 20:01:54
 :| :| :|
ya lo estoy asumiendo.... no se si dejarme vencer por esta vibracion y seguir con otra cosa...  :8}
el adc lo tengo en 8bits, condensadores los puse en todas las posiciones posibles, e intente lo de la pila fifo, pero me va FATAL  :(
supongo que es un problema del soft... debo tener algo mal en el programa. estoy 80% seguro de que no es el pot
si alguien tiene alguna rutina para comandar servos que le funcione bien, y este escrita en C se lo agradeceria un monton...
salu2
Título: Re: mi servo no se queda quieto
Publicado por: jfh900 en 15 de Junio de 2007, 20:08:35
Utiliza un solo decimal en la conversión. Con eso evitaras las fluctuaciones.

Un saludo.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 15 de Junio de 2007, 23:43:25
no entiendo a que te refieres a que use un solo decimal en la conversion...
tengo el pic a 4mhz, el adc a 8bits
timer 0 a 1:256. cada desbordamiento (65ms) lee el adc
timer 1 a 1:1. empieza a contar en 45535, asi tengo 20.000 uS para la frecuencia del servo
cada vez que leo el adc lo convierto en una posicion, es decir en un duty de entre 500uS y 2500uS
lo hago de la siguiente manera: Posicion_Servo = 500 + floor(ValorADC * 7.8)
de donde sale el 7.8?
regla de 3:
256        --> 2000
ValorADC --> X
es decir el valor que tengo que variar esta entre 500uS y 2500uS, es decir son 2000uS
esos 2000uS los voy a reducir a las 256 posibilidades del adc 2000/256=7.8125, redondeado a 7.8
entonces, al multiplicar el ValorADC por 7.8 obtengo siempre un numero entre 0 y 2000, a este valor le sumo 500 entonces asi tendre siempre un valor entre 500 y 2500. fijate que uso la opcion floor, con lo que la posicion del servo nunca va con decimales.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 16 de Junio de 2007, 00:21:10
Yaaaaaahooooo!!!
Yaaabaaadaaaabaaaa doooooo!!!!!!!
 :-/ :-/ :-/ :-/  :mrgreen: :mrgreen:   :-) :-) :-)
encontre la solucion a mis males!!!!
hasta ahora todas las cosas que hice con pics las ponia a funcionar a 4MHZ... para que mas??
pues antes cuando lei lo que decia dogflu sobre tener funcionando a 8 o a 20mhz me puse a pensar si hacer funcionar el pic mas rapido influiria en algo.
y una vez probado todo lo que se comenta en este hilo, y que nada diera resultado, se me dio por probar a 8mhz, los internos del 12F683. al principio me hice un lio con el tema de cambiar las configuraciones de los timers con sus respectivos calculos... pero logre hacerlo funcionar
 :shock: :shock: :shock: el servo dejaba de menar sus caderas como antes y pasaba a bailar una suave balada, apenas se movia!! a la vez que se me abria la boca de emocion, mi cerebro a la velocidad de 0,2Hz por segundo (o mas!) entendio que tenia que probar a mas velocidad a ver que ocurria!
empece a mirar mi caja con cosas y encontre un cristal de 12Mhz, una pena que no hubiese uno de 20, pero para probar valdria!
nuevamente me lie haciendo calculos, incluso peor que con el de 8mhz, ya que con este cristal te salen numeros periodicos, y decimales interminables... aunque despues terminas con los calculos y ves que todo cuadra perfectamente sin tener que truncar ni redondear ningun valor  :mrgreen:
pues eso, que lo puse a 12mhz... podia sentir la velocidad sobre mi cara, inicluso creo que pude escuchar las RPM a todo gas dentro del pic, y en ese momento broto una lagrima de mis ojos, y no era por la velocidad, sino porque mi pequeño servo solo se movia APENAS cuando encontraba una zona inestable del pot! vaya felicidad!
no paro de jugar con el, y mi cerebro funcionando a sus 0.2hz, que ahora en su pila de tareas tiene algo menos de lo que preocuparse, anela que llegue el lunes para ir a comprar un cristal de 20mhz.
lo que me queda mientras tanto es dejaros el codigo comentado (que funciona a 4, 8 o 12Mhz) para mover un servo con un potenciometro (con antirebote de pot incorporado!)
os dejo un video para que veais como vibra el servo a 4mhz aqui (http://www.youtube.com/watch?v=4Iez6T6VMwo)
lo que me preocupa es porque hay gente que puede hacer funcionar el servo a 4mhz sin que le vibre... sera que mi codigo esta poco optimizado?
pues un saludo y a ver si alguien me sabe decir si mi codigo esta tan mal como para que no funcione a 4mhz
Título: Re: mi servo no se queda quieto
Publicado por: Nocturno en 16 de Junio de 2007, 02:44:51
Marttyn, me alegro que hayas disminuido las vibraciones, pero he visto algo en tu código que me chirría y te sugiero que pruebes a cambiarlo.

En tu interrución del Timer te limitas a activar un flag (flagOMS) que indica a tu bucle principal que debe levantar el pulso. En tu bucle principal tienes dos operaciones que comen bastantes ciclos de reloj: la conversión ADC y un cálculo con números float. Estas pesadas operaciones pueden retrasar el levantamiento del pulso bastante; quizás lo suficiente como para apreciar una vibración a 4MHz, aunque no tanto como para verla a 12MHz. Por eso con más frecuencia tu problema deja de verse, aunque no deja de existir.

Sugerencia:
- en tu bucle principal ve haciendo continuamente la conversión ADC y calcula dos números: nuevoTimerNivelAlto y nuevoTimerNivelBajo.
- estos dos números deben sumar siempre 20ms, y determinan el ancho del pulso que vamos a enviar al servo
- en tu bucle principal no haces nada más, no manipules la señal de control del servo
- tu interrupción podría quedar así:
Código: C
  1. if (input(SERVO)) {
  2.                                         // estaba en nivel alto
  3.                                         output_low(SERVO);
  4.                                         set_TIMER1(TimerNivelBajo);
  5.                                         TimerNivelBajo=nuevoTimerNivelBajo;
  6.                                         TimerNivelAlto=nuevoTimerNivelAlto;
  7.                                 } else {
  8.                                         // estaba en nivel bajo
  9.                                         output_high(SERVO);
  10.                                         set_TIMER1(TimerNivelAlto);
  11.                                 }
            
Observa que sólo cargo los nuevos valores que has calculado cuando el pulso ha bajado y está programado para sumar 20ms. Si lo cargase durante el pulso alto estaría corriendo el riesgo de que no sumase 20ms.

Por último, decirte que no lo he probado; esto es sólo teoría. Ya me contarás cómo va.
Título: Re: mi servo no se queda quieto
Publicado por: Marttyn en 16 de Junio de 2007, 06:43:36
suena interesante nocturno
y sobre todo corrobora mis sospechas de que habia algo que demoraba la subida o la bajada del pulso pwm, y por eso las vibraciones
a ver si mañana puedo probar lo que me sugieres. pero no suena para nada descabellado.
ya te contare los avances
un saludo y gracias!
Título: Re: mi servo no se queda quieto
Publicado por: dogflu66 en 16 de Junio de 2007, 11:11:50
dogflu, me acabo de leer todo el post del bot controlado por RF y no hay ni una sola mencion sobre servos  :5]
aunque mirando el lado positivo, aprendi algunas cosas sobre RF  :mrgreen:
j1m, con respecto a lo de promediar el adc, yo lo hice asi: leia el adc 10 veces en un lapso de 50ms (1 vez cada 5ms), sacaba el promedio y comenzaba de nuevo. es decir, tenia un valor cada 50ms, que es el que usaba para la pocicion del servo. el resultado: lo mismo que no promediar... aun asi probare lo que me comentas de la pila fifo a ver que tal...
por cierto, no creais que el servo se mueve BRUTALMENTE! es una vibracion pequeñita, pero genera mucho ruido y me calienta el 7805
salu2

Cierto no es en el Bot por Rf, es en este otro hilo del amigo Lord_lafebre donde compartimos invento tambien controlado por RF, de todas formas el enlace al codigo ya no funciona.
vere de probar de nuevo el codigo con los cinco servos y ya contare que ocurre.

http://www.todopic.com.ar/foros/index.php?topic=13556.0

PD. sorry..  :(
Título: Re: mi servo no se queda quieto RESUELTO
Publicado por: Marttyn en 18 de Junio de 2007, 01:02:48
 :-/ :-) :-/ :-) :-/ :-)
pues ahora si! lo he conseguido de verdad de la buena!
bueno, no se puede decir exactamente que lo he conseguido yo, sino vosotros, y en especial nocturno con su ultima aportacion que fue la decisiva!
ya puedo mover un servo con total precision y sin que vibre lo mas minimo.
ahora, he hecho cantidad innumerable de pruebas... es mas, creo que el pic con el que hago las pruebas ya debe haber cumplido su ciclo de vida promedio  :D
tantas pruebas me lleva a sacar nuevas conclusiones de la mejor manera de configurar los componentes y el soft para que funcione mejor.
lo que me parecio mas curioso es que no hacen falta condensadores de filtrado en ningun lado. ni antes o despues del 7805, ni en la entrada del pot, ni entre el + y - del pot... SOLO hace falta un condensador de 100 nanos entre Vss y Vdd del pic. NADA MAS
primero probe con una bateria de 12v como fuente, y como vi que no hacian falta los condensadores probe con los 12v de la fuente de alimentacion del PC (esa que todos dicen que son tan malas) porque no da voltaje constante... y el servo seguia sin vibrar ni nada...
de hecho, le quite el antirebotes por soft que le hice al pot, para ver que ocurria, y el servo seguia moviendose perfectamente.
las pruebas las estaba haciendo con un pot de los caros, pero casi me indignaba que el servo no quisiera vibrar, asi que busque el peor pot que encontre y probe con el... pero seguia funcionando todo con la suavidad de la seda.
visto que parecia a prueba de bombas recurri al adc de 10bits, calculos con mas decimales y a un potenciometro multivueltas (de estos de tornillo), y lo unico que consegui fue quedarme perplejo al ver que vuelta tras vuelta del pot, el servo se limitaba a responder a la perfeccion, sin encontrar NI UNA zona inestable en todo su recorrido  :shock:
pues nada... ahora soy un hombre feliz, que puede continuar con su vida y dormir bien por las noches.
pero como no, ahora tendre que embarcarme en nuevos proyectos, porque no se si soportare estas por mucho tiempo sin un problema gordo sin resolver  :D
os dejo el codigo para que lo aprovecheis, esta en C, para un 12F683... tiene implementado el codigo de antirrebote del pot, pero esta desactivado porque por ahora no hizo falta.
solo me queda una duda a la que todavia no le habia hecho caso... hace falta poner una resistencia limitadora de corriente en la entrada del ADC y en el pin de salida del servo? alargarian la vida util de ambos o solo los haria mas propensos a los ruidos e interferencias?
un saludo y gracias a todos por la ayuda!
Título: Re: mi servo no se queda quieto (RESUELTO)
Publicado por: Nocturno en 18 de Junio de 2007, 01:54:42
Enhorabuena por conseguirlo. Acabas de recibir una inyección de adrenalina pura para acometer nuevos proyectos.
Título: Re: mi servo no se queda quieto (RESUELTO)
Publicado por: dogflu66 en 18 de Junio de 2007, 18:01:52
Quedo magnifico el hilo, ya lo puse en el indice de robotica como recomendado...  :-)
Título: Re: mi servo no se queda quieto (RESUELTO)
Publicado por: RedPic en 18 de Junio de 2007, 18:22:14
Me encanta que las cosas terminen bien.

Mi experimento con el Servo terminó (quedó abandonado) sin solucionar el tema de la impresición según que lectura hacía (en mi caso un termo-servo cuya posición la controlaba un sensor de temperatura) ... asi que ahora me toca revisar todo el hilo y aprender de las soluciones que nos aportas.

Mis mas sinceras felicitaciones Marttyn, ése es el espíritu del foro.  :mrgreen:

Título: Re: mi servo no se queda quieto (RESUELTO)
Publicado por: Marttyn en 19 de Junio de 2007, 17:05:51
 :cry: que felicidad... ya me siento "util" en el foro...
bueno, hice una prueba mas con un potenciometro deslizante. los otros con los que habia probado eran todos diferentes tipo de los que giran 270º, excepto el multivuelta. y con el pot deslizante si que encuentro bastante impresicion al leer el adc, es decir, me vibra. tambien vibra con cables largos hasta el pot (como ya lo habia comentado antes alguien). asi que lo de que no son necesarios los condensadores de filtrado o el antirebote por soft es relativo... variara segun el diseño de cada circuito y la calidad de los componentes.
nada mas... salu2

PD: que ilusion! estoy en el indice de robotica!  :-/
Título: Re: mi servo no se queda quieto (RESUELTO)
Publicado por: Marttyn en 20 de Junio de 2007, 20:17:41
vamos a enroscarlo aun mas  :-)
el codigo que funciona tiene un pequeño (o muy grande) defecto... que ocurre si se quiere controlar mas de un servo? habria que tener un timer por cada uno... y eso no es viable.
que solucion podriamos encontrar para eso?
dogflu, tu como controlabas los 5 servos a la vez con presicion?
yo ya estoy dandole vueltas al asunto y haciendo las pruebas necesarias... si alguno tiene alguna idea que la comente.
salu2

PD: que poco duro la paz...  :D
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 21 de Junio de 2007, 01:54:34
Te lanzo mi sugerencia.

Lo primero sería definir la resolución mínima con la que quieres trabajar. Por ejemplo, si divides el rango de movimientos del servo en 100 posiciones, necesitarías un byte (o sólo 7 bits) que te indique la posición de cada uno. Podríamos almacenar estas posiciones en un array Servo(i)

Obviamente, tendrás que dividir también en 100 posiciones el ancho máximo del pulso alto de la señal PWM que maneja el servo. Si el rango va de 0.5ms a 2.5ms, tendrás una resolución mínima de (2.5ms - 0.5ms) / 100 = 20us. Configura el timer para que interrumpa cada 20us.

La primera vez que se entra a la interrupción ponemos todas las salidas a nivel alto.
A continuación, cada vez que volvemos a entrar en la interrupción vamos incrementando en una unidad el "contador de pasos". Recorremos el array de posiciones para comparar dicho contador de pasos con la posición que tenemos almacenada para cada servo. En los servos en los que la condición se cumpla, bajamos el pulso.

Al llegar al paso nº 100 ya hemos tenido que bajar el pulso de todos los servos. Sólo nos queda esperar a que pasen los 20ms de rigor sin hacer nada para comenzar un nuevo ciclo.

La pega más importante que puede haber es que a la interrupción no le dé tiempo acabar los deberes en 20us, por lo que yo empezaría las pruebas con una resolución baja (10 posiciones, por ejemplo) y la aumentaría cuando todo estuviese funcionando y depurado.

Al igual que la otra vez, no lo he probado; sólo es una idea y espero que tú puedas convertirla en realidad como en la ocasión anterior.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 21 de Junio de 2007, 03:43:59
Pues Manolo te lo explico claro y con todo detalle.... :mrgreen:
y aqui si que se necesita velocidad de proceso... :D
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 21 de Junio de 2007, 13:18:37
y una solucion como la que nos ofrece redpic en sus ejemplitos?
es decir, el timer a 20ms, y en el bucle principal miras en que posicion se encuentra el timer. cuando le corresponda a cada servo se baja el pulso.
vamos, es el primer codigo con el que probe... y vibraba, pero supongo que era por las conversiones adc...
pero si las conversiones adc las hiciera SOLO una vez que el pulso haya bajado tendria como minimo 17.5ms para esta tarea, con lo que EN PRINCIPIO no deberia hacer vibrar al servo ya que el pulso se esta bajando correctamente cada vez.
nocturno, voy a probar de esta manera primero que asi tengo que hacer menos modificaciones al codigo, y si no da resultado mirare como tu dices.
y sino siempre podemos subir la velocidad del micro  :mrgreen:
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Giovanny en 21 de Junio de 2007, 19:35:54
hola amigos de todo pic.  :mrgreen:

para marttyn y todos lo interesados en controlar la posicion de los servomotores, pongo a su disposicion un ejemplo (con comentarios) de cómo hacerlo usando el puerto serie.
En este programa he seguido algunas recomendaciones del amigo Nocturno. :-)
cualquier otra sugerencia les agradezco. 

Espero que les sea de utilidad y que se diviertan en el camino. :D :D

Hasta pronto
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Giovanny en 22 de Junio de 2007, 16:56:41
correccion..
en la interrupcion #int_rda
//y guarda este valor en tServo1
//para luego cargarlo a timer0

cambiar por:

//y guarda este valor en tServo1
//para luego compararlo con timer0
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 22 de Junio de 2007, 20:22:14
Seguro que serviran Giovanny, en el hilo quedan para todo aquel que esta interesado y para los que vendran despues.
Te lo puedo asegurar por propia experiencia.... que ya son unos añitos... :mrgreen:
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: softjad en 16 de Julio de 2007, 12:47:18
y una solucion como la que nos ofrece redpic en sus ejemplitos?
es decir, el timer a 20ms, y en el bucle principal miras en que posicion se encuentra el timer. cuando le corresponda a cada servo se baja el pulso.
vamos, es el primer codigo con el que probe... y vibraba, pero supongo que era por las conversiones adc...
pero si las conversiones adc las hiciera SOLO una vez que el pulso haya bajado tendria como minimo 17.5ms para esta tarea, con lo que EN PRINCIPIO no deberia hacer vibrar al servo ya que el pulso se esta bajando correctamente cada vez.
nocturno, voy a probar de esta manera primero que asi tengo que hacer menos modificaciones al codigo, y si no da resultado mirare como tu dices.
y sino siempre podemos subir la velocidad del micro  :mrgreen:
salu2


Como lo puedo adaptar para 2 servos?

salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 16 de Julio de 2007, 13:45:20
Como lo puedo adaptar para 2 servos?

salu2

eso es lo que estamos queriendo saber...
ahora estoy terminando otro proyecto, y cuando tenga tiempo libre me pondre a hacer pruebas para ver como conseguirlo con 2 servos...
mientras tanto puedes adelantar algo de trabajo tu  :wink:
tienes la base de como hacerlo con un servo... y tambien las ideas que se comentan en este hilo
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 18 de Julio de 2007, 14:50:42
bueno, ya me he puesto nuevamente a molestar con los servos  :-/
primero hice pruebas con el codigo de redpic (el PWM se realiza desde un bucle en el main) pero leyendo el adc una vez que el pulso este bajo, para que no interfiera con el tiempo de la señal, pero no funciona... vibra...
asi que empece a hacer pruebas con la idea de manolo, poniendo el timer para que se desborde cada 100uS y mirando en cada interrupcion si hay que bajar o no el pulso de alguno de los servos...
las pruebas las empece directamente a 8mhz, ya que para esto seguramente iba a necesitar algo mas de velocidad de proceso.
las pruebas fueron genial! logre controlar 2 servos independientemente con su respectivo POT....
lo malo: al desbordarse el timer cada 100uS solo tenia 20 posiciones para el servo (2.5mS - 0.5mS = 2mS / 100uS = 20 Posiciones)
asi que baje el tiempo de desborde a 50uS. el codigo siguio funcionando correctamente, los servos se posicionaban correctamente y no vibraban, pero el POT se notaba un poco capado al tacto, ya que seguia teniendo solo 40 posiciones para el servo (2.5mS - 0.5mS = 2mS / 50uS = 40 Posiciones)
volvi a bajar el tiempo de desborde del timer, a 10uS.... la cosa fue FATAL!
los servos ya ni siquiera respondian al POT... con lo cual fui corriendo a CETRONIC (mi tienda amiga de electronica en coruña  :mrgreen: ) y compre un cristal de 20mhz...
asi que ahora me pondre a hacer las pruebas a altas velocidades  :-)
supongo que la cosa ira mejor... ya os contare
os dejo el codigo para dos servos funcionando perfectamente (con 40 posiciones), con un 12f683 a 8mhz
salu2

--- Edito ---
Al parecer el directorio para subir archivos esta lleno.... asi que no podre dejar el codigo colgado
lo pongo en un post....
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 18 de Julio de 2007, 14:55:15
Código: C
  1. #include <12F683.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT,NOMCLR,PUT,INTRC_IO
  5. #use delay(clock=8000000)
  6.  
  7. #include <math.h>
  8.  
  9. #define ADC1   0
  10. #define ADC2   3
  11. #define SERVO1 PIN_A1
  12. #define SERVO2 PIN_A5
  13.  
  14. int1 flagLeerADC = FALSE;     //flag para que sepa cuando leer el adc
  15. int16 PosicionServo1 = 15;    //posicion del servo1
  16. int16 PosicionServo2 = 15;    //posicion del servo1
  17. int16 ContInt = 0;            //Contador de interrupciones
  18.  
  19. void rLeerADC(void);
  20.  
  21. #int_TIMER0
  22. TIMER0_isr() {
  23. //Timer 8 bits -> 255 = Desborde
  24. //Prescaler de 1:2
  25. //1 Tick cada 1uS
  26. //1 desbordamiento cada 50uS (255 - 205 ticks)
  27.  
  28.    set_timer0(205);
  29.    
  30.    ContInt = ContInt + 1;
  31.    
  32.    if(ContInt < 51){
  33.       if(ContInt > PosicionServo1){
  34.          output_low(SERVO1);
  35.       }
  36.      
  37.       if(ContInt > PosicionServo2){
  38.          output_low(SERVO2);
  39.       }
  40.    }
  41.    
  42.    if(ContInt == 51){
  43.       flagLeerADC = TRUE;
  44.    }
  45.    
  46.    if(ContInt == 400){
  47.       ContInt = 0;
  48.       output_high(SERVO1);
  49.       output_high(SERVO2);
  50.    }
  51. }
  52.  
  53. void main() {
  54.  
  55.    setup_adc_ports(sAN0|sAN3|VSS_VDD);
  56.    setup_adc(ADC_CLOCK_INTERNAL);
  57.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
  58.    setup_timer_1(T1_DISABLED);
  59.    setup_timer_2(T2_DISABLED,0,1);
  60.    setup_comparator(NC_NC);
  61.    setup_vref(FALSE);
  62.    enable_interrupts(INT_TIMER0);
  63.    enable_interrupts(GLOBAL);
  64.    setup_oscillator(OSC_8MHZ);
  65.    set_adc_channel(ADC1);
  66.    
  67.    set_timer0(205);
  68.    
  69.    do{
  70.       if(flagLeerADC = TRUE)
  71.          rLeerADC();
  72.    }while(TRUE);
  73.    
  74. }
  75.  
  76.  
  77. void rLeerADC(void){
  78.    int16 ValorADC;
  79.    
  80.    ValorADC = read_adc();
  81.    PosicionServo1 = 10 + floor(ValorADC * 0.15686);
  82.    
  83.    set_adc_channel(ADC2);
  84.    delay_us(5);
  85.    
  86.    ValorADC = read_adc();
  87.    PosicionServo2 = 10 + floor(ValorADC * 0.15686);
  88.    
  89.    set_adc_channel(ADC1);
  90.    flagLeerADC = FALSE;
  91. }
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 18 de Julio de 2007, 16:50:40
Creo que esa rutina de interrupción podría reducirse, ganando en velocidad de proceso y, por tanto, pudiendo meter más pasos de potenciómetro.
A ver si tengo un ratito y le echo un vistazo.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 18 de Julio de 2007, 17:04:01
gracias nocturno!
yo ahora estoy con las pruebas a 20mhz...
cuentame cuando se te ocurra algo
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 19 de Julio de 2007, 00:38:16
No es mucho, pero algún avance he conseguido.
En primer lugar y por si no lo sabías, te diré que para saber cuánto ocupa una función tenemos una opción en el menú que nos vendrá bastante bien. Se trata de la opción View->Statistics.
Al probarla con tu programa vemos lo siguiente:
Código: [Seleccionar]
Page ROM  %  RAM  Functions:
---- --- --- ---  ----------
0     63   4  10  @FLT
0     32   2   4  @SFTOI
0     30   2   2  @ITOF
0    203  13  14  @DIVFF
0    319  21  16  @ADDFF
0    118   8  13  @MULFF
0    408  26   4  floor
0     68   4   0  TIMER0_isr
0     86   6   0  main
0    172  11   6  rLeerADC
Observa que la interrupción del timer consume 68 instrucciones.

He hecho un par de cambios en la rutina de interrupción dejándola como sigue:
Código: C
  1. #int_TIMER0
  2. TIMER0_isr() {
  3.  
  4.    set_timer0(205);
  5.    
  6.    ContInt++;
  7.    
  8.    if(PuedenBajar){
  9.       if(ContInt == PosicionServo1){
  10.          output_low(SERVO1);
  11.       }
  12.  
  13.       if(ContInt == PosicionServo2){
  14.          output_low(SERVO2);
  15.       }
  16.    }      
  17.  
  18.    if(ContInt == 51){
  19.       flagLeerADC = TRUE;
  20.       PuedenBajar=FALSE;
  21.    }
  22.  
  23.  
  24.    if(ContInt == 400){
  25.       ContInt = 0;
  26.       PuedenBajar=TRUE;
  27.       output_high(SERVO1);
  28.       output_high(SERVO2);
  29.    }
  30. }

Los cambios son principalmente dos:
- los if con condición ">" los he sustituido por "==". El micro tarda menos en comprobar esta condición y para el funcionamiento de tu programa es lo mismo.
- he añadido un flag (PuedenBajar) para sustituir la condición if (ContInt<51)

Ahora al compilar aparece lo siguiente:
Código: [Seleccionar]
Page ROM  %  RAM  Functions:
---- --- --- ---  ----------
0     63   4  10  @FLT
0     32   2   4  @SFTOI
0     30   2   2  @ITOF
0    203  13  14  @DIVFF
0    319  21  16  @ADDFF
0    118   8  13  @MULFF
0    408  26   4  floor
0     60   4   0  TIMER0_isr
0     86   6   0  main
0    172  11   6  rLeerADC

Como ves, hemos ahorrado 8 instrucciones, o lo que es igual, un 12% de tamaño que probablemente puedas incrementar en frecuencia de proceso.
Ni que decir tiene que si hicieras esta interrupción en assembler conseguirías reducirla bastante más, aunque en ese tema yo no puedo ayudarte.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 19 de Julio de 2007, 02:49:26
Master por mas que miro veo las dos tablas iguales....  :shock:
donde esta la diferencia?...
Manolo al final que compilador usas?... con que entorno de trabajo?...
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 19 de Julio de 2007, 10:43:19
dogflu, yo tambien estuve mirando un buen rato las tablas, y ahora me doy cuenta! en donde dice timer0_isr, la primera tabla dice que son 68 instrucciones, y en la segunda son 60
lo de ver las estadisticas lo acabo de probar (en PICC) y esta interesante! sobre todo para saber cuanto tarda el programa en cada cosa.
probare a ver si asi va mejor el tema.... pero aun asi no creo que la solucion este por este lado... si que es un paso importante para reducir el codigo, pero al hablar de 80 pasos al menos del POT creo que habra que buscar soluciones mas drasticas, tanto puede ser lo de incluir algo de ASM (que nunca es tarde para aprender  :mrgreen: ) o ir a mas Mhz.
yo ya habia adaptado el codigo a 20mhz y empece a hacer las pruebas... y no comprendia porque la cosa no funcionaba... hasta que me di cuenta que el micro se me queda pequeño... ya que el pin A3 es solo entrada (no analogica)... y como estoy usando 2 pines para el xtal me quede sin pines, ya que necesito dos salidas para el pwm y dos entradas analogicas para los pot.... asi que ahora me pongo a modificar el codigo para ver que tal va con un 16f88
salu2 y gracias manolo por aportarnos sabiduria! cada vez que dices algo yo aprendo una cosa nueva  :-)
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 19 de Julio de 2007, 13:37:58
Ahora si lo vi...  :z)

Yo tengo un codigo para controlar un servo. Este codigo no usa contadores
para controlarlo, lo que hago es cargar directamente el registro del timer
con el valor... es una primera aproximacion... lo que ocurre es que no esta
en C.

PD. por el momento puedes asociar una entrada analogica a varios servos y
de esta manera aprovechas el hard operativo que tengas por el momento.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 19 de Julio de 2007, 14:12:24
Manolo al final que compilador usas?... con que entorno de trabajo?...
Utilizo un vetusto pero fiable CCS 3.242
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 20 de Julio de 2007, 22:33:47
manolo, desde que dijiste lo de "statics" no dejo de mirar como optimizar el codigo!
es curioso, pero "a=a+1" ocupa las mismas instrucciones que "a += 1", pero ambas una instruccion mas que "++a" / "a++"... aunque en principio creo que tendrian el mismo efecto, no? (hablando del lenguaje C, claro)
esto lo quiero usar para incrementar el contador de interrupciones del timer
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: jfh900 en 21 de Julio de 2007, 02:08:29
Efectivamente a=a+1 es igual a a += 1 y necesita tres posiciones de memoria, dos para los operandos (la variable "a" y "1") mas una posición para la operación con los operandos (+). Sin embargo ++a y a++ solo utilizan dos posiciones, una para la variable y otra para la operación (el 1 es implicito, mientras con la otra instrucción puedes incrementar lo que quieras, con esta solo puedes incrementar la unidad).

Un saludo.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 21 de Julio de 2007, 03:06:56
Qué curioso, juraría que el compilador detectaba el a=a+1 y lo compilaba como a++

Si no es así, ya tienes otro ciclo que ahorrar ;-)
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 21 de Julio de 2007, 06:11:37
Esa misma pregunta la hice como hace unos 15 años o mas, jeje,
se me quedo grabada la respuesta, los compiladores deben optimizar
el código lo mas posible, que seria lo deseado por todos, pero no
debían de cambiar la sintaxis porque en algunos proceso se requiere
que una rutina determinada tarde un tiempo exacto, ya opere con
unos valores u otros. No se si será la respuesta correcta pero entonces
me pareció suficiente.. jeje.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 21 de Julio de 2007, 16:42:44
[...]los compiladores deben optimizar el código lo mas posible, que seria lo deseado por todos, pero no
debían de cambiar la sintaxis porque en algunos proceso se requiere que una rutina determinada tarde un tiempo exacto, ya opere con unos valores u otros.[...]

sabias palabras dogflu... nunca lo habia pensado, pero para mi y para muchos tal vez sea mejor optimizar el codigo al maximo, pero algun que otro listo hace rutinas que duran los ciclos exactos que ellos necesitan, y no puede venir el compilador y joderle el trabajo  :D

alguien sabe alguna pagina donde hablen de los ciclos que tardan las diferentes lineas de codigo? asi como formas de optimizarlo y todo eso... no esta de mas ir profundizando de vez en cuando  :-/
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 22 de Julio de 2007, 17:05:44
:8} odio cuando algo no funciona y no se por que!!
como no tenia suficientes pines con el 12F683 para hacer las pruebas con 2 pot y 2 servos me pase al 16F88. usando el codigo adaptado que usaba antes no puedo hacer andar el servo con este micro!!! reduje el codigo hasta quedar solo 1 servo y lo basico.... no funciona

Código: C
  1. #include <16F88.h>
  2. #device adc=8
  3.  
  4. #include <math.h>
  5.  
  6. #FUSES NOWDT,INTRC_IO,NOMCLR,PUT,NOBROWNOUT,NOCPD,NOLVP,NOIESO,NODEBUG
  7. #use delay(clock=8000000)
  8. #use standard_io(a)
  9. #use standard_io(b)
  10.  
  11. #define SERVO1 PIN_B4
  12.  
  13. void rLeerADC(void);
  14.  
  15. int1 LeerADC = FALSE;        //indica si el tiempo del timer es menor a 2.5mS
  16. int8 PosicionServo1 = 15;    //posicion del servo1
  17. int16 ContInt = 0;            //cuenta cuantas veces ocurrio la interrupcion
  18.  
  19. #int_TIMER0
  20. TIMER0_isr() {
  21. //Timer 8bits -> 256 ticks = overflow
  22. //1 ciclo cada 0.5uS
  23. //prescaler 1:2 -> 1 tick cada 1uS
  24. //overflow cada 50uS (255 - 205)
  25.  
  26.    set_timer0(205);
  27.    ContInt = ContInt + 1;
  28.  
  29.    if(ContInt = PosicionServo1)
  30.       output_low(SERVO1);
  31.      
  32.    if(ContInt == 51)
  33.       LeerADC = TRUE;
  34.      
  35.    if(ContInt == 400){  //reinicia los 20mS
  36.       ContInt = 0;
  37.       output_high(SERVO1);
  38.    }
  39. }
  40.  
  41. void main() {
  42.  
  43.    setup_adc_ports(sAN1|VSS_VDD);
  44.    setup_adc(ADC_CLOCK_INTERNAL);
  45.    setup_spi(FALSE);
  46.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
  47.    setup_timer_1(T1_DISABLED);
  48.    setup_timer_2(T2_DISABLED,0,1);
  49.    setup_comparator(NC_NC_NC_NC);
  50.    setup_vref(FALSE);
  51.    enable_interrupts(INT_TIMER0);
  52.    enable_interrupts(GLOBAL);
  53.    setup_oscillator(OSC_8MHZ|OSC_INTRC);
  54.    
  55.    set_adc_channel(1);
  56.    set_timer0(205);
  57.    
  58.    do{
  59.       if(LeerADC = TRUE)
  60.          rLeerADC();
  61.    }while(TRUE);
  62. }
  63.  
  64. void rLeerADC(void){
  65.    int16 ValorADC;
  66.    
  67.    ValorADC = read_adc();
  68.    PosicionServo1 = 10 + floor(ValorADC * 0.15625);
  69.    LeerADC = FALSE;
  70. }

supongo que no estara bien configurado el pic... porque el codigo veo que es el mismo que usaba con el 12f683, y funcionaba...
alguien sabe si estoy configurandolo mal?
llevo todo el dia haciendo pruebas y no consigo nada  :(
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: dogflu66 en 25 de Julio de 2007, 18:34:31
Siento no poder ayudarte en tu lenguaje,
te dejo un ejemplo para el 16F88 a ver
si te sirve la configuracion del micro para
hacerte algo de luz.


Código: FreeBasic
  1. Define CONF_WORD = 0x2f10
  2. Define CONF_WORD_2 = 0x3ffc
  3. Define CLOCK_FREQUENCY = 8
  4.  
  5. '***************** Placa Entrenadora (PIC EBadic) ***************************************
  6. 'NOMBRE:16F88_Pic_EBasic_LCD_Timer1_ADC_PWM_Servo_12
  7. 'Descripcion: Control de un servomotor (Futaba S3003) usando el ADC, Timer1, Interrupciones
  8. 'Micro: pic16f88 / 8mhz reloj interno
  9. 'version 1.2
  10. 'añado base de tiempos, 20 mSeg.
  11. 'suprimo "flag2_pwm"
  12. 'Version 11
  13. 'se fusiona la rutina de division con decimales
  14. 'para mostrar el tiempo del duty cycle en pantalla, minimo 0.43mSeg. y maximo 2.26mSeg.
  15. 'modificacion del formato de salida de la imformacion por el lcd
  16. 'Version: 1.0
  17. 'Fecha/Autor: 4/07, By COS
  18. 'Uso del LCD con bus de datos a 4Bit y sin pin de RW
  19. 'uso del timer1 para controlar el PWM, de periodo 20mSeg.
  20. 'lectura de entrada analogica y conversion a tiempo
  21. 'conversion de tiempo a valores a cargar en el timer1
  22. '************************************************************************************************
  23. '-------------------------------------Puertos del LCD---------------------------------------------
  24. Define LCD_BITS = 4  'indicamos que el bus de datos del lcd sera de 4bit
  25. Define LCD_DREG = PORTA  'el bus de datos sera el puerto A
  26. Define LCD_DBIT = 0  'el bus de datos seran los 4 bit menos significativos del puerto A
  27. Define LCD_RSREG = PORTB  'el bit de control RS sera del puerto B
  28. Define LCD_RSBIT = 7  'se usara el RB7 como RS
  29. Define LCD_EREG = PORTB  'el bit de control E sera del puerto B
  30. Define LCD_EBIT = 6  'se usara el RB6 como E
  31. 'Define LCD_RWREG = PORTA  'el bit de control RW sera del puerto A (si se suprime el compilador no protesta)
  32. 'Define LCD_RWBIT = 5  'se usara el RA5 como RW (si se suprime el compilador no protesta)
  33. Define LCD_COMMANDUS = 500  '2000  'Tiempo de espera despues de ejecutar un comando del lcd en uSeg.
  34. Define LCD_DATAUS = 50  'Tiempo de espera despues de enviar un dato al LCD en uSeg.
  35. Define LCD_INITMS = 5  '50  'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
  36. '****************************************************************************************************
  37. Define SIMULATION_WAITMS_VALUE = 1  'Ignora los valores de Waitms
  38. '--------------------------------------Reasignacion de nombres---------------------------------------
  39. Symbol led_amarillo = PORTA.7  'led amarillo
  40. Symbol led_verde = PORTB.0  'led verde
  41. Symbol luz_lcd = PORTB.3  'retroiluminacion del lcd
  42. '------------------------------------declaracion de variables---------------------------------------
  43. '-------------------------------Bases de tiempos,variables--------------------------------------
  44. Dim timer1_20ms As Word  'base de tiempos, 20mSeg
  45. Dim timer1_20ms_tiempo As Word  'tiempo a temporizar por la base de tiempos * 20mSeg
  46. '-------------------------------Variables del ADC y Rutina division------------------------------
  47. Dim entero As Word  'parte entera
  48. Dim decimal As Word  'los dos decimales
  49. Dim division As Long  'almacenara el numero con los dos decimales
  50. Dim factor_escala As Word  'situa la parte entera del numero
  51. Dim reg_timer1 As Word  'valor maximo que puede contener el registro del TMR1
  52. Dim tiempo_ms As Word  'tiempo a on de la señal de control del servo en mSeg.
  53. Dim aux_adc_4 As Word  'auxiliar
  54. Dim adc_4 As Word  'contiene el valor de la entrada ADC
  55. '----------------------------------------variables calculo y control PWM-----------------------------
  56. Dim pwm As Word  'variable de paso
  57. Dim pwm_nop As Word  'variable de paso
  58. Dim aux_pwm As Long  'calculo del tiempo a ON, de la señal de control
  59. Dim aux_pwm_nop As Long  'calculo del tiempo a OFF, de la señal de cotrol
  60. Dim timer_pwm As Word  'valor del tiempo a on, para ser interpretado
  61. Dim timer_pwm_nop As Word  'valor del tiempo a off, para ser interpretado
  62. Dim flag1_pwm As Byte  'variable que determina si ON o a OFF de la señal de control
  63. '------------------------------------asignacion de valores a las variables--------------------------
  64. pwm = 62535
  65. pwm_nop = 28535
  66. aux_pwm = 62535
  67. flag1_pwm = 1
  68. entero = 0
  69. decimal = 0
  70. division = 0
  71. adc_4 = 0
  72. reg_timer1 = 65535  'maximo valor registro de 16 bit del TMR1
  73. factor_escala = 100  'factor de escala para dos decimal
  74. timer1_20ms_tiempo = 2  '40 mSeg.
  75. timer1_20ms = timer1_20ms_tiempo
  76. '------------------------------------Definicion de puertos------------------------------------------
  77. Define ADC_SAMPLEUS = 0  'el minimo, configuracion del ADC
  78. Define ADC_CLOCK = 5  '16Tad a 8Mhz = 2uSeg, minimo permitido por el micro 1.5uSeg,
  79.                                                                 'configuracion adc
  80. '_______________registros afectados por Define ADC_CLOCK y ADCIN________________
  81. ANSEL = %00010000  'los pin I/O digitales y RA4 analogico
  82. ADCON0 = %01100000  'Fosc/16 a 8Mhz (ADCON1.ADCS2=1) =2uSeg (minimo 1.uSeg), channel RA4
  83. ADCON1 = %01000000  'voltage reference (AVdd/AVss) y seleccion de escala division
  84.                                                         'clock/2 ADCON1.ADCS2=1
  85. '_______________________________________________________________________________
  86. CMCON = 0x07  'comparador a off
  87. OSCCON = 0x7e  'set intrc To 8mhz, se usara reloj interno a 8Mhz
  88. OSCTUNE = 2  'factor de correcion del reloj
  89. TRISA = 0x00  'Puerto A como salidas
  90. TRISB = 0x00  'puerto B como salidas
  91. TRISA.4 = 1  'como entrada (RA4, adc)
  92. TRISA.6 = 1  'como entrada (RA6, tecla S1)
  93. TRISA.5 = 1  'como entrada (RA5, tecla S2)
  94. PORTB.3 = 1  'luz lcd a on (RB3)
  95. PORTA.7 = 1  'led amarillo a off, negado
  96. PORTB.0 = 1  'led verde a off, negado
  97. '------------------------------------Inicializacion de Interrupciones-----------------------------
  98. T1CON.TMR1CS = 0  'asigna el reloj interno al timer1, se incrementa cada ciclo de instruccion
  99. T1CON.T1CKPS0 = 0  'factor del preescales del timer1, 0
  100. T1CON.T1CKPS1 = 0  'factor del preescales del timer1, 0
  101. TMR1H = 0xf8  'carga el registro del contador para que desborde cada 1mSeg, byte alto
  102. TMR1L = 0x30  'carga el registro del contador para que desborde cada 1mSeg, byte bajo
  103. T1CON.TMR1ON = 1  'habilitacion del TMR1, comienza a incrementarce
  104. INTCON.PEIE = 1  'bit de habilitacion de interrupciones de perifericos
  105. Enable  'INTCON.GIE habilita todas las interrupciones globales
  106. '------------------------------------Inicio-------------------------------------------------------
  107. Lcdinit  'inicializa el lcd sin cursor
  108. WaitMs 1000  'espera 1Seg
  109. Lcdout "LCD_Tmr1_ADC_PWM"  'escribe en el lcd
  110. Lcdcmdout LcdLine2Home  'seleciona la linea dos como proxima para escritura
  111. Lcdout "Servo S3003"  'escribe en el lcd
  112. WaitMs 3000  'espera 3Seg
  113. Lcdcmdout LcdClear  'borra el display
  114. PIE1.TMR1IE = 1  'activa las interrupciones del timer1
  115. '------------------------------------rutinas del Programa----------------------
  116. main:  'comienza el programa principal
  117.         If timer1_20ms >= timer1_20ms_tiempo Then
  118.                 Gosub lee_adc  'salto con retorno a la rutina de lectura del ADC
  119.                 aux_pwm = ((adc_4 + 240) * 250) / (1023 + 370)  'tiempo a ON de la señal de control del servo
  120.                 '240 y 370 fijan los valores minimo y valores maximos del duty cycle
  121.                 aux_pwm_nop = 2000 - aux_pwm  'calculo del tiempo de la señal de control a OFF
  122.                 aux_pwm_nop = 65535 - ((aux_pwm_nop * 100) / 5)  'valor a cargar en el timer1, OFF
  123.                 aux_pwm = 65535 - ((aux_pwm * 100) / 5)  'valor a cargar en el timer1, ON
  124.                 pwm = aux_pwm  'se cambia de long a word, para acelerar la rutina de interrupciones
  125.                 pwm_nop = aux_pwm_nop  'se cambia de long a word, para acelerar la rutina de interrupciones
  126.                 Gosub print_lcd  'salto con retorno a la rutina que muestra los dato por el display
  127.                 tiempo_ms = ((reg_timer1 - pwm) * 5) / 100  'calculo en mSeg.
  128.                 division = dvsion_dcmles(tiempo_ms, factor_escala)  'llama a la funcion dvsion_dcmles,
  129.                                                                                                                                                         'que retorna un Long
  130.                 Gosub formato_decimales  'extrae e imprime con formato decimal
  131.                 timer1_20ms = 0
  132.         Endif
  133. Goto main  'impide que termine el programa principal
  134. End  'es conveniente ponerlo siempre segun el manual
  135. formato_decimales:  '____________________da formato a los decimales y los saca por el lcd
  136.         entero = division.HW  'sede el word alto a entero, parte entera
  137.         decimal = division.LW  'sede el byte alto del word bajo a decimal_1
  138.         Lcdout #entero, "."  'muestra los datos en el lcd
  139.         If decimal < 10 Then Lcdout "0"  'mantiene la plantilla de los decimales, quitar para 1 decimal
  140.         Lcdout #decimal, "         "  'muestra los datos en el lcd
  141. Return                                            
  142. '--------------------------------------Subrrutina lectura ADC
  143. lee_adc:  '_______________________lee la entrada analogica
  144.         Adcin 4, adc_4  'lee el valor de la entrada analogica y lo carga en adc_4
  145. Return                                            
  146. print_lcd:  '____________________muestra los datos por el display
  147.         Lcdcmdout LcdLine1Home  'cursor al principio
  148.         Lcdout "ADC--TMR1--mSeg."  'magnitudes
  149.         Lcdcmdout LcdLine2Home  'selecciona la linea dos del lcd y cursor a inicio
  150.         If adc_4 < 1000 Then Lcdout "0"  'para mantener la plantilla
  151.         If adc_4 < 100 Then Lcdout "0"  'para mantener la plantilla
  152.         If adc_4 < 10 Then Lcdout "0"  'para mantener la plantilla de salida
  153.         Lcdout #adc_4, " ", #pwm, " "  'muestra los datos en el lcd
  154. Return                                            
  155. '________Argumentos de entrada dos variables tipo word, dividendo y divisor,
  156. '________argumento de salida una variable tipo Long
  157. Function dvsion_dcmles(dvdo As Word, dvsor As Word) As Long  '_Rutina funcion division con decimales
  158.         Dim f_entera As Word  'variable local, contendra la parte entera
  159.         Dim f_resto As Word  'varable local, contendra el resto
  160.         Dim f_decimal As Long  'contendra la parte decimal
  161.         f_entera = dvdo / dvsor  'obtengo la division
  162.         f_resto = dvdo Mod dvsor  'obtengo el resto
  163.         f_decimal = (f_resto * 100) / dvsor  'Multiplicar 1xx seguido de tantos ceros como decimales
  164.         dvsion_dcmles.HW = f_entera  'almacena la parte entera en el word alto
  165.         dvsion_dcmles.LW = f_decimal  'almacena la parte decimal word bajo
  166.         'Recuerda que la parte decimal tiene que ser mostrada en el display con plantilla
  167.         'especial en este caso de dos digitos
  168. End Function                                      
  169. '--------------------------------Interrupciones---------------------------------------------------
  170. On Interrupt  'Comienzan las rutinas de las interrupciones, desactiva las interrupciones
  171. 'Save System  'Guarda los valores del sistema para poder reemprender el curso normal del programa
  172. '___________Rutina generadora del PWM, para la entrada de control del servomotor
  173.         If flag1_pwm = 1 Then  'controla el tiempo de la señal del servo a OFF
  174.                 RB4 = 0  'salida del servo a OFF
  175.                 TMR1H = timer_pwm_nop.HB  'recarga el contador del timer1 para que desborde, tiempo a off
  176.                 TMR1L = timer_pwm_nop.LB  'recarga el contador del timer1 para que desborde, tiempo a off
  177.                 flag1_pwm = 0  'permite la alternancia entre señal del servo a ON o a OFF
  178.                 timer_pwm = pwm  'recarga la rutina con los nuevos valores del potenciometro
  179.                 timer_pwm_nop = pwm_nop  'recarga la rutina con los nuevos valores del potenciometro
  180.                 If timer1_20ms < timer1_20ms_tiempo Then timer1_20ms = timer1_20ms + 1
  181.         Else
  182.                 RB4 = 1  'salida de la señal de contol del servo a ON
  183.                 TMR1H = timer_pwm.HB  'recarga el contador del timer1 para que desborde, tiempo a on
  184.                 TMR1L = timer_pwm.LB  'recarga el contador del timer1 para que desborde, tiempo a on
  185.                 flag1_pwm = 1  'permite la alternancia entre señal del servo a ON o a OFF
  186.         Endif
  187.         PIR1.TMR1IF = 0  'borra el flag de salto del tmr1
  188. Resume  'activa las interrupciones y retorna al curso normal del programa antes del salto
  189. End
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 30 de Julio de 2007, 23:05:34
dogflu, estuve mirando tu codigo y me cuesta un poco entenderlo... pero tampoco me soluciona nada, porque me di cuenta que el fallo no esta en la configuracion del pic, sino que al programarlo, no se graba la configuracion (la posicion 0x2007 no tiene lo que deberia), todo lo demas se graba correctamente, excepto la configuracion... :cry:
estoy viendo que esto tambien me ocurre con los pic 16f648a...
es raro porque hace unos dias funcionaba todo bien
no se q podra ser...
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 02 de Agosto de 2007, 18:58:03
Efectivamente a=a+1 es igual a a += 1 y necesita tres posiciones de memoria, dos para los operandos (la variable "a" y "1") mas una posición para la operación con los operandos (+). Sin embargo ++a y a++ solo utilizan dos posiciones, una para la variable y otra para la operación (el 1 es implicito, mientras con la otra instrucción puedes incrementar lo que quieras, con esta solo puedes incrementar la unidad).

Un saludo.

es curioso, apartandome un poco del tema de los servos y volviendo sobre la cantidad de instrucciones que ocupa algo, me di cuenta de lo siguiente:
en el codigo, "ServoActivo" es una variable INT1
Código: C
  1. if(input(PIN_A0) == TRUE)
  2.    ServoActivo = FALSE;
  3. else
  4.    ServoActivo = TRUE;
esto ocupa 12 posiciones de memoria

ahora, hacer esto:
Código: C
  1. ServoActivo = !input(PIN_A0);
ocupa 8 posiciones de memoria...

y esto:
Código: C
  1. ServoActivo = input(PIN_A0);
ocupa 6 posiciones de memoria... aunque en este caso nos daria el valor contrario a los anteriores, para quie esto no ocurra se puede invertir la la logica del hard...

con lo que evitando el if ya ahorramos 4 posiciones... y si nos evitamos la negacion, nos ahorramos 2 posiciones mas...
jfh900 o alguno que entienda mas a fondo el compilador podria decirme que es lo que se compila en cada caso?
y sobre todo... una posicion de memoria se ejecuta en un cliclo? por ejemlo, si mi micro corre a 4mhz, tardare 10uS en ejecutar 10 posiciones de memoria?
gracias y ahora me pongo otra vez con lo servos  :D
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 03 de Agosto de 2007, 02:05:09
Por alguna razón, tu versión de CCS y la mía no compilan de la misma forma, y la mía compila mejor.

Código: [Seleccionar]
....................    if(input(PIN_A0) == TRUE)
03C0:  MOVLW  00
03C2:  BTFSC  F80.0
03C4:  MOVLW  01
03C6:  SUBLW  01
03C8:  BNZ   03CE
....................          ServoActivo = FALSE;
03CA:  CLRF   2C
....................      else
03CC:  BRA    03D2
....................          ServoActivo = TRUE;
03CE:  MOVLW  01
03D0:  MOVWF  2C

Este primer caso lo compila en 9 instrucciones en lugar de 12.

Código: [Seleccionar]
....................    ServoActivo = !input(PIN_A0);
03D2:  CLRF   2C
03D4:  BTFSS  F80.0
03D6:  INCF   2C,F

Aquí ocupa sólo 3 posiciones en lugar de las 6 que te ocupa a ti.

Código: [Seleccionar]
....................    ServoActivo = input(PIN_A0);
03D8:  CLRF   2C
03DA:  BTFSC  F80.0
03DC:  INCF   2C,F

Y por supuesto, su negación ocupa exactamente lo mismo porque no tiene lógica que ocupe menos: 3 posiciones.

Utilizo la versión 3.242 y estos listados de assembler los puedes ver tú mismo en el menú View -> C/ASM List.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Marttyn en 03 de Agosto de 2007, 13:40:43
tienes media verdad manolo.... y yo tengo la otra  :P
estuve haciendo unas cuantas pruebas y llegue a la conclusion que tu tienes declarado el puerto como "fast_io"... y yo lo tenia como "standard_io" es por eso las diferencias en la cantidad de instrucciones.
la verdad nunca me habia parado a pensar en esto, siempre use standard para olvidarme de tener que configurar los puertos, pero por lo visto compensa bastante tenerlos declarados correctamente. sobre todo en el tema de los servos, porque como hemos visto antes, mientras menos instrucciones, menos retrasos y mejor funcionaran.
ya puedo tener por seguro que usando esto puedo aumentar la presicion para el el tema de controlar 2 servos. en el programa que estoy haciendo ahora controlaba 4 servos (sin pot) y pase de 56 a 28 instrucciones en el timer1 solo con esto!!
y por cierto... el fixed_io, usa 7 instrucciones para hacer lo mismo... por lo visto el fast_io es el mejor... :-/
lo que no entiendo es porque a ti te compila con instrucciones diferentes que las mias usando los dos el fast:
el tuyo:
Código: ASM
  1. ....................    ServoActivo = input(PIN_A0);
  2. 03D8:  CLRF   2C
  3. 03DA:  BTFSC  F80.0
  4. 03DC:  INCF   2C,F

y el mio:
Código: ASM
  1. ....................       ServoActivo = input(PIN_A0);
  2. 0011:  BCF    20.0
  3. 0012:  BTFSC  05.0
  4. 0013:  BSF    20.0

sera porque usamos pics diferentes? el mio es un 16f88...
salu2
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 03 de Agosto de 2007, 13:43:15
Pos va a ser que sí, el mío es un 18F4550.
Enhorabuena, ya va saliendo.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: jfh900 en 10 de Agosto de 2007, 13:26:37
Una pregunta Manolo, en:

Código: [Seleccionar]
....................    ServoActivo = !input(PIN_A0);
03D2:  CLRF   2C
03D4:  BTFSS  F80.0
03D6:  INCF   2C,F

Desde 03D2 a 03D6 van 5 posiciones de memoria y si tenemos en cuenta que para la última instrucción hacen falta dos posiciones (instrucción + operando) eso nos daría 6 posiciones de memoria (tres instrucciones que ocupan 6 posiciones de memoria), no?

Un saludo
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: Nocturno en 10 de Agosto de 2007, 13:37:52
Sí, Jesús, exacto, cuando dije posiciones debía haber dicho instrucciones.
Título: Re: mi servo no se queda quieto (NUEVO RETO)
Publicado por: mandoanaiz en 30 de Agosto de 2007, 11:51:16
Help, Houston tengo un froblema.
Habia hecho algo parecido que no terminaba de funcionar como debe de ser, y por esas cosas del curro se traspapeló, al ver el hilo me he estudiado el programita (por cierto mejor hecho que el mio) y al simularlo en protues me da un error con la simulación del rotor.dll y otras cosas raras, alguien sabe como solucionarlo?
Gracias de antemano.
PD adjunto una imagen de los errores.