TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Tho0oR en 08 de Junio de 2008, 13:17:35

Título: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 08 de Junio de 2008, 13:17:35
Buenos dias !!

Tengo un problema que es la mayor tonteria del mundo, que por empeño o por cabeza cuadrada no consigo ver!!
Estoy haciendo un programa, que maneja un servomotor (HS311).

El servo motor, tiene un sistema de control por PWM. (Pulso de 1.5ms le pone al medio). Esto es decir, le tengo que meter una señal de 3ms de periodo y con el PWM ir modificando el pulso alto. Bien, hasta ahi, todo perfecto.

configuro el CCP como PWM, y configuro tambien el timer2, para que me saque una señal de 3ms de periodo. Eso esta conseguido. de hecho, mi programa funciona perfectamente salvo por la tonteria siguiente:


la entrada, es analogica. Utilizo la entrada RA0 con un potenciometro, para dependiendo de como situe el potenciometro, el servo adquiera una posicion u otra.

El problema, esque el servo recorre todo su recorrido, en un pequeño tramo del potenciometro. Eso en realidad es una chorrada... pero me gustaria, que el recorrido del motor, se ajuste al recorrido completo del potenciometro.

Esta claro que es la configuracion del CAD... pero chicos... soy muy tonto y no soy capaz de configurarlo bien... es mas, poniendo valores dispares y al azar... ni siquiera el resultado cambia (lo he intentado hacer a ojo).

Os dejo el codigo:

#include <16F877.h>
#FUSES XT
#use delay(clock=4000000)


void main()                                    //PROGRAMA PRINCIPAL
{

int lectura =0;
float final;
SET_TRIS_C(11111011);                          //RC2 salida (por RC2 vamos a sacar el control para el servo)
SETUP_CCP1(CCP_PWM);                           //CCP1 como PWM
SET_TIMER2(1);                               //cargo 0xAA en el timer 2
setup_timer_2(T2_DIV_BY_16,46,1);
RA0_ANALOG;
setup_ADC(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
setup_adc_ports(ALL_ANALOG);
delay_us(50);
do
   {
   lectura = read_adc();                    //lee el valor del potenciometro
   final = lectura*0.10;                       //pasa el valor a un rango de 0 a 5
   SET_PWM1_DUTY(lectura);                  //cargo el valor 0-256 al PWM
   delay_ms(20);
   }while(true);
}



y aver si se adjuntar una imagen del circuito que tengo montado  :D.

Si me podeis ayudar, perfecto!!! sino, pos aver si apaño algo.

De cualquier forma, aqui tene un codigo el que quiera manejar un servomotor!!  :mrgreen:



Un saludo amigos!!


Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 08 de Junio de 2008, 13:19:40
Aqui el esquema!    Creo que no lo dije antes, la diferencia de potencial en RA0 es de 5V... el servo trabaja en el rango desde 0 a 0.70V. entre esos valores, recorre todas sus posiciones
Título: Re: Configuracion de un ADC para un servo
Publicado por: Gonzalo_BlackHawk en 08 de Junio de 2008, 14:06:15
Hola Tho0or, el problema es el siguiente, o por lo menos a mi modo de ver lo es:

Código: [Seleccionar]
int lectura =0;
Estas definiendo a lectura como variable de 8 bits, es decir, que varia de 0 a 255.

Código: [Seleccionar]
lectura = read_adc();
Aqui estas leyendo el ADC y guardando el valor en un variable de 8 bits, el problema es que en forma predeterminada la función read_adc() devuelve un valor de 10 bits!!! Por lo tanto la variable lectura alcanza su rango máximo en 1/4 del recorrido total del potenciómetro y por lo tanto el PWM tambien. Lo que debes hacer es incluir el preprocesador #device adc=8 luego de #include <16F877.h> . Esta linea #device adc=8 le indica al compilador que la función read_adc debe devolver un valor de 8 bits, es decir que cuando tenemos 0V en la entrada analógica tenemos un 0 y cuando tenemos 5V tendremos 255 (Antes variaba de 0 a 1023).

Si funciona luego podremos corregir otras cosas como el reloj del ADC que no esta correctamente configurado, pero vayamos por partes.

Saludos.

Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 08 de Junio de 2008, 14:34:53
Mu buenas amigo!!


Nose que me pasa! ha sido cambiar eso y la simulacion me ha dejado de funcionar. El frecuencimetro me sale en 00000000

El caso esque e cargado mi programa anterior, y sige asi... es el proteus??

Te adjunto el arhcivo de simulacion con el .cof por si aca tenes el proteus tu vale??

ya me contaras


y gracias por la respuesta, tenia que haber tenido eso en cuenta... eres un crack!
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 08 de Junio de 2008, 14:47:56
He vuelto a hacer la simulacion de 0 y ya simula bien. Sigo igual. El servo funciona en el rango desde los 0.20V a los 0.7V

mmmm Se te ocurre algo?
jajajaja

no te comas mucho la cabeza, gracias por haberme dicho ese detalle! :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: pocher en 08 de Junio de 2008, 15:55:23
Gonzalo creo que es al revés, por omisión del #device la conversión es a 8 bits. Si quieres 10 bits es cuando debes de incluir el #device adc=10
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 08 de Junio de 2008, 16:14:49
eso creia yo, pero he visto a gonzalo tan convencido que he pensao que sino decia nada, el por defecto es de 10 bits... de todas formas no hay nada como mirar el datasheet y realmente, como dice pocher, los bits de resolucion de serie del CAD son 8 bits.

de todas formas, gonzalo tenia que decirme algo sobre el clock del CAD, y aqui hago un inciso. Hace poco, observe un warning del proteus a la hora de simular, y me decia:
[PIC16 ADC] PC=0X001F. ADC conversion clock period (1e-06) is possibly invalid for device clock frequency

estube comiendo la cabeza para ver como lo solucionaba, pero desisti cuando en un foro de ISIS vi a un chico que decia que es un "falso warning" que da proteus. Realmente, aun estando ese warning, todo funciona correctamente asique supongo que sea un falso warning.

por eso me encantaria oir lo que piensa gonzalo sobre el reloj del CAD, aver si da un poco de luz al warning.



Podrias ayudarme tu Pocher?


Un saludooo!!! :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: Gonzalo_BlackHawk en 08 de Junio de 2008, 20:59:25
eso creia yo, pero he visto a gonzalo tan convencido que he pensao que sino decia nada, el por defecto es de 10 bits... de todas formas no hay nada como mirar el datasheet y realmente, como dice pocher, los bits de resolucion de serie del CAD son 8 bits.

Pocher tenia toda la razón, el compilador justifica el resultado en 8 bits cuando hay omisión de #device adc=x. Por lógica supuse que como el ADC es de 10 bits, el resultado predeterminado que definiria el compilador sería de 10 bits, pero bueno, una vez más se demuestra que CCS no siempre sigue la misma lógica que nosotros. Corrijo mi afirmación y pido disculpas por el error.

Ahora bien, creo que lo que expresa Tho0or no es correcto, los bits de resolución del ADC son 10 bits y en realidad esto nunca cambia por más que pongamos el código que pongamos. El PIC posee dos bytes asociados a los registros ADRESH:ADRESL donde coloca el resultado de la conversión y este valor puede ser justificado en un valor de 10 bits o 16 bits según el bit de configuración ADFM del registro ADCON1, es decir que en realidad por HW no podemos obtener un valor de 8 bits del ADC, la magia sucede que cuando colocamos #device adc=8 (o simplemente no colocamos nada) el compilador se encarga de generar solito la operación de desplazamiento de bits para llevar el resultado de 2 bytes a uno solo.
De todas formas, me alegro haber aprendido algo mas sobre CCS, son detalles que a uno se le escapan y siempre viene bien que se lo recuerden  :-).

de todas formas, gonzalo tenia que decirme algo sobre el clock del CAD, y aqui hago un inciso. Hace poco, observe un warning del proteus a la hora de simular, y me decia:
[PIC16 ADC] PC=0X001F. ADC conversion clock period (1e-06) is possibly invalid for device clock frequency
estube comiendo la cabeza para ver como lo solucionaba, pero desisti cuando en un foro de ISIS vi a un chico que decia que es un "falso warning" que da proteus. Realmente, aun estando ese warning, todo funciona correctamente asique supongo que sea un falso warning.

Proteus no da tal cosa como un "falso warning". El chico que dijo que a ese warning no habia que darle importancia parecería que a lo que no le dio importancia es a leer el datasheet del PIC, en la sección A/D Converter :D.
Primero recomiendo que leas este (http://www.todopic.com.ar/foros/index.php?topic=21209.msg169103#msg169103) post, aqui debatimos con bastante profundidad el tema de la selección del reloj para el ADC.
Como te enteraras en ese post, no es recomendable bajar el TAD del ADC a menos de 1,6 us ya que a partir de ese punto se empieza a perder precisión a un ritmo alarmante. El warning "ADC conversion clock period (1e-06) is possibly invalid for device clock frequency" indica que ese tiempo TAD ha descendido por debajo del limite de los 1,6 us (fijate que el numero entre parentesis indica el tiempo de muestreo y 1e-06 es menor que 1,6e-06) yque por lo tanto no es recomendable para la frecuencia a la que esta trabajando el PIC. Este warning en general se produce por una mala configuración del reloj del ADC. Es normal que este warning se emita una vez durante el arranque del PIC antes de que el código llegue a la instrucción setup_adc(); pero si lo hace en forma repetitiva durante cada lectura del mismo, le has errado en la configuración.

Para evitar ese warning deberias reemplazar la instrucción setup_adc(ADC_CLOCK_INTERNAL); en tu código por la siguiente:

Código: [Seleccionar]
setup_adc(ADC_CLOCK_DIV_8);
Esta es la mejor configuración para tu modelo de PIC y frecuencia de reloj (4 MHz) y tendrás un TAD de 2 us, bastante aceptable.

Ahora vamos con tu problema del servo, creo que configuraste mal el PWM. Si necesitas un período de 3ms, es decir una frecuencia de 333,33 Hz, la más proxima que puedes alcanzar es 332,447 Hz, que se logra con la siguiente configuración del timer 2:

PR2 = 187
Preescalador = 1/16
Postescalador = Indistinto

Por lo tanto la instrucción setup_timer_2() deberia quedar asi:

Código: [Seleccionar]
setup_timer_2(T2_DIV_BY_16,187,1);
Prueba y nos cuentas, pude haberme equivocado. De todas formas no tienes plena resolución a esta frecuencia y alcanzaras el 100% del duty en un valor menor a los 255, si mis calculos no me fallan cuando set_pwm_duty(187) el PWM ya alcanzará su máximo duty. Tambien prueba esto y nos dices. A trabajar se ha dicho  :mrgreen:, esperamos tus resultados.

0x01 saludo.
Título: Re: Configuracion de un ADC para un servo
Publicado por: firepic en 08 de Junio de 2008, 23:43:19
Saludos!

Aquí me parece que estás en un grave error:
El servo motor, tiene un sistema de control por PWM. (Pulso de 1.5ms le pone al medio). Esto es decir, le tengo que meter una señal de 3ms de periodo y con el PWM ir modificando el pulso alto. Bien, hasta ahi, todo perfecto.

configuro el CCP como PWM, y configuro tambien el timer2, para que me saque una señal de 3ms de periodo.
Viejo, la señal para ese servo no es 3ms de período, sino 20ms, pues trabaja a 50Hz.
Si no me crees puedes ver el datasheet en esta página: http://www.hitecrcd.com/servos/show?name=HS-311 (http://www.hitecrcd.com/servos/show?name=HS-311)

Donde sí estás en lo cierto es que con un pulso de 1.5ms pone al servo en el medio... luego con 0.9ms y 2.1ms en los otros extremos.
Si sacas unas cuenticas creo que el resultado va a ser que no vas a poder controlar el servo usando la instrucción de CCS para el PWM, pues no te va a dar un período de 20ms... se te queda corto el timer2.
Es por eso que para manejar el servo vas a necesitar usar interrupciones. Es la forma como lo hace el maestro Diego RedPic en un hilo por allí, puedes usar el buscador para buscarlo. Creo que hay uno que se llama "Manejando 8 servos con una sóla interrupción".

Yo hice hace poco exactamente el programa que tú necesitas... ahorita no consigo exactamente el que hice para ese momento, tengo es uno que controla los servos pero hace otras cosas también... está modificado...
Pero te coloco el código relevante para los servos y tú lo puedes adaptar a tus propias necesidades:

Código: C
  1. int ajusta_pwm (int servo)                              //Esta funci&#243;n fija los par&#225;metros para el siguiente pulso de la PWM.
  2.  
  3. {
  4.  
  5.         float escala=0;
  6.  
  7.         switch (servo)
  8.  
  9.         {
  10.  
  11.                 case 1: valor=conversion(0);
  12.  
  13.                                 break;
  14.  
  15.                 case 2: valor=conversion(1);
  16.  
  17.                                 break;
  18.  
  19.                 case 3: valor=conversion(3);
  20.  
  21.                                 break;
  22.  
  23.         }
  24.  
  25.         escala=1024/(tmr_pulso_maximo-tmr_pulso_minimo);        //Escala para convertir a un valor que se cargar&#225; a timer0
  26.  
  27.         ancho_pulso=(int)(valor/escala);                                        //y es proporcional al ancho de pulso deseado.
  28.  
  29.         ancho_pulso=256-tmr_pulso_minimo-ancho_pulso;           //El valor se carga en el timer.
  30.  
  31.         return (ancho_pulso);
  32.  
  33. }
  34.  
  35.  
  36.  
  37. /* Funci&#243;n de interrupci&#243;n por sobreflujo en timer 0 */
  38.  
  39. /* Esta funci&#243;n genera la PWM que controla los 3 servos */
  40.  
  41. #INT_RTCC
  42.  
  43. RTCC_isr ()
  44.  
  45. {
  46.  
  47.         switch (i)
  48.  
  49.         {
  50.  
  51.                 case 0:
  52.  
  53.                         output_high (servo_1);
  54.  
  55.                         tiempo = tiempo_s1;
  56.  
  57.                         flag_pulso=0;
  58.  
  59.                         i++;
  60.  
  61.                         break;
  62.  
  63.                 case 1:
  64.  
  65.                         output_low (servo_1);
  66.  
  67.                         tiempo = 255 - (tmr_pulso_maximo - tiempo_s1);
  68.  
  69.                         //tiempo = 255 - (tmr_pulso_maximo - tmr_pulso_medio);
  70.  
  71.                         i++;
  72.  
  73.                         break;
  74.  
  75.                 case 2:
  76.  
  77.                         output_high (servo_2);
  78.  
  79.                         tiempo = tiempo_s2;
  80.  
  81.                         //tiempo = 255 - tmr_pulso_maximo;
  82.  
  83.                         i++;
  84.  
  85.                         break;
  86.  
  87.                 case 3:
  88.  
  89.                         output_low (servo_2);
  90.  
  91.                         tiempo = 255 - (tmr_pulso_maximo - tiempo_s2);
  92.  
  93.                         //tiempo = 255 - (tmr_pulso_maximo - tmr_pulso_maximo);
  94.  
  95.                         i++;
  96.  
  97.                         break;                 
  98.  
  99.                 case 4:
  100.  
  101.                         output_high (servo_3);
  102.  
  103.                         tiempo = tiempo_s3;
  104.  
  105.                         //tiempo = 255 - tmr_pulso_minimo;
  106.  
  107.                         i++;
  108.  
  109.                         break;
  110.  
  111.                 case 5:
  112.  
  113.                         output_low (servo_3);
  114.  
  115.                         tiempo = 256 - (tmr_pulso_maximo - tiempo_s3);
  116.  
  117.                         //tiempo = 256 - (tmr_pulso_maximo - tmr_pulso_minimo);
  118.  
  119.                         i++;
  120.  
  121.                         break;                 
  122.  
  123.                 default:
  124.  
  125.                         tiempo = 256 - tmr_pulso_maximo;
  126.  
  127.                         flag_pulso=1;
  128.  
  129.                         i++;
  130.  
  131.                         break;
  132.  
  133.         }
  134.  
  135.         if (i==10) i=0;
  136.  
  137.         set_rtcc(tiempo);
  138.  
  139. }
  140.  
  141.  
  142.  
  143. /* Programa principal */
  144.  
  145. main()
  146.  
  147. {
  148.  
  149.         envio_serial(0);                                                        //Para mostrar el mensaje inicial por puerto serial
  150.  
  151.         tiempo_s1=ajusta_pwm(1);
  152.  
  153.         tiempo_s2=ajusta_pwm(2);
  154.  
  155.         tiempo_s3=ajusta_pwm(3);
  156.  
  157.         j=0;                                                                            //contador para calcular DCM del aceler&#243;metro
  158.  
  159.         setup_adc(ADC_CLOCK_INTERNAL);
  160.  
  161.         setup_adc_ports(RA0_RA1_RA3_ANALOG);
  162.  
  163.         setup_counters(RTCC_INTERNAL,RTCC_DIV_64);      //Configura el timer0 (RTCC), aqu&#237; uso pre-escala de 1:64
  164.  
  165.         enable_interrupts(INT_RTCC);                            //Habilita interrupci&#243;n por sobreflujo en timer0
  166.  
  167.         enable_interrupts(GLOBAL);                                      //Habilita interrupciones globales
  168.  
  169.         i=0;                                                                            //valor que debe tener "i" (contador) para que
  170.  
  171.         RTCC_isr();                                                                     //cuando entre a esta funci&#243;n coloque la se&#241;al a 1 (inicia pulso).
  172.  
  173.         while(TRUE)                                                                     //Un ciclo infinito.
  174.  
  175.         {
  176.  
  177.                 if (flag_pulso==1)
  178.  
  179.                 {
  180.  
  181.                         tiempo_s1=ajusta_pwm(1);
  182.  
  183.                         tiempo_s2=ajusta_pwm(2);
  184.  
  185.                         tiempo_s3=ajusta_pwm(3);
  186.  
  187.                 }
  188.  
  189.         }
  190.  
  191. }

Y hay unas constantes que tienes que definir al principio del programa y que están relacionadas con el tiempo de 0.9ms, 1.5ms y 2.1ms...
Son estas:

Código: C
  1. /* Definici&#243;n de Constantes */
  2.  
  3. const int tmr_pulso_minimo = 50;
  4.  
  5. const int tmr_pulso_medio&#160; = 117;
  6.  
  7. const int tmr_pulso_maximo = 195;
  8.  
  9. const int precarga_tmr = 33;
  10.  
  11. const int16 periodo = 1563;

Disculpa que no te dé el código completo... en cuanto lo consiga trataré de publicarlo...
Pero ahí tienes para que vayas analizando la cosa... yo había hecho un hilo explicando el funcionamiento de este programa, pero me parece que luego no lo encontré... creo que tal vez fue borrado...

De todos modos es muy sencillo, échale una estudiadita y lo entenderás rapidamente, y así podrás hacer el tuyo.
Ok es todo por ahora, nos leemos!  :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: scientist en 09 de Junio de 2008, 00:05:29
muy cierto lo que dice el amigo firepic, el servo trabaja con frecuencias de 50 Hz, y asi como lo tenias estaba sacando una frecuencia de 333.33 Hz es por eso que no hace nada, saludos
Título: Re: Configuracion de un ADC para un servo
Publicado por: firepic en 09 de Junio de 2008, 00:15:04
Saludos scientist!
Oye, no ofendas así al gran pocher, comparándolo conmigo!   :(
Soy firepic  :D
Gracias por ratificar mi comentario.
Nos leemos!  :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: scientist en 09 de Junio de 2008, 02:24:29
upssss  :lol:, disculpa firepic ya esta corregido y mejorado, eso me pasa por leer varios hilos a la vez, no volvera a pasar, tendre que achacarselo a que es de madrugada, jejeje, saludos
Título: Re: Configuracion de un ADC para un servo
Publicado por: Gonzalo_BlackHawk en 09 de Junio de 2008, 03:34:11
Hola a todos.

Citar
Oye, no ofendas así al gran pocher, comparándolo conmigo!   Sad

Vaya uno a saber que paso, no, mejor no, no quiero saberlo  :-/.

Bueno, Firepic, te agradezco, ni se me habia ocurrido revisar el datasheet del servo, confie plenamente en lo que tho0or expreso cuando enunció su problema, bueno, son cosas que pasan  :mrgreen:.

Saludos.
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 09 de Junio de 2008, 05:33:17
Citar
Bueno, Firepic, te agradezco, ni se me habia ocurrido revisar el datasheet del servo, confie plenamente en lo que tho0or expreso cuando enunció su problema, bueno, son cosas que pasan 

Realmente me lei el datasheet, pero me fie de mi asquerosa logica aplastante y cuando lei que 1.5ms es la mitad del recorrido, supuse mentalmente 0 y 3ms eran los extremos. Realmente si siges leyendo te dice que la frecuencia de funcionamiento es de 50Hz y por lo tanto, el periodo 1/50 es de 20ms.

Perdonarme todos!!! ha sido un fallo garrafal de esos.

Citar
muy cierto lo que dice el amigo firepic, el servo trabaja con frecuencias de 50 Hz, y asi como lo tenias estaba sacando una frecuencia de 333.33 Hz es por eso que no hace nada, saludos

Lo modifique un poco los tiempos y si que funciona, se desplaza desde -90 a + 90 en un rango de tension de 1.2V - 2.5V

Pero realmente, creo que si funciona, es de casualidad, porque lo que decis todos vosotros, deberia haberlo tenido en cuenta y no lo he hecho.


Citar
Yo hice hace poco exactamente el programa que tú necesitas... ahorita no consigo exactamente el que hice para ese momento, tengo es uno que controla los servos pero hace otras cosas también... está modificado...
Pero te coloco el código relevante para los servos y tú lo puedes adaptar a tus propias necesidades:

Gracias por esa guia que me has dejado, la verdad esque menudo crack es RedPick dios mio... aver si algun dia acabo haciendo algo parecido a el...

Pues muchisimas gracias a todos por vuestra ayuda e? en especial a Gonzalo y firepick que han estado ahi luchando contra mi ignorancia :D!!!

Os indicare mis resultados!!

Cualquier cosa, seguir escribiendo por aqui!!
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 09 de Junio de 2008, 05:37:03
Por cierto gonzalo, gracias por la contestacion de la configuracion del relog del ADC. Como me alegro de saberlo, ademas, me se de una persona, que en cuanto se lo cuente, va a sonreir de oreja a oreja. (dire que me lo comentaron en un foro  8) ) un Saludooo
Título: Re: Configuracion de un ADC para un servo
Publicado por: firepic en 09 de Junio de 2008, 09:36:34
En cuanto a esto:
Si sacas unas cuenticas creo que el resultado va a ser que no vas a poder controlar el servo usando la instrucción de CCS para el PWM, pues no te va a dar un período de 20ms... se te queda corto el timer2.

Creo que el que tengo que sacar cuentas soy yo  :D
Me fijé bien que tú estás usando un cristal de 4MHz, de manera que el timer2 podrá contar hasta un período de unos 65ms si mis cálculos son correctos (me corriges si no es así eh Gonzalo).
Yo sí tuve que hacerlo con interrupciones porque uso cristal de 20MHz, así que el máximo período es de unos 13ms...  :D

Bueno pues me alegro que Tho0oR haya resuelto su problema, felicidades viejo!
Y no te preocupes, que para eso estamos aquí en el foro, para ayudarnos.

Citar
Oye, no ofendas así al gran pocher, comparándolo conmigo!
Vaya uno a saber que paso, no, mejor no, no quiero saberlo  :-/.
Para que no se quede como incógnita, lo que pasó fue que scientist en su primer post había colocado "el amigo pocher", en lugar de "el amigo firepic"... por eso dije que realmente es una ofensa al gran pocher el compararlo conmigo.
Menos mal que scientist lo arregló ya... por cierto, gracias por eso scientist!  :P

Saludos, nos leemos!  :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: Gonzalo_BlackHawk en 09 de Junio de 2008, 18:11:15
Hola firepic.

El PWM solo puede funcionar a una frecuencia minima de 244,141 Hz es decir un periodo de 4,1 ms cuando el prescalador es igual a 1:16 y PR2 es maximo es decir 255. Como el postescalador no se aplica para el PWM, no es posible obtener frecuencias menores a estas. Por lo tanto en el 16F877 no es posible tener un PWM de 50 Hz. Tho0or, Tendrás que hacerlo con interrupciones.

Saludos.
Título: Re: Configuracion de un ADC para un servo
Publicado por: firepic en 09 de Junio de 2008, 19:44:23
Qué tal Gonzalo!
Gracias por la aclaratoria. No sabía que el postescalador no se aplicaba en el PWM. Me dió curiosidad y revisé la datasheet, y en efecto es como tú dices. Hay un recuadrito que justamente dice: "the timer2 postcaler is not used in the determination of the PWM frequency". Muy interesante, gracias!  :P
Bueno pues nada Tho0or, a darle con las interrupciones  :D
Esperamos tus resultados, nos leemos!  :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 10 de Junio de 2008, 04:14:28
buuufffff!!!


Lo que esta aprendiendo uno a base de andar por estos mundos. Gracias a todos, pero hay una cosa que deberiais saber, soy bastante novato y la unica interrupcion que he usado ha sido la de RB0 con una variable booleana para alternar 2 partes del codigo. En cuanto a las interrupciones del timer2, todavia no he mirado nada.

De momento bajare la frecuencia a 1Mhz. Pero tengo que aprender a usar las interrupciones del timer2. Algun post, link o algo interesante para "estudiar"?


Gracias amigooos!!!  :mrgreen:
Título: Re: Configuracion de un ADC para un servo
Publicado por: Tho0oR en 10 de Junio de 2008, 06:16:39
Este codigo hecho para los 4 Mhz hace funcionar perfectamente al servo sin necesidad de interrupciones. He ajustado un poco el timer2 y ademas e creado una nueva variable de "correccion" para la conversion adc cuando la mete al PWM. Aver si os gusta, y os parece una chapuza!  :mrgreen:

#include <16F877.h>
#FUSES XT
#use delay(clock=4000000)                  
void main()                                    //PROGRAMA PRINCIPAL
{
float a=2.5;
long lectura=0;
SET_TRIS_C(11111011);                          //RC2 salida (por RC2 vamos a sacar el control para el servo)
SETUP_CCP1(CCP_PWM);                          //CCP1 como PWM
setup_timer_2(T2_DIV_BY_16,185,1);
RA0_ANALOG;
setup_ADC(ADC_CLOCK_INTERNAL);
setup_adc_ports(ALL_ANALOG);
set_adc_channel(0);
do
   {
   lectura = read_adc()*a;                    //lee el valor del potenciometro y lo multiplica por una constante que corrige el valor
   SET_PWM1_DUTY(lectura);                 
   delay_ms(20);
   }while(true);
}


os dejo ademas el archivo de simulacion por si quereis probarlo!!
Título: Re: Configuracion de un ADC para un servo
Publicado por: firepic en 10 de Junio de 2008, 11:52:09
No creo que sea buena idea eso del período a 3ms como lo tienes ahora.
No conozco el entero funcionamiento de los servos, pero siempre trabajo bajo la premisa que el fabricante lo conoce mejor y hay que respetar sus especificaciones.
Trabajar con interrupciones no es tan difícil, si ya lo has hecho, pues ahora lo que vas a hacer es cambiar de interrupción. Yo creo que sí puedes.
Ahora bien, si quieres trabajarlo así, sin interrupciones, es tu decisión. Pero entonces por lo menos coloca:
Código: [Seleccionar]
setup_timer_2(T2_DIV_BY_16,255,1);
Para que aunque sea el período sea de unos 4ms...

En cuanto a esto:
y ademas e creado una nueva variable de "correccion" para la conversion adc cuando la mete al PWM.
Así como lo estás haciendo está medio extraño.
Porque estás multiplicando el valor leído del CAD por un valor float, pero después lo guardas en un entero?
Yo te recomendaría que guardaras la lectura en una variable int16, o long; luego multipliques por el factor en float y guardes en otra variable float; y después pases la variable float a entero haciendo casting.
Aunque sinceramente, no le veo lógica a eso. ¿Qué es lo que hace exactamente esa corrección?
Porque la conversión A/D la puedes configurar a 10bits, y luego el valor de duty también es de 10bits... entonces qué necesitas corregir?
Espero haberme explicado.

Como siempre digo, sólo son sugerencias, la decisión final está en tus manos.
Nos leemos!  :mrgreen: