TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: pajaro en 02 de Julio de 2012, 17:16:51

Título: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 02 de Julio de 2012, 17:16:51
Hola

Tengo unos micro servos llamados :
tower pro sg90 tienen tres pines de colores ;marron,rojo,naranja
me gustaria saber como se conectan.

Yo en un principio conecte marron a masa , rojo a vcc 5v y naranja a pwm
pero no se mueven , cuando doy pequeños toquecitos con el cable rojo,
el servo se mueve hacia un lado.

¿Alguien ha trabajado con ellos antes?

estoy intentando simularlos en proteus pero no doy con el componente.

sigo investigando..


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: jukinch en 02 de Julio de 2012, 17:46:09
Hola Pájaro. Te paso un link con los pinout. El conector es del tipo JR.
    http://www.coastalplanes.com/articles/pinout.htm
y en este hilo http://www.todopic.com.ar/foros/index.php?topic=20918.0 hay simulaciones con proteus.
                Saludos.
               Jukinch.
(http://www.coastalplanes.com/articles/servopin.gif)
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: PCCM en 02 de Julio de 2012, 18:11:11
Tu conexión esta bien, el problema debe estar en un mal contacto, o una lógica errada de tu programación.

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 03 de Julio de 2012, 17:36:40
Hola
hay forma de saber
con que frecuencia trabaja un servo
en concreto el microservo TOWER PRO SG90
como saber cuanto tienen que pernanecer en alto y cada cuanto se les envia inpulsos
ya que no dos los servos son iguales..

Los servos tambien tienen hoja de datos?

sigo investigando..
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 03 de Julio de 2012, 18:26:20
  Por lo general en un servo analógico el período de trama es de unos 20ms  y el ancho de pulso entre 1ms y 2ms dependiendo del ángulo de movimiento. Creo que con esos tiempo se logra un recorrido de extremo a extremo de 60º
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: MLO__ en 04 de Julio de 2012, 20:56:46
Hola.

Si son de los azulitos :P  ... los he puesto a andar con un D.C minimo de 560uS y un maximo de 2.5mS .. el periodo de la senal es de unos 15.6mS


Saludos
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 09 de Julio de 2012, 14:11:46
Hola

hola 560 microsegundos:
 1 ms 1x10 exp -3
 1 us  1x10 exp -6

si dices 560 us es es la posicion inicial y la 2.5 ms es para llevar al servo al final de su posición.
si el periodo es inverso dela frecuencia le metiste uha fecuencia de 64 hercios mas o menos.

        _
_ _ _    _ _ _
       

¿Como se hace para que el servo no tiemble?

ahora hace tac (*) y chic (+) y a veces no hace ruido (-)
entonces cuando avanza hace
*++++++*++++++*++++++*++++++*++++++

*-----------*-----------*-----------*-----------*-----------


alguna idea..

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 16 de Julio de 2012, 14:38:58
hola
abri el micro servo y parece que una chapita de plastico salto

La pregunta :
¿como lo vuelvo a poner para que gire como antes?
algun manual de contratrutaje de servos.

Se agradecari alguna ide de como reparar este servo.

Un saludo.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: MLO__ en 16 de Julio de 2012, 19:13:14
Hola

En mi caso, el servo no tiembla ... se desplaza normalmente hasta la posición y ahí se queda fijo. Esos valores los obtuve experimentalmente.

Cuando inicie las pruebas si había como un "temblor" en el servo, pero fue cuestión de cambiar los valores para asignar el D.C., es como si se me hubiese pasado la mano en esa aasignacion  :oops:

Saludos
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 17 de Julio de 2012, 10:47:12
Hola
eso del D.C. a que te refieres?

leyendo por diversos enlaces y otros foros recomindan poner la frecuancia a 50Hz pero en mi caso es
imposible con cristal de 20 Mhz lo que me recomiendan en el asistente del pwm del CCS esta sobre 12khz
yo recuerdo que le ponia 20khz.

Me da un poco de palo probar en fisico, porque ya me cargue un servo,
se me truco sin querer.  :?  He pensado en ponerle un pequeño tornillo donde la pestaña para que
haga de tope pero tampoco se donde estaba la pentaña.

sigo con el asunto..
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: MLO__ en 17 de Julio de 2012, 19:28:34
Hola.

Hago referencia al ciclo de trabajo (Duty Cycle) del PWM.

Para experimentar podrías poner una senal con un periodo de unos 15mS (o cercano) y ajustar el estado HIGH a 1mS a ver como se comporta y según ese comportamiento fijar los valores máximo y mínimo.

Saludos
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 19 de Julio de 2012, 14:46:56
Hola

Como es posible averiguar el maximo o el minimo y el exacto de los putos del servo.
me refiero que sipatimos de sus 3 posiciones, izquierda,derecha y centro.

en algunas pruebas no hace ruido pero ...si se suelta el cable de control
y se vuelve a poner si aparece el ruido como un mosquito de verano de esos que pican..

Otras veces no hace ruido pero, el regulador , 7805 se calienta un cojon, no lo puedes tocar
te quemas.

sigo probando..
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 19 de Julio de 2012, 15:47:46
  En las pruebas que hice con un microservo E-Sky usé tiempos de 1ms para un extremo y 2ms para el otro extremo. Eso en cuanto al tiempo en alto del pulso, para el período de la señal utilicé 20ms.

  En otros experimentos (decoder de RC), conecté la salida de trainer del RadioControl (que contiene la información para todos los canales) y utilicé un 16F628 para decodificar la señal hacia los distintos servos.
En esa oportunidad me hacía un poco de ruido, pero fue por problemas de falsos contactos en el cable de señal hacia el servo.

  Por supuesto debes tener un filtro a la salida del regulador, yo utilizaba 10uF que eran suficientes.

  Yo no usé resistencia entre la salida del pic y el cable de señal del servo, pero creo que sería conveniente.

  Revisa el sitio este que está muy bueno con toda la info que tiene respecto del RadioControl. http://www.e-radiocontrol.com.ar/?Documentacion:Decodificador:PWM
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 19 de Julio de 2012, 17:23:43
Hola

Gracias por el enlace AngelGris, buena aportacion al hilo.

Lo de la resistencia te refieres para evirar ruido y mandar lo mas estable posible verdad?


Tengo una pregunta ...¿a que es debido que el servo en algunas posiciones
el servo se autorectifique solo..
me explico lo llevo de la posicion + 0 - cental a ojimetro () hasta 0

segun el valor llega y parece como que quisiera seguir avanzando
pero en otras  llega y se retrasa un pelin el solo.. parece como si no fuera lineal la sucesion

El perido de la señal lo puse en 20ms --> 20 000 us
que seria usar una fecuanica de 50Hz

para mi tower pro SG9 (los azulitos)

izquierda esta entre  110us y un poco por encima tambien ...
por debajo hace cosas muy raras

derecha cerca de los 800us (probando aun)

y el centro cuando termine de acotar los extremos
imagina que lo tendre..

uso una funcion de prueba:

Código: C++
  1. // main
  2.  
  3. while(true){
  4.  
  5. pwm_p(pwm_sf,200);
  6. }
  7. ..
  8. ..

la funcion trabaja con microsegundos (us)

Código: C++
  1. void pwm_p(int8 pin, int16 useg){
  2. int16 resto;
  3. //20mms -- 20000us
  4. resto=20000;
  5.    output_high(pin);
  6.    delay_us(useg);
  7.    //delay_ms(mseg);
  8.    output_low(pin);
  9.    resto=resto-useg;
  10.    delay_us(resto);
  11.    //delay_ms(resto);
  12. }

sigo buscando el otro extremo ....


bueno ya consegui los valores de los extremo

lo malo es la de pruebas que tuve que hacer todo experimental

izquierda:  110 us,  120 us,  130 us    me quedo con 110 us
derecha :   360 us,  370 us,  380 us    me quedo con 630 us
centro:       620 us,  630 us,  640 us    me quedo con 370 us

si restamos: 630 - 370 = 260
si restamos: 370 - 110 = 260

si 370 es 90 grados cuantos tiempos sera  1 Grado

370 us ------ 90º
 x    us ------  1º

como el cero empieza en 110
370-110
x=370/90

x=2.88888889 periodo

3us es 1 grado

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 20 de Julio de 2012, 12:17:22
Hola
al final logre adaptar los tiempos:

como mi servo no tiene 180º exactos sino sino unos poco mas debo de ajustar los extremos
de forma manual.

central:  370 us
izq:       120 us
der:       620 us

despues de esto se plantea una nueva cuestion
hasta ahora probe toda el proceso con un funcion:

Código: C++
  1. //main
  2. ..
  3. ..
  4.    while(true){
  5.       pwm_p(pwm_sf,120);
  6.  
  7.    }
  8.    
  9. ..
  10. ..

ahora deseo sacar esta funcion del bucle

al hacerlo ya no responde de igual forma...

he observado que una vez que se mueve el servo a su posicion
deseada se puedes sacar el cable de control que el servo no se mueve
esto vendria a ser lo mismo que que desactivar esta funcion.

Pero que tiempo minimo necesita de repeticion?
cuantas veces tienen que reeenviar ?


Un Saludo
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 20 de Julio de 2012, 12:33:01
  La autocorreción del servo es debido a que internamente tienen un preset, justamente para poder quedar en la posición indicada.
Seguramente se moverá un poquito debido a impuresas en el preset. Habría que ver que ocurre con un servo de gama alta (en cuanto a calidad).

  La repetición es justamente el período de la señal.

  En tu caso no se mueve porque está en vació, pero si es sometido a una fuerza seguramente se correrá de lugar. Es por ello que necesitan el refresco de la información.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: MLO__ en 20 de Julio de 2012, 13:10:17
Hola.

Hay que enviar continuamente la senal de PWM al servo para que quede fijo en la posicion. Yo lo hice con un PIC12F629 y el siguiente codigo:

Código: C#
  1. #include<12F629.h>
  2. #fuses HS,NOWDT,PROTECT,NOBROWNOUT,PUT,MCLR
  3. #use delay(clock=20M)
  4.  
  5. #define on                      output_high
  6. #define off                     output_low
  7.  
  8. #define OUT_SERVO       pin_a0
  9. #define bPLUS           pin_a1
  10. #define bMINUS          pin_a2
  11.  
  12. struct BytesPWM
  13. {
  14.         int Ticks;
  15.         int SetPoint;
  16. }PWM;
  17.  
  18. #int_TIMER0
  19. void PWMServo_isr(void)
  20. {
  21.         PWM.Ticks++;
  22.         if(PWM.Ticks==0)
  23.                 on(OUT_SERVO);
  24.                
  25.         if(PWM.Ticks>=PWM.SetPoint)
  26.                 off(OUT_SERVO);
  27.  
  28.         set_timer0(0);
  29. }
  30.  
  31. void main(void)
  32. {
  33.         setup_comparator(NC_NC_NC_NC);
  34.         setup_timer_0(RTCC_8_BIT|RTCC_INTERNAL|RTCC_DIV_1);
  35.         enable_interrupts(INT_TIMER0);
  36.         enable_interrupts(GLOBAL);
  37.         PWM.SetPoint=40;
  38.        
  39.         while(true)
  40.         {
  41.                 if(input_state(bPLUS))
  42.                 {
  43.                         delay_ms(40);
  44.                         if(input_state(bPLUS))
  45.                         {
  46.                                 PWM.SetPoint++;
  47.                                 if(PWM.SetPoint>=42)
  48.                                         PWM.SetPoint=42;
  49.                         }
  50.                         while(input_state(bPLUS));
  51.                 }
  52.                
  53.                 if(input_state(bMINUS))
  54.                 {
  55.                         delay_ms(40);
  56.                         if(input_state(bMINUS))
  57.                         {
  58.                                 PWM.SetPoint--;
  59.                                 if(PWM.SetPoint<=9)
  60.                                         PWM.SetPoint=9;
  61.                         }
  62.                         while(input_state(bMINUS));
  63.                 }
  64.         }
  65. }

El PWM se genera con la interrupción del TIMER0 y con los pulsadores ajusto la posición.

Saludos
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 20 de Julio de 2012, 16:47:45
Hola

si estas en lo cierto AngelGris si lo desconecto se deja mover con la mano.
MLO eso de 42 y 9 es microsengundo verdad los meneas 15 grados uno y el otro el del 9
son 5 verdad


entonces debo de ingeniarmelas para enviarle la señal cada 20ms
imagino que en esta situacion no debo de usar retardos del tipo delay.

seria bueno usar es este enlace

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

ademas de estar enviandole constantemente esto al servo bueno en mi caso son 4 servos
tambine debe de estar libre el pic para otras cosas.

No se como me las voy a ingeniar esta vez.

voy a ver si me adapto eso par los microsegundos.

que opinais de ello.

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: MLO__ en 20 de Julio de 2012, 17:00:25
Hola.

No son uS, son multiplos de la base de tiempo que se genera con la interrupcion del Timer0 (51uS aprox.)

Saludos
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 22 de Julio de 2012, 10:34:59
Hola

AngelGris la resistencia entre la entrada de pwm y el pic de que valor era?, en la documentacion
no logro encontrarla, ¿esa resistencia es para estabilizar la señal?

El dilema esta en como usar los timer
los tengo todos los tiempos en us no se si usar el timer 0 o el timer 1

los tiempos van de 110us a 700us
y para mas historia me gustaria usar tambien para los retardos los timer

¿como contar us, ms y segundos a la vez y ademas evitar usar int16

se acaptan ideas..

sigo madurando la idea


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 22 de Julio de 2012, 11:25:17
  ¿Y cuál es el problema de tener que usar variables int16?

  Se pueden implementar varios contadores por soft que se incrementen con la interrupción del timer.

  Por ejemplo si el timer genera interrupción cada 10us, cuando tu contador llegue a 100 serán 1ms. En el ciclo principal del programa podés evaluar dichos contadores para ver si paso el tiempo estipulado.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 23 de Julio de 2012, 09:28:59
Hola
tras mucho persarlo
voy a configurar el timer 0 para que produzca interrupcion cada 1us,
despues creare variables en ram que cuenten esas interrupciones:

timer= va de 255 a 000 crea una INT
el clock es 20Mhz
si los timer se incrementan cada 4 instruciones entonces

4 x  (1/20 000 000hz) = 0.2 usegundos

0.2 useg x 5 tick de timer  =  1us

si cargo el timer0 con set_timer0(251);

¿en ccs como se configura eso?, en el asistente:

te se muestra la resolucion: 0.2us, 0.4us, 0.8us,

overflow,depende de la resolucion
y despues te permite marcar esto con aspa:

RTCC_off,

trc_8_bit

si marcas alguno de estos se configura el rebose..

y para selecionar el oscilador: internal, external (ext_l_to_h o ext_h _to_l),

esto como se selecciona y lo de la frecuncia como va esto, ahi iría el 50 de 50 hercios del perido
o el 20Mz del cristal


alguien sabria decirme?

sigo investigando






Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 23 de Julio de 2012, 09:57:19
  Como primer punto creo que querer una interrupción cada 1us en C y a 20MHz te va a ser muy difícil. Ten en cuenta que, como vos bien dijiste, son 5 ciclos de instrucción, y entre que salta la rutina de interrupción y guardas las variables y se testea cual interrupción de activó (todo ese código lo agrega el compilador, sin que figure en el archivo C), ya van a pasar unos cuantos ciclos más. Distinto sería si lo programas en ASM donde tiene un mayor control de los tiempos, y aún así creo que estaría difícil.

  Para que cada interrupción se ejecute en el tiempo deseado, dentro de la rutina de interrupción tienes que precargar el timer con el valor adecuado que en tu caso sería "set_timer0(251)"


  ext_l_to_h o ext_h_to_l supongo que hace mención a la interrupción externa que se produzca por flanco ascendente o descendente.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 23 de Julio de 2012, 10:13:38
hola AngelGris

si ese es uno de los problemas que no he logrado resolver,
si hago eso que digo de cada 1us creo que saturale al micro
pero los tiempos del pwm no llegan a ms
en mi caso es 130us(0),365us(90), 610us(180).

otra cosa seria poner para que rebose cada 20ms y lo otro hacerlo contando ticnk del timer.

¿una pregunta miestras el timer esta contado, el micro esta realizando o pude realizar otra cosa
de forma paralela o semi paralela?

un saludo
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 23 de Julio de 2012, 10:24:45
hola AngelGris

si ese es uno de los problemas que no he logrado resolver,
si hago eso que digo de cada 1us creo que saturale al micro
pero los tiempos del pwm no llegan a ms
en mi caso es 130us(0),365us(90), 610us(180).

otra cosa seria poner para que rebose cada 20ms y lo otro hacerlo contando ticnk del timer.

¿una pregunta miestras el timer esta contado, el micro esta realizando o pude realizar otra cosa
de forma paralela o semi paralela?

un saludo


  El timer cuenta sin que nuestro programa influya, es decir que mientras vos hacés cosas el timer va contando.

  Una "solución", al menos para ir haciendo pruebas sería utilizar un timer para la trama (20ms) y otro timer para el tiempo en alto..
  Básicamente sería hacer que cuando pasaron los 20ms, se reseteen los contadores y a su vez se ponga en 1 la salida PWM, luego pasa a contar el timer que da el tiempo de trabajo y una vez que termina su cuenta se hace 0 la salida PWM.

  Al timer que da el tiempo en alto, lo podrías precargar por ejemplo con un valor leído desde el ADC o con una variable. Entonces ya no sería necesario que desborde cada 1us. sino que contaría el total del tiempo.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 23 de Julio de 2012, 20:39:31
Hola
el tiempo que permanece en alto el pwm y en bajo
se lo voy a pasar por i2c bueno se lo tengo que sasar por i2c.
lo que no se como voy ha hacer porque la comunicacion no dura menos de 20 milisegundos

una aclaracion- pregunta -confirmacion:

, tengo entendido que si utilizas interrupciones no se debe de usar los retardos de ningun tipo (delay..)
eso es cierto?  o es una leyenda urbana, por aca en el foro hay ejemplos asi, pero tambien hay hilos que
no lo recomindan sin retardos.

¿a quien le das  prioridad a la interupcion del timer o la del i2c?o a una tercera que domine ambas
uf...

eso me genera otra pregunta?
si cuando el micro tiene interrupcion deja lo que esta haciendo para atender a la interrupcion,
pregunta 1.- cuando termina esta interrupcion sigo donde lo dejo ante? verdad

si esto es asi..

es posible gener una interrupcion dentro de otra a modo de administrador de hilos...

si el  proceso 1 duro mas de t tiempo dejalo y sigue con el proceso 2
si este proceso no temino dejalo y sigue con el tres y si este tampoco se termino
 en el tiempo esperado vuelve al proceso 1 .. como un adminstrador de tareas
 regido por tiempo, en mi caso seria el refresco del pwm.

como hace el ordenador generado quantum de tiempos.. con los olgaritmos..

esto se debe de hacer de alguna forma con los pic de una forma sencilla...

voy a seguir apurando...

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 23 de Julio de 2012, 21:00:34
  ¿Si o si es por I2C?

  Teniendo en cuenta una comunicación a 400KHz, nos da un tiempo de 2.5uS por bit. Suponiendo que se transmitan 16 bits de datos para el tiempo en alto y 16 bits para el tiempo en bajo. Cada 8 bits hay que agregar uno de ack, entonces...

8 bits de address
1 ack
8 bit tiempo en alto
1 ack
8 bit tiempo en alto
1 ack
8 bit tiempo en bajo
1 ack
8 bit tiempo en bajo
1 noack

es un total de 45 bits, a 2.5uS por bit nos da un total de 112.5uS. Eso sería lo que tardarías en mandar toda la info por I2C en el mejor de los casos. Pero no creo que llegues a tardar mucho más.


  No es bueno utilizar retardos dentro de la rutina de interrupción, porque entonces el programa quedaría colgado allí y a su vez no permitiría que atienda a otra interrupción. Pero en algunos casos que uno está seguro de que nunca se nos va a ejecutar otra interrupción mientras estemos atendiendo una, no habría demasiados problemas en incluir un pequeño delay.

  En los pic18, existen interrupciones de alta prioridad y de baja prioridad. Para saber cuales corresponden a cada grupo hay que ver el datasheet.

  Sí, si el micro está ejecutando algo y salta a la interrupción, luego de ella prosigue en el punto desde donde se derivo a la interrupción.

  Lo que planteas con eso de los tiempos es justamente lo que hace un RTOS.

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 24 de Julio de 2012, 20:16:27
  Te dejo un ejemplo hecho en HiTech que maneja un servo en base al timer0 para el período (20ms) y con el timer1 maneja el tiempo en alto de la señal

Código: C
  1. #include <htc.h>
  2.  
  3. __CONFIG (1, HS & PLLPOSTDIV2);
  4. __CONFIG (2, WDTDIS);
  5. __CONFIG (3, LVPDIS & PBADDIS & MCLRDIS);
  6.  
  7. #define _XTAL_FREQ 20000000
  8.  
  9. void interrupt low_priority ssp(void)  //interrpcion de baja prioridad
  10. {
  11. }
  12.  
  13. void interrupt timer(void) // interrupcion de alta prioridad
  14. {
  15.   if ((TMR0IF == 1) &&  (TMR0IE == 1)) //interrupcion por timer0
  16.   {
  17.     LATC0 = 1;            // salida en 1
  18.     TMR0 = 65146;
  19.     TMR1ON = 1;           // enciendo el timer1
  20.     TMR0IF = 0;          
  21.   }
  22.  
  23.   if ((TMR1IF == 1) && (TMR1IE == 1)) // interrupcion por timer1
  24.   {
  25.     LATC0 = 0;           // salida en 0
  26.     TMR1ON = 0;          // apago el timer1
  27.     TMR1 = 58036;
  28.     TMR1IF = 0;
  29.   }
  30.  
  31. }
  32.  
  33. void main(void)
  34. {
  35.  
  36.   TRISC = 0;    // puerto C como salida
  37.   LATC0 = 0;    // salida en 0
  38.  
  39.   IPEN = 1;     // habilito prioridades de interrupcion
  40.   TMR0IP = 1;   // timer0 interrupcion de alta prioridad
  41.   TMR1IP = 1;   // timer1 interrupcion de alta prioridad
  42.   T0CON = 0x07; // configuro el timer0 (prescaler 256, modo 16 bits)
  43.   T1CON = 0x80; // configuro el timer1 (sin prescaler)
  44.  
  45.   // ambos timer trabajan con el ciclo de instruccion
  46.  
  47.   TMR0 = 65146;
  48.   TMR1 = 58036;
  49.   TMR0IF = 0;
  50.   TMR1IF = 0;
  51.   TMR0IE = 1;   // habilito interrupcion timer0
  52.   TMR1IE = 1;   // habilito interrupcion timer1
  53.   GIEH = 1;     // habilito todas las interrupciones de alta prioridad
  54.   TMR0ON = 1;   // enciendo el timer0
  55.   TMR1ON = 1;   // enciendo el timer1
  56.  
  57.   while (1)
  58.   {
  59.   }
  60. }
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 25 de Julio de 2012, 08:48:14
Hola
estoy analizado varios codigos
gracias por tu aporte,


Tu antes manejaste ccs , verdad?
creo que no eres elprimero que empezo con ccs y se paso a C18
por que sera eso..?

Aca encontre un enlace parece bueno:
    
rtos ccs minor_cycle
http://www.todopic.com.ar/foros/index.php?topic=28860.0

Sistemas operativos en PIC
http://www.todopic.com.ar/foros/index.php?topic=15876.0

RTOS para PIC GNU
http://www.todopic.com.ar/foros/index.php?topic=15561.0

FreeRTOS - C18 - PIC18F2550 - LCD - Hola Mundo!
http://www.todopic.com.ar/foros/index.php?topic=31520.0

y aca otro que estoy buscando:
    
RTOS en CCS: Como gestionar las interrupciones ???
http://www.todopic.com.ar/foros/index.php?topic=25666.0

interrupciones a mi: lo estoy buscando no doy con el.


sigo de agua hasta el cuello..

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 25 de Julio de 2012, 09:50:20
...

Tu antes manejaste ccs , verdad?
creo que no eres elprimero que empezo con ccs y se paso a C18
por que sera eso..?
....


  Lo utilicé muy poquito. No me gustaba como se manejaba el tema de las salidas y las entradas. Luego, no me gusto el tema que sea de pago... Después encontré HiTech que su versión lite es gratis y la sintaxís me pareció más adecuada.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 25 de Julio de 2012, 09:56:25
Hola
en la actualidad ¿sobre que entorno trabajas y con que compilador?
con ese entorto ¿que clase o familias de pic puedes programar?
¿te permite otros controladores como avr, arm, ...?

Un Saludo
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 25 de Julio de 2012, 10:43:33
  Estoy usando PikLab en linux (Kubuntu 10.04) y puede trabajar con algunos 10F, 12F, 16F, 18F, 24F, 24H, 30F y 33F.

  Uso el compilador HiTech PIC-C para las familias 10, 12 y 16 y el HiTech PIC-C18 para los 18, en ambos casos tengo la versión 9.80

  Hubo un cambio muy notorio entre la versión 9.65 y 9.80 de HiTEch para 18, y es que en los header de los pics, la forma de definir las cosas está hecha para que quede compatible con C18 de microchip.

  Como sólo lo hago por hobby, con eso me es suficiente.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 02 de Agosto de 2012, 20:02:25
hola
de vuelta por este hilo,
despues de la visita por la seccion de RTOS

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

y hacer sondeos:

http://www.todopic.com.ar/foros/index.php?topic=38942.new#new

hemos vuelto al principio, servos e interrupciones:

http://www.todopic.com.ar/foros/index.php?topic=20918.0
http://picmania.garcia-cuervo.net/picc_servos_x_8.php

Que desastre,... una semana por la borda...!





Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 03 de Agosto de 2012, 14:15:22
  Una forma sencilla para manejar varios servos podría ser la siguiente:

  Un timer asignado al tiempo en alto de cada señal. Un timer que genere interrupción cada 2mS (o incremente una variable y actuas cuando llegue a 2mS)

  Cuando se genera la interrupción de 2mS, activas una salida y a su vez el timer que cuenta el tiempo en alto, e incrementas una variable que indique cuantas veces se generó la interrupción de 2mS. Cuando genera la interrupción el timer de tiempo en alto apagás la salida.
  Cuando se vuelve a generar la interrupción de 2mS, activas otra salida y repetís los pasos respecto del timer que cuenta el tiempo en alto.

  Esos ciclos se repiten constantemente con lo que lograrías ir cambiando de servo. Cuando la variable que cuenta la cantidad de interrupciones de 2mS llegue a 10, ya habrán pasado los 20mS de trama por lo tanto la próxima interrupción volvería a activar al primer servo... y la historia se repite.

  Por supuesto el tiempo en alto de cada servo puede ser distinto. Para ello habría que precargar el timer de tiempo en alto con el valor adecuado. Dicho valor puede provenir de una variable para cada servo.

  Todo eso se aplicaría a el PIC esclavo de I2C.

  En el PIC maestro se podría hacer algo así:

  Conectar potenciómetros a los ADC (uno por cada servo a controlar). Se leen los ADC y se almacenan en variables. También hay que tener otra variable con el estado anterior de cada canal.
  Se evalúa cual canal cambio de valor y se envía solamente ese dato. De esa manera podrás ahorrar mucho tiempo de transmisión.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 08 de Agosto de 2012, 14:28:07
Hola

gracias AngelGris, eres un buen colaborador del foro, ahora estoy probando
con la idea que me has dado, por el momento va ganando el pic, pero...

Espero terminar ganando yo

sigo con la faena..
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 11 de Agosto de 2012, 16:28:11
  Te subo un programa hecho en SDCC el cual genera sobre el puerto B señales para 8 servos.
  Cada 2mS se salta la interrupción del timer0 y en base a ello cambio activo el servo correspondiente. La duración de cada servo está data por el timer1, cuyo valor se carga a partir de un array.
  En este programa el array tiene valores prefijados pero bien se puede cargar el array via I2C o cualquier otro tipo de comunicación.

Código: C
  1. unsigned int duty[8];
  2.  
  3. void timers(void) __interrupt 1                // interrupcion alta prioridad
  4. {
  5.   static unsigned int salida = 1;
  6.   static unsigned char indice = 0;
  7.  
  8.   if ((INTCONbits.T0IE) && (INTCONbits.T0IF))  //interrupcion por timer0, cada 2mS
  9.   {
  10.     LATB = salida;         // salida correspondiente en 1
  11.     T1CONbits.TMR1ON = 1;  // enciendo el timer1
  12.     TMR0L = 0x16;          
  13.     TMR0H = 0xD9;          // precargo nuevamente el timer0 (para que desborde cada 2mS)
  14.     salida = salida << 1;  
  15.     indice++;              // incremento el indice para el tiempo en alto
  16.     if (salida == 1024)
  17.     {
  18.       salida = 1;
  19.       indice = 0;
  20.     }  
  21.     TMR1L = duty[indice] & 0x0FF;
  22.     TMR1H = duty[indice] >> 8;     // precargo el timer1 con el valor correspondiente
  23.     INTCONbits.T0IF = 0;           // borro el flag interrupcion del timer0
  24.   }
  25.  
  26.   if ((PIE1bits.TMR1IE) && (PIR1bits.TMR1IF))  // interrupcion timer1, el tiempo en alto
  27.   {
  28.     LATB = 0;                     // pongo en 0 la salida actual
  29.     T1CONbits.TMR1ON = 0;         // apago el timer1
  30.     PIR1bits.TMR1IF = 0;          // borro el flag de interrupcion del timer1
  31.   }
  32.  
  33. }
  34.  
  35. void main(void)
  36. {
  37.  
  38.   TRISB = 0b00000000;    // puerto B como salida
  39.   LATB = 0;    // salida en 0
  40.  
  41. // configuro los timers y les precargo un valor
  42.  
  43.   T0CON = 0x08;
  44.   T1CON = 0x80;
  45.   TMR1L = 0x77;
  46.   TMR1H = 0xEC;
  47.   TMR0L = 0x16;
  48.   TMR0H = 0xD6;
  49.  
  50. // habilito prioridades de interrupcion
  51. // el timer0 y timer1 alta prioridad
  52.  
  53.   RCONbits.IPEN = 1;
  54.   INTCON2bits.TMR0IP = 1;
  55.   IPR1bits.TMR1IP = 1;
  56.   PIE1bits.TMR1IE = 1;
  57.   INTCONbits.T0IE = 1;
  58.   INTCONbits.GIEH = 1;
  59.  
  60.   T0CONbits.TMR0ON = 1;   // enciendo el timer0
  61.  
  62.   // valores para el tiempo en alto de los distintos servos
  63.  
  64.   duty[0] = 60535;
  65.   duty[1] = 59535;
  66.   duty[2] = 58535;
  67.   duty[3] = 57535;
  68.   duty[4] = 56535;
  69.   duty[5] = 60535;
  70.   duty[6] = 59535;
  71.   duty[7] = 58535;
  72.  
  73.   while(1)
  74.   {
  75.    
  76.   }
  77. }

  También te adjunto una captura del osciloscopio de Proteus, donde se aprecian las señales correspondientes a B0, B1, B2 y B3 que sería las cuatro primeras salidas.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 14 de Agosto de 2012, 13:35:02
Hola AngelGris

Se ve muy bueno tu programa, el mio esta atascado
primero con los tick para los angulos y segundo con el dichoso i2c..
me esta dondo muchos problemas,.... y muchos no son nada logicos..

mediante la simulacion de proteus, me obliga a poner
delante y detrras de la funcion de envia desde el master al esclavo
retardos de 1s de lo contrario el debug del i2c te muestra que llega el dato
pero te muestra por el terminal virtual lo que le da la gana.

si le pones a enviar dato "1" el esclavo recibe 0 y todo se bloquea y el debug de i2c detecta Nack
si le envias dato sin esperar 1000ms, te la prepara metiendote el dato como si fuera la direcion de almacen
del dato, lo malo es que te carga ese dato a cero.
para mas descaro te sobreescribe donde no debe, descalibrando el pwm ....ufff una pesadilla

bueno casi podria escribir un libro con todos lo errores que me ha dado, uno tras otro.
no se si sera culpa del ccs o del proteus o de todo en su conjunto..



Oye AngelGris tu pwm es por harware o por software?
que cristal usas?
con el timer0 haces lo que decia redpic de la ventana? , el cambio de servo no lo veo
pero como lo haces me pierdo un poco, activas el pwm de esa salida ?



Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 14 de Agosto de 2012, 14:09:30
Hola AngelGris

Se ve muy bueno tu programa, el mio esta atascado
primero con los tick para los angulos y segundo con el dichoso i2c..
me esta dondo muchos problemas,.... y muchos no son nada logicos..

mediante la simulacion de proteus, me obliga a poner
delante y detrras de la funcion de envia desde el master al esclavo
retardos de 1s de lo contrario el debug del i2c te muestra que llega el dato
pero te muestra por el terminal virtual lo que le da la gana.

si le pones a enviar dato "1" el esclavo recibe 0 y todo se bloquea y el debug de i2c detecta Nack
si le envias dato sin esperar 1000ms, te la prepara metiendote el dato como si fuera la direcion de almacen
del dato, lo malo es que te carga ese dato a cero.
para mas descaro te sobreescribe donde no debe, descalibrando el pwm ....ufff una pesadilla

bueno casi podria escribir un libro con todos lo errores que me ha dado, uno tras otro.
no se si sera culpa del ccs o del proteus o de todo en su conjunto..


  He leído el mensaje que creaste por dicha cuestión y sinceramente no respondí porque no sé que decirte al respecto. Es un problema muy muy extraño.
  Yo hice siempre pequeñas simulaciones y nunca envié un array completo, así que no sabría decirte si es problema del compilador o del simulador.


Oye AngelGris tu pwm es por harware o por software?
que cristal usas?
con el timer0 haces lo que decia redpic de la ventana? , el cambio de servo no lo veo
pero como lo haces me pierdo un poco, activas el pwm de esa salida ?


  El PWM lo controlo yo manualmente -podríamos decir que es por software- en base a los timer0 y timer1.

  Uso cristal de 20MHz.

  Con el timer0 -cada 2mS- activo una salida distinta del puerto B (sólo una está activa el resto queda con salida 0) con la instrucción "LATB = salida".
También  hago que varíe la variable salida con la instrucción "salida = salida << 1;" que rota a la izquierda el dato, por lo tanto se va activando sólo un bit a la vez; para que al entrar a la próxima interrupción por el timer0 y al hacer "LATB = salida" se produzca un nuevo cambio de servo.

  Una vez que activo la salida, activo el timer1 (eso va a establecer el tiempo en alto de la señal). Cuando se genera la interrupción por timer1 desactivo la salida. Como yo sé que sólo una salida está activa, la forma más sencilla para desactivar es poniendo todo el puerto B en 0. También apago el timer1.

  Básicamente lo que hace es ir activando sólo una salida a la vez (como si fuese un contador decimal tipo 4017), y el tiempo que permanece en alto cada salida es dado por el timer1.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 14 de Agosto de 2012, 18:55:11
Hola AngelGris

como calibraste el osciloscopio para cazar las ondas,
a mi aca me da como errores de refresco?
y hay veces que hasta se cuerga el simulador.

Probaste esa implemtacion con comandos i2c?

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 14 de Agosto de 2012, 19:04:34
  Para que se vea así de alto los pulso ajuste el control de vertical de cada canal -los dejé en 2V/div- y también los dejé acoplados en continua.
Al cambiar eso, tuve que ajustar un poco el nivel de trigger.

  Ojo!! que también pude ser que tu señal no sea periódica y por lo tanto el osciloscopio no queda enganchado.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 14 de Agosto de 2012, 19:53:36
Hola AngelGris

este es el codigo del main:

Código: C++
  1. //variables i2c
  2. int8 state, comando;
  3. //int8 iic_dato, Direc_master;
  4. int8 direc_Mas_esc, recivo=0;
  5. int8 dato[4];
  6. //int8 dato_1[4];
  7. int8 cnt=0;
  8. int8 angulo;
  9. int8 inclina;
  10. int8 motor_on;
  11.  
  12. //servos pwm soft
  13. int8 servos[]={sv_0,sv_1,sv_2,sv_3,sv_4,0,0,0,0,0};
  14.  
  15.  
  16.  
  17.  
  18.  
  19. //variables timer
  20. int8 cnt_t0=0;
  21. int8 cnt_t1=0;
  22. int1 t0=0;
  23. int1 t1=0;
  24.  
  25. #priority timer0, timer1, ssp,
  26. /*
  27. #int_RTCC
  28. void  RTCC_isr(void)
  29. {
  30.  
  31. }
  32. */
  33. #int_TIMER0
  34. void  TIMER0_isr(void)
  35. {
  36.    if(cnt_t0==20){ //cambio de ventana
  37.       cnt_t0=0;
  38.       printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  39.    }
  40.    //desborda cada 1ms
  41.    set_timer0(ventana); //ventana de 1 ms cambio de svmotor
  42.    
  43.    printf("\n\r ON SERVO: %d " cnt_t0); //debug ---
  44.    switch(cnt_t0){
  45.               //sv_x seria un vector(cnt_to), y lo del timer1 otro
  46.       case 0: output_high (servos[cnt_t0]); set_timer1(g_90); break;
  47.       case 1: output_high (servos[cnt_t0]); set_timer1(g_90); break;
  48.       case 2: output_high (servos[cnt_t0]); set_timer1(g_90); break;
  49.       case 3: output_high (servos[cnt_t0]); set_timer1(g_90); break;
  50.       case 4: output_high (servos[cnt_t0]); set_timer1(g_90); break;
  51.       /*case 5: output_high (sv_0); set_timer1(g_0); break;
  52.       case 6: output_high (sv_1); set_timer1(g_0); break;
  53.       case 7: output_high (sv_2); set_timer1(g_0); break;
  54.       case 8: output_high (sv_3); set_timer1(g_0); break;
  55.       case 9: output_high (sv_4); set_timer1(g_0); break;
  56.       */
  57.    }//fin switch
  58.    printf("\n\r cnt_t0: %d "cnt_t0);
  59.    //cnt_t0=cnt_t0+1; //incremta ventana => motor
  60. }
  61.  
  62. #int_TIMER1
  63. void  TIMER1_isr(void)
  64. {
  65. output_low (servos[cnt_t0]);
  66. printf("\n\r OFF servo: %d "cnt_t0);
  67. cnt_t0=cnt_t0+1; //incremta ventana => motor
  68.  
  69.  
  70. }
  71.  
  72. /*
  73. #int_SSP
  74. void  SSP_isr(void)
  75. {
  76.  
  77. }
  78. */
  79.  
  80. #int_SSP
  81. void  SSP_isr(void){
  82. disable_interrupts(INT_SSP);
  83. //int8 comando;
  84. //master escribe de esclavo  menor de <80
  85. //master lee de esclavo      mayor de >80
  86.  
  87. state = i2c_isr_state();
  88.    if(state==0)
  89.    {
  90.       direc_Mas_esc=i2c_read();
  91.       if(direc_Mas_esc==S1){
  92.       printf("\n\r --> Direccion: %X "direc_Mas_esc);
  93.          recivo=1;
  94.       }
  95.      
  96.       //printf("\n\r Direccion : %X "direc_Mas_esc); //para solo imprime s1
  97.       //if(SSPADD==S1){
  98.       //printf("\n\r state==0 soy S1: %X "SSPADD);
  99.       //}
  100.      
  101.    }
  102.    
  103.    if(state < 0x80)
  104.    {
  105.      
  106.       //iic_dato=i2c_read();
  107.       //comando=iic_dato;
  108.       if(recivo==1){
  109.          dato[cnt]=i2c_read();
  110.          
  111.          // coreccion para lo de error en dato=1
  112.          if(dato[cnt]==10){
  113.            dato[cnt]=1;
  114.          }
  115.          
  116.          if(dato[0]==1){ // control de motor
  117.             output_high(PIN_B6);
  118.             motor_on=1;
  119.          }
  120.          
  121.          if(dato[cnt]!=0){ //control de angulo
  122.             angulo=dato[1];
  123.             inclina=dato[2];
  124.          }
  125.          ///////////////////////
  126.          
  127.          printf("\n\r dato[%u]:%u"cnt,dato[cnt]);
  128.          recivo=0;
  129.          
  130.          // para resetear almacen dato
  131.          if(dato[cnt]==99){  //cnt resetea en 3 si es 99
  132.            cnt=0;
  133.          }
  134.          else{
  135.            cnt=cnt+1;
  136.          }
  137.          
  138.       }
  139.      
  140.      
  141.      
  142.  
  143.      
  144.  
  145.      
  146.       //Aqui colocas lo que necesites hacer con el dato enviado por el maestro
  147.       //printf("\n\r comando recibo <80: %u"comando);
  148.      
  149.    }
  150.    if(state == 0x80)
  151.    {
  152.    
  153.     switch(comando)
  154.       {
  155.          Case Pide_Dato1:
  156.             i2c_write(Dato1);
  157.             output_high(PIN_B7);
  158.             delay_ms(300);
  159.             output_low(PIN_B7);
  160.            
  161.             printf("\n\r Llego dato.");
  162.             break;
  163.          Case Pide_Dato2:
  164.             i2c_write(Dato2);
  165.             output_high(PIN_B2);
  166.             break;
  167.       }
  168.    }
  169. }
  170.  
  171.  
  172. #int_BUSCOL
  173. void  BUSCOL_isr(void)
  174. {
  175.  
  176. }
  177.  
  178.  
  179.  
  180. void main()
  181. {
  182.  
  183.    setup_adc_ports(NO_ANALOGS|VSS_VDD);
  184.    setup_adc(ADC_CLOCK_DIV_2);
  185.    setup_wdt(WDT_OFF);
  186.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  187.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  188.    setup_timer_2(T2_DISABLED,0,1);
  189.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  190.    setup_comparator(NC_NC_NC_NC);
  191.    setup_vref(FALSE);
  192.    enable_interrupts(INT_RTCC);
  193.    enable_interrupts(INT_TIMER0);
  194.    enable_interrupts(INT_TIMER1);
  195.    enable_interrupts(INT_SSP);
  196.    enable_interrupts(INT_BUSCOL);
  197.    enable_interrupts(GLOBAL);
  198. //Setup_Oscillator parameter not selected from Intr Oscillator Config tab
  199.  
  200.    // TODO: USER CODE!!
  201. set_timer0(0);
  202. set_timer1(0);
  203.  
  204. printf("\n\r Prueba de timer: ");
  205.  
  206.    while(true){
  207.       if(t0==2){
  208.          printf("\n\r -->T0 20ms");
  209.       }
  210.       if(t1==4){
  211.          printf("\n\r -->T1 40ms");
  212.       }
  213.    }
  214. }


en el fichreo de cabecera:

Código: C++
  1. #include <18F2550.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT                    //No Watch Dog Timer
  5. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  6. #FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
  7. #FUSES NOPROTECT                //Code not protected from reading
  8. #FUSES NOBROWNOUT               //No brownout reset
  9. #FUSES BORV20                   //Brownout reset at 2.0V
  10. #FUSES NOPUT                    //No Power Up Timer
  11. #FUSES NOCPD                    //No EE protection
  12. #FUSES STVREN                   //Stack full/underflow will cause reset
  13. #FUSES NODEBUG                  //No Debug mode for ICD
  14. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  15. #FUSES NOWRT                    //Program memory not write protected
  16. #FUSES NOWRTD                   //Data EEPROM not write protected
  17. #FUSES IESO                     //Internal External Switch Over mode enabled
  18. #FUSES FCMEN                    //Fail-safe clock monitor enabled
  19. #FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
  20. #FUSES NOWRTC                   //configuration not registers write protected
  21. #FUSES NOWRTB                   //Boot block not write protected
  22. #FUSES NOEBTR                   //Memory not protected from table reads
  23. #FUSES NOEBTRB                  //Boot block not protected from table reads
  24. #FUSES NOCPB                    //No Boot Block code protection
  25. #FUSES MCLR                     //Master Clear pin enabled
  26. #FUSES LPT1OSC                  //Timer1 configured for low-power operation
  27. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  28. #FUSES PLL12                    //Divide By 12(48MHz oscillator input)
  29. #FUSES CPUDIV4                  //System Clock by 4
  30. #FUSES USBDIV                   //USB clock source comes from PLL divide by 2
  31. #FUSES VREGEN                   //USB voltage regulator enabled
  32.  
  33.  
  34. //esclavos
  35. #define S1 0xB0
  36. #define S2 0xB2
  37. #define S4 0xB4
  38. #define S6 0xB6
  39. #define S8 0xB8
  40.  
  41. // define los servos
  42. #define sv_0 PIN_B7
  43. #define sv_1 PIN_B6
  44. #define sv_2 PIN_B5
  45. #define sv_3 PIN_B4
  46. #define sv_4 PIN_B3
  47. /*
  48. #define sv_5 PIN_B7
  49. #define sv_6 PIN_B6
  50. #define sv_7 PIN_B5
  51. #define sv_8 PIN_B4
  52. #define sv_9 PIN_B3
  53.  
  54. */
  55. // tick para grados 16 bit : 65536 tick 0.2us -->13107.2us
  56.  
  57. //tiempo entre servomotor
  58. const int16 ventana = 60536;  // 65536 - 5000 = n tick para INT 1000us :1ms
  59.  
  60. const int16 g_0   = 64936;    //65536 -  600  120us
  61. const int16 g_90  = 63661;    //65536 - 1875  375us
  62. const int16 g_180 = 62386;    //65536 - 3150  630us
  63.  
  64. //const int16 g_45  = 63661;    //65536 - 1875  375us
  65. //const int16 g_135 = 63661;    //65536 - 1875  375us
  66.  
  67. static int16 valor_PWM[8]={g_90, g_0,g_180,0,0,0,0,0};
  68. static int16 ini_PWM[8]={g_90, g_90, g_90, g_90,0,0,0,0};
  69.  
  70. #define Pide_Dato1 2
  71. #define Pide_Dato2 3
  72. #define dato1 4
  73. #define dato2 5
  74.  
  75. #use delay(clock=20000000)
  76. #define I2C_SCL   PIN_B7
  77. #define I2C_SDA   PIN_C4
  78. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
  79. #use i2c(Master,Slow,sda=PIN_C4,scl=PIN_B7)

como mis servos van de 0 grados en 120us y el 180 es 630us
la ventana o cambio de servo la puse en 1ms ya que el periodo es de 20ms
podia haber apurado mas o puesto mas pequeña
pero queria cifras redondas.

como el periodo es de 20 ms puedo ponerle 20 ventanas de 1 ms, 20 cambio de servo,
para probar le enviaba 10 servos pero al final le deje solo 5 servos, los simulo con led
pero no se ven nada , se ven encendidos todo el rato y pense yo,.. no deberian de verse apagados
el pulso de mi 90 grados es de 375 us y el resto del tiempo estan en off.

con el timer0 cuento las ventanas(los cambio de servo), y enciendo el servo correspondiente iniciando el timer0
con el timer 0 cuando entra en INT incremento ventana, y apago servo

lo del osciloscopio no hay manera se ha colgado al meno una docena de veces el proteus.
ademas me da uno mesajes un poco raros,

PIC18 MEMORY PC=0x022E write 0x00 (0) to unimplemented memory address 0x0f95 does nothing
PIC18 MEMORY PC=0x0226 Read of unimplemented memory address 0x0f8D returns zero
..
.
.
..
esto se repite pero cambiando las direcciones.
cada pocos us


ya lo he corregido lo de los errores de color rojo
en el timer1 copiar-pegar me jugo un mala pasada
en vez de ponerla en bajo la ponia en alto.

este codigo ya funciona.

bueno ahora si que se ve..
es tal como yo pensaba se aprecia un leve parpadeo y el mayor
tiempo estan apagados..

pero me quedan muy separadas las señales

ahora solo queda pegarme con el i2c..

miedo me da..ufff.





Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 14 de Agosto de 2012, 20:41:30

..................

bueno ahora si que se ve..
es tal como yo pensaba se aprecia un leve parpadeo y el mayor
tiempo estan apagados..

pero me quedan muy separadas las señales

ahora solo queda pegarme con el i2c..

miedo me da..ufff.


  ¿A qué te refieres con "me quedan muy separadas las señales"?  Si el tiempo de "ventana" es de 1 mS, cada canal de servo tendría que ir a 1 justamente cada 1 mS. Mide ese tiempo con el osciloscopio de Proteus a ver cuanto te da.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 14 de Agosto de 2012, 21:18:52
Hola

configure el timer en cada canal le puse 2 (2-2)
y en la debebajo del timer 20m, 50m o 100m
con 10 empieza la serie

pero he descubierto que el cursor vertical no me empieza en el blanco
de subida de la primera señal pudiera deberse a que el timer al principio lo arranco en 0.

midiendo con 20ms
con los cursores me mide, el flanco de subina del primero me parece desfasado -16ms
y aparece a la derecha del cursor vertical
en los otros:


2º: 32ms
3º: 77ms
4º: 123ms


 voy a cambiar la resolucion para medir el periodo entero
en cada señal de motor.
Cambio la resolucion a 100ms en el de debajo del triger:
y mido de flanco positivo a flanco positivo en la primera señal.


1º  -70ms a 915ms
2º  -25ms a 960ms
2º   20ms a 1.01s
3º   70ms a 1.05s


estado mirando con esta misma resolucion
y en alto esta 0.01s en algunos en otros varia de una señal a otra y ademas tambien varia
entre pulsos del mismo motor..

que cosa mas rara.


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 14 de Agosto de 2012, 22:12:18
  Como primer medida te recomiendo "comentar" los "printf" que tengas en las interrupciones. Para evitar ese tiempo de mas.

  Como segunda medida, eliminar el "switch" ya que no tiene sentido hacer un switch de la variable cnt_t0 y en cada caso hacer "output_high (servos[cnt_t0])". Siempre realizas la misma instrucción sea cual fuere el valor de cnt_t0, por lo tanto pierdes tiempo en las evaluaciones del "switch" innecesariamente.

  Tercer, es conveniente primero activar la salida y el timer1, y luego hacer las evaluaciones necesarias.

  Cuarto, en la interrupción del timer1 también debes apagar el mismo, para que no siga contando y pueda saltar nuevamente la interrupción.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 15 de Agosto de 2012, 08:59:56
Hola AngelGris

Lo del printf ya lo habia hecho, me di cuanta despues,
ya le estoy aciendo las modificaciones sucesivas.

cuando entra en el timer 0  que haces primero:
 activar el timer1 y  empezar a contar tiempo en alto
o activar de nuevo el timer 0

¿es posible saber cuanto timepo dura cada intrucción?
y en base a eso recarcular los timer para corregir ese error?

el perido entre flancos de subida de cada señal me sale 20.60ms
des el cursor vertical al primer pulso de la señal le cuesta 6.70ms.
entre pulso y pulso es decir la ventana me va 1.10ms

y me da un error creo que tiene que ver con el encendido y apagado del timer..
no se es asi..

error: OSCTUNE register not fully modelled - the TUNx bits are not modelled

este es un bucle..de este error.

el code modificaco quedo asi..solo en main lo demas todo igual

Código: C++
  1. //variables i2c
  2. int8 state, comando;
  3. //int8 iic_dato, Direc_master;
  4. int8 direc_Mas_esc, recivo=0;
  5. int8 dato[4];
  6. //int8 dato_1[4];
  7. int8 cnt=0;
  8. int8 angulo;
  9. int8 inclina;
  10. int8 motor_on;
  11.  
  12. //servos pwm soft
  13. int8 servos[]={sv_0,sv_1,sv_2,sv_3,sv_4,0,0,0,0,0};
  14.  
  15.  
  16.  
  17.  
  18.  
  19. //variables timer
  20. int8 cnt_t0=0;
  21. int8 cnt_t1=0;
  22. int1 t0=0;
  23. int1 t1=0;
  24.  
  25. #priority timer0, timer1, ssp,
  26. /*
  27. #int_RTCC
  28. void  RTCC_isr(void)
  29. {
  30.  
  31. }
  32. */
  33. #int_TIMER0
  34. void  TIMER0_isr(void)
  35. {  
  36.    
  37.    output_high (servos[cnt_t0]);             //activo servo
  38.    //ventana de 1 ms cambio de svmotor
  39.    set_timer0(ventana);                      //desborda cada 1ms
  40.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   //activo timer1
  41.    set_timer1(g_90);                         //tiempo en alto
  42.  
  43.    if(cnt_t0==20){ //cambio de ventana
  44.       cnt_t0=0;
  45.       //printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  46.    }
  47.  
  48.    //printf("\n\r cnt_t0: %d "cnt_t0);
  49.    //cnt_t0=cnt_t0+1; //incremta ventana => motor
  50. }
  51.  
  52. #int_TIMER1
  53. void  TIMER1_isr(void)
  54. {
  55. output_low (servos[cnt_t0]);     //apago motor
  56. //printf("\n\r OFF servo: %d "cnt_t0-1);
  57. cnt_t0=cnt_t0+1;                 // incremta ventana => motor
  58. setup_timer_1(0);                // desactivo timer 1
  59.  
  60. }
  61.  
  62. /*
  63. #int_SSP
  64. void  SSP_isr(void)
  65. {
  66.  
  67. }
  68. */
  69.  
  70. #int_SSP
  71. void  SSP_isr(void){
  72. disable_interrupts(INT_SSP);
  73. //int8 comando;
  74. //master escribe de esclavo  menor de <80
  75. //master lee de esclavo      mayor de >80
  76.  
  77. state = i2c_isr_state();
  78.    if(state==0)
  79.    {
  80.       direc_Mas_esc=i2c_read();
  81.       if(direc_Mas_esc==S1){
  82.       printf("\n\r --> Direccion: %X "direc_Mas_esc);
  83.          recivo=1;
  84.       }
  85.      
  86.       //printf("\n\r Direccion : %X "direc_Mas_esc); //para solo imprime s1
  87.       //if(SSPADD==S1){
  88.       //printf("\n\r state==0 soy S1: %X "SSPADD);
  89.       //}
  90.      
  91.    }
  92.    
  93.    if(state < 0x80)
  94.    {
  95.      
  96.       //iic_dato=i2c_read();
  97.       //comando=iic_dato;
  98.       if(recivo==1){
  99.          dato[cnt]=i2c_read();
  100.          
  101.          // coreccion para lo de error en dato=1
  102.          if(dato[cnt]==10){
  103.            dato[cnt]=1;
  104.          }
  105.          
  106.          if(dato[0]==1){ // control de motor
  107.             output_high(PIN_B6);
  108.             motor_on=1;
  109.          }
  110.          
  111.          if(dato[cnt]!=0){ //control de angulo
  112.             angulo=dato[1];
  113.             inclina=dato[2];
  114.          }
  115.          ///////////////////////
  116.          
  117.          printf("\n\r dato[%u]:%u"cnt,dato[cnt]);
  118.          recivo=0;
  119.          
  120.          // para resetear almacen dato
  121.          if(dato[cnt]==99){  //cnt resetea en 3 si es 99
  122.            cnt=0;
  123.          }
  124.          else{
  125.            cnt=cnt+1;
  126.          }
  127.          
  128.       }
  129.      
  130.      
  131.      
  132.  
  133.      
  134.  
  135.      
  136.       //Aqui colocas lo que necesites hacer con el dato enviado por el maestro
  137.       //printf("\n\r comando recibo <80: %u"comando);
  138.      
  139.    }
  140.    if(state == 0x80)
  141.    {
  142.    
  143.     switch(comando)
  144.       {
  145.          Case Pide_Dato1:
  146.             i2c_write(Dato1);
  147.             output_high(PIN_B7);
  148.             delay_ms(300);
  149.             output_low(PIN_B7);
  150.            
  151.             printf("\n\r Llego dato.");
  152.             break;
  153.          Case Pide_Dato2:
  154.             i2c_write(Dato2);
  155.             output_high(PIN_B2);
  156.             break;
  157.       }
  158.    }
  159. }
  160.  
  161.  
  162. #int_BUSCOL
  163. void  BUSCOL_isr(void)
  164. {
  165.  
  166. }
  167.  
  168.  
  169.  
  170. void main()
  171. {
  172.  
  173.    setup_adc_ports(NO_ANALOGS|VSS_VDD);
  174.    setup_adc(ADC_CLOCK_DIV_2);
  175.    setup_wdt(WDT_OFF);
  176.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  177.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  178.    setup_timer_2(T2_DISABLED,0,1);
  179.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  180.    setup_comparator(NC_NC_NC_NC);
  181.    setup_vref(FALSE);
  182.    enable_interrupts(INT_RTCC);
  183.    enable_interrupts(INT_TIMER0);
  184.    enable_interrupts(INT_TIMER1);
  185.    enable_interrupts(INT_SSP);
  186.    enable_interrupts(INT_BUSCOL);
  187.    enable_interrupts(GLOBAL);
  188. //Setup_Oscillator parameter not selected from Intr Oscillator Config tab
  189.  
  190.    // TODO: USER CODE!!
  191. set_timer0(ventana);
  192. setup_timer_1(0);  // timer 1 no activo T1_DISABLED = 0
  193. //set_timer1(0);
  194.  
  195. printf("\n\r Prueba de timer: ");
  196.  
  197.    while(true){
  198.       if(t0==2){
  199.          printf("\n\r -->T0 20ms");
  200.       }
  201.       if(t1==4){
  202.          printf("\n\r -->T1 40ms");
  203.       }
  204.    }
  205. }

solo modifique el timer0 y el timer1
y dentro del main donde se inicia el timer delante del while.

sigo investigando.


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 15 de Agosto de 2012, 19:19:52

cuando entra en el timer 0  que haces primero:
 activar el timer1 y  empezar a contar tiempo en alto
o activar de nuevo el timer 0


  Lo primero es activar la salida correspondiente.
  Luego activar el timer1
  Precargar nuevamente el valor del timer0
  Incrementar el contador de salida.


¿es posible saber cuanto timepo dura cada intrucción?
y en base a eso recarcular los timer para corregir ese error?


  Dentro de proteus puedes colocar un BreakPoint luego de activar la salida -en la interrupción del timer0-, y ejecutas el código. con el botón de "play". A la derecha vas a encontrar entre paréntesis cuando tiempo llevó la ejecución del código entre que le diste play y que paró por el breakpoint. En mi caso me da 2.0008mS.

  Teniendo en cuenta dicho valor, será cuestión de ir variando el valor que le precargas al timer0 para que llegue a la interrupción en mayor o menor tiempo.


el perido entre flancos de subida de cada señal me sale 20.60ms
des el cursor vertical al primer pulso de la señal le cuesta 6.70ms.
entre pulso y pulso es decir la ventana me va 1.10ms

y me da un error creo que tiene que ver con el encendido y apagado del timer..
no se es asi..

error: OSCTUNE register not fully modelled - the TUNx bits are not modelled

este es un bucle..de este error.


  Entre flanco de subida y flanco de subida de una misma señal -supongamos el canal A del osciloscopio- tiene que dar el período de trama. En tu caso debería ser de 20mS porque cuentas 20 interrupciones de timer0. Si en la práctica obtienes 20.6mS es porque tienes que ajustar un poco el valor que precargas en el timer0.
No es para marearte, ten en cuenta que antes de que estés activando tu salida hay código que se ejecuta y está escapando a tu cálculo de tiempo y por lo tanto hay que ajustar la precarga.

  Si la ventana te da 1.1mS, se soluciona ajustando la precarga del timer0.

  También deberías medir cuanto dura cada pulso en alto, para saber si debes ajustar la precarga del timer1.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 15 de Agosto de 2012, 22:14:34
hola
coloque los puntos de ruptura en las lineas:

6 - 8 - 9 - 10 - 12 - 13

Código: C++
  1. ..
  2. #int_TIMER0
  3. void  TIMER0_isr(void)
  4. {  
  5.  
  6.   output_high (servos[cnt_t0]);             //activo servo
  7.   //ventana de 1 ms cambio de svmotor
  8.   set_timer0(ventana);                      //desborda cada 1ms
  9.   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   //activo timer1
  10.   set_timer1(g_90);                         //tiempo en alto
  11.  
  12.   if(cnt_t0==20){ //cambio de ventana
  13.      cnt_t0=0;
  14.      //printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  15.   }
  16.  
  17.   //printf("\n\r cnt_t0: %d "cnt_t0);
  18.   //cnt_t0=cnt_t0+1; //incremta ventana => motor
  19. }
  20.  
  21. #int_TIMER1
  22. void  TIMER1_isr(void)
  23. {
  24. output_low (servos[cnt_t0]);     //apago motor
  25. //printf("\n\r OFF servo: %d "cnt_t0-1);
  26. cnt_t0=cnt_t0+1;                 // incremta ventana => motor
  27. setup_timer_1(0);                // desactivo timer 1
  28.  
  29. }
  30. ..

una vez colocados los puntos de ruptura de ejecucion
le doy al stop, vuelvo adarle al play y se para
en el primer punto:(linea 6)

le doy una segunda vez (linea 8 )

me marca dos tiempo : entiendo que un es el total
y el otro entre punto y tunto de ruptura.

linea 6: 18.772ms (18.772ms)

si entra en la interrupcion del timer0 es que ha pasado el tiempo que precargue
cuyo valor es el de la ventana 20ms, pero por el contrario faltan casi 2ms

pero me parece muy raro porque si tambien cuenta el tiempo de carga desde que di al play
hasta el punto de rupctura , ese tiempo sera el de ejucion de las lineas más el del timer0
si las intrucuiones se ejecutan en us .

en linea 8 me dice: 18.801ms ( 28.800us)

hay algo que no me cuadra.
analizamos el proceso ..

arrana el programa y cuando llega a la linea de carga del timer0 le carga el valor de la ventana 10ms
sigue ejecutando el programa y de forma trasparente contara lo cargado en el timer 0
quien llegara primero?

- la ejecucion hasta fin de programa o
- la interupcion del timer 0.

llegara antes al final de programa, al while..! y la interupcion se producira despues.

tengo que controlar el tiempo desde que se produce la primera interrupcion
hasta la siguiente es decir 1ms.

parece sencillo pero no lo es, ...


hice calculos y la diferencia es 1.041, 1.032 ,1.039, 1.032, 1.03 ms no es el milisegundo perfecto

los calculos los hice entre  ventana y ventana

como se puede ajustar un tiempo que varia tanto, es imposible...

lo peor es cuando tenga que ajustar el tiempo en alto que tambien varia
para mas dar mal..



Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 15 de Agosto de 2012, 23:48:09
  Yo dejaría el breakpoint sólo en la línea 8, el resto de las líneas dentro de la interrupción las puedes ir ejecutando con F11 si quieres.

  Por el momento dejaría sólo ese breakpoint y tomaría el tiempo que tarda entre la parada y una nueva parada. Que sería justamente el tiempo que cuenta el timer0.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 16 de Agosto de 2012, 09:28:55
Hola
ya coloque el punto de ruptura en la linea 8:
y los tiempos que obtuve fueron:

Código: C++
  1. ...
  2. INT_1.....   18.801ms(18.801ms)  cnt_t0=0 (cuando entra en la INT vale)
  3. INT_2.....   19.840ms(1.0392ms)  cnt_t0=1
  4. INT_3.....   20.872ms(1.0312ms)
  5. INT_4.....   21.904ms(1.0328ms)
  6. INT_5.....   22.934ms(1.0296ms)
  7. INT_6.....   23.964ms(1.0296ms)
  8. INT_7.....   24.993ms(1.0296ms)
  9. INT_8.....   26.023ms(1.0296ms)
  10. INT_9.....   27.052ms(1.0296ms)
  11. INT_10....   28.082ms(1.0296ms)
  12. INT_11....   29.115ms(1.0328ms)
  13. INT_12....   30.144ms(1.0296ms)
  14. INT_13....   31.174ms(1.0296ms)
  15. INT_14....   32.208ms(1.0344ms)
  16. INT_15....   33.238ms(1.0296ms)
  17. INT_16....   34.268ms(1.0296ms)
  18. INT_17....   35.297ms(1.0296ms)
  19. INT_18....   36.327ms(1.0296ms)
  20. INT_19....   37.356ms(1.0296ms) cnt_t0=18
  21. INT_20....   38.389ms(1.0328ms) cnt_t0=19
  22. INT_21.....  39.430ms(1.0408ms) cnt_t0=20
  23.  
  24. INT_1.....   40.469ms(1.0392ms) cnt_t0=0 (cuando entra en la INT vale)
  25. INT_2.....   41.500ms(1.0312ms)
  26. INT_3.....   42.533ms(1.0328ms)
  27. INT_4.....   43.563ms(1.0296ms)
  28. ..
debo de evaluar que el cambio debe de ser en 19 ya que cuanto emepieza desde 0

la pregunta la corrrepción seria de 1.03 redondeando?
¿Porque no es constante el incremento?




Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 16 de Agosto de 2012, 09:47:15
  Todo dependerá del código generado por CCS.

  Yo ahora lo estoy probando con el compilador SDCC, el primer ingreso tarda 13mS y algo -debido a todo el código anterior-. El segundo ingreso se da a los 2.5mS (en mi caso el salto debería ser cada 2mS). Luego de ello probé 70 saltos sucesivos y todos dieron a 2.0008mS.

  Vale aclarar que no tengo implementado nada todavía con I2C.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 16 de Agosto de 2012, 18:18:32
Hola AngelGris

otra cosa rara si cambio entre 20 o 19 en la comparacion de la ventana
me tira abajo el primer servo.

deberia de rectificar ya que de 0 a 20 hay 21 INT ya que evalua despues.
no ha manera..lo qu eno entiendo es que si el servo primero esta en la posicion 0
del vector que narces le afecta, ... no deberia de afectarle por lo menos la primera vez..

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 16 de Agosto de 2012, 22:18:57
  No sé que código generará CCS, posiblemente haya algún problema en como maneja la configuración de los timers y por ello las diferencias de tiempo.

  Estuve modificando un poco mis códigos y logré lo siguiente...

  Al código que mostré anteriormente en SDCC, le agregué el manejo de I2C slave por interrupción de baja prioridad. Se reciben 3 bytes que indican el servo al cual va dirigido el dato, el byte alto del dato y el byte bajo del dato. Luego de recibido los tres, los dos que forman el dato indican el tiempo en alto del servo.

  Hice un código con I2C master que justamente transmite los datos hacia el slave. El master lee el valor de un pote por el ADC, calcula el valor adecuado para el tiempo en alto y lo envía por I2C.

  Por el momento sólo tengo el pote correspondiente al servo0, pero es suficiente para corroborar que funciona perfectamente y que el ancho de pulso del slave varía conforme  a la posición del pote.

  En mi caso, el ancho de pulso varía entre 1mS y 2mS
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 17 de Agosto de 2012, 10:32:44
Hola AngelGris

el SDCC con que IDE lo manejas?


Encontre este hilo por el foro:

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

pero mo me cuadra el tiempo que le pone:

--------------------------------------------------------------------

float const uSxTick = 0.2;                  // Microsegundos por Tick de TMR1 a 20 Mhz

#define VAL_TIMER1 53000   // 65536-53000=12536 * 0,0002 = 2,5 milisegundos

----------------------------------

supongo que el timer1 lo tine a 2^16=65536
si cada tick es 0.2us  un int son 13107.2 us

si quiere conseguir 2.5ms serian 2500us
si

 1 tick -------------    0.2 us
 x tick -------------  2500 us

me salen: 12500tick la pregunta porque a el le salen 36 mas

esos 36 tick de mas son 36 tick X 0.2 us = 7.2 us de mas
---------------------------

Estoy pensando en armarme yo tambine un potenciomentro y un lcd
para mover el servo y ver cuantos tick, us y gados se mueve el servo

tenia por ahi montado un lcd por i2c solo seria buscar el potenciometro adecuado.

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 17 de Agosto de 2012, 13:48:04
  SDCC lo uso con PikLab, siempre estoy "trabajando" desde linux.

  Acá te dejo un link a la simulación
feature=youtu.be

  El dato que tiene que variar es el canal rojo (tercero de arriba hacia abajo) pero en algunos momentos varia un poquito también el canal azul. Quizá haya que retocar el código...
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 17 de Agosto de 2012, 17:37:13
Hola

otra sorpresa, con el proteus veo que la señal le llega  cada 20.20ms
y la ventana la he ajustado para 4ms y de tal forma. las señales llegan al osciloscopio
pero al probar con los servos estos no se mueven,

ni siquiera con los estandeares de 0.5ms, 1.5ms, 2.5ms
probe con los tiempo que yo tenia de ejemplos anteriores con el set_duty y los delay.
y no hay manera y se oye el tick, tick, tick

no se que esta pasando
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 17 de Agosto de 2012, 21:55:24
Hola

otra sorpresa, con el proteus veo que la señal le llega  cada 20.20ms
y la ventana la he ajustado para 4ms y de tal forma. las señales llegan al osciloscopio
pero al probar con los servos estos no se mueven,


  ¿Qué señal le llega cada 20.20mS? ¿A qué le llega esa señal?

ni siquiera con los estandeares de 0.5ms, 1.5ms, 2.5ms
probe con los tiempo que yo tenia de ejemplos anteriores con el set_duty y los delay.
y no hay manera y se oye el tick, tick, tick

no se que esta pasando
 
  Hasta donde tengo entendido "set_duty" es para trabajar con el módulo CCP en su función de PWM. Pero eso es por hardware, y si vos te estás guiando con los timers en realidad lo estás implementando por software.

  Has una cosa, sube una captura de pantalla del osciloscopio de proteus. También te conviene medir el tiempo entre flanco de subida y flanco de subida de una misma señal (que tendría que ser 20mS o aproximado). Y también mide el tiempo en alto de dicha señal. El osciloscopio de proteus tiene cursores para dichos menesteres. Para medir el tiempo en alto te conviene ajustar la base de tiempo para ver el pulso lo mas largo posible y poder medir con mayor precisión.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 18 de Agosto de 2012, 09:30:18
Hola AngelGris
Pongo la foto del osciloscopio de proteus
los canales se corresponden con las patillas:

A: RB7
B: RB6
C: RC2
D: RC1

se puede apreciar que hay una diferencia

el periodo es de 20ms, la ventana es de 1ms
hice zoom  y hay diferencia entre ello es unas decimas.

creo que hay limite de cursores..pongo dos

pongo el codigo.
code main
Código: C++
  1. //variables i2c
  2. int8 state, comando;
  3. //int8 iic_dato, Direc_master;
  4. int8 direc_Mas_esc, recivo=0;
  5. int8 dato[4];
  6. //int8 dato_1[4];
  7. int8 cnt=0;
  8. int8 angulo;
  9. int8 inclina;
  10. int8 motor_on;
  11.  
  12. //servos pwm soft
  13. int8 servos[]={sv_0,sv_1,sv_2,sv_3,sv_4,0,0,0,0,0};
  14.  
  15.  
  16. //variables timer
  17. int8 cnt_t0=0;
  18. int8 cnt_t1=0;
  19. int1 t0=0;
  20. int1 t1=0;
  21.  
  22. //debug tick
  23. int16 valor;
  24.  
  25. #priority  ssp, timer0, timer1    
  26. /*
  27. #int_RTCC
  28. void  RTCC_isr(void)
  29. {
  30.  
  31. }
  32. */
  33. #int_TIMER0
  34. void  TIMER0_isr(void)
  35. {  
  36.    
  37.    output_high (servos[cnt_t0-1]);             //activo servo
  38.    //ventana de 1 ms cambio de svmotor
  39.      
  40.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   //activo timer1
  41.    //valor = t_on(500); //convierte us en tick --<> no va bien
  42.    
  43.    //printf("\n\r tick: %ld "valor);
  44.    set_timer1(g_90);  //tiempo en alto
  45.    
  46.    set_timer0(ventana);             //ventana desborda cada Xms
  47.    //printf("\n\r cnt_t0: %d"cnt_t0);
  48.    if(cnt_t0==5){ //cambio de ventana
  49.       cnt_t0=0;
  50.       //printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  51.    }
  52.  
  53.    //printf("\n\r cnt_t0: %d "cnt_t0);
  54.    //cnt_t0=cnt_t0+1; //incremta ventana => motor
  55. }
  56.  
  57. #int_TIMER1
  58. void  TIMER1_isr(void)
  59. {
  60. output_low (servos[cnt_t0-1]);     //apago motor
  61. //printf("\n\r OFF servo: %d "cnt_t0-1);
  62. cnt_t0=cnt_t0+1;                 // incremta ventana => motor
  63. setup_timer_1(0);                // desactivo timer 1
  64.  
  65. }
  66.  
  67.  
  68. #int_SSP
  69. void  SSP_isr(void){
  70. //disable_interrupts(INT_SSP);
  71. //disable_interrupts(INT_TIMER0);
  72. //disable_interrupts(INT_TIMER1);
  73. //int8 comando;
  74. //master escribe de esclavo  menor de <80
  75. //master lee de esclavo      mayor de >80
  76.  
  77. state = i2c_isr_state();
  78.    if(state==0)
  79.    {
  80.       direc_Mas_esc=i2c_read();
  81.       if(direc_Mas_esc==S1){
  82.       ////////////////////////////////
  83.       printf("\n\r --> Direccion: %X "direc_Mas_esc); //--- debug mas rapido
  84.       ////////////////////////////////
  85.          recivo=1;
  86.          output_high(PIN_B2);  //---debug rapido
  87.       }
  88.      
  89.       //printf("\n\r Direccion : %X "direc_Mas_esc); //para solo imprime s1
  90.       //if(SSPADD==S1){
  91.       //printf("\n\r state==0 soy S1: %X "SSPADD);
  92.       //}
  93.      
  94.    }
  95.    
  96.    if(state < 0x80)
  97.    {
  98.      
  99.       //iic_dato=i2c_read();
  100.       //comando=iic_dato;
  101.       if(recivo==1){
  102.          dato[cnt]=i2c_read();
  103.          
  104.          // coreccion para lo de error en dato=1
  105.          if(dato[cnt]==10){
  106.            dato[cnt]=1;
  107.          }
  108.          
  109.          if(dato[0]==1){ // control de motor
  110.             output_high(PIN_B6);
  111.             motor_on=1;
  112.          }
  113.          
  114.          if(dato[cnt]!=0){ //control de angulo
  115.             angulo=dato[1];
  116.             inclina=dato[2];
  117.          }
  118.          ///////////////////////
  119.          
  120.          /////////////////////////////
  121.          printf("\n\r dato[%u]:%u"cnt,dato[cnt]);  //-- debug +rapido
  122.          /////////////////////////////
  123.          recivo=0;
  124.          output_low(PIN_B2);  //--- debug rapido
  125.          
  126.          // para resetear almacen dato
  127.          if(dato[cnt]==99){  //cnt resetea en 3 si es 99
  128.            cnt=0;
  129.          }
  130.          else{
  131.            cnt=cnt+1;
  132.          }
  133.          
  134.       }
  135.      
  136.      
  137.      
  138.  
  139.      
  140.  
  141.      
  142.       //Aqui colocas lo que necesites hacer con el dato enviado por el maestro
  143.       //printf("\n\r comando recibo <80: %u"comando);
  144.      
  145.    }
  146.    if(state == 0x80)
  147.    {
  148.     /*
  149.     switch(comando)
  150.       {
  151.          Case Pide_Dato1:
  152.             i2c_write(Dato1);
  153.             output_high(PIN_B7);
  154.             delay_ms(300);
  155.             output_low(PIN_B7);
  156.            
  157.             printf("\n\r Llego dato.");
  158.             break;
  159.          Case Pide_Dato2:
  160.             i2c_write(Dato2);
  161.             output_high(PIN_B2);
  162.             break;
  163.       }
  164.       */
  165.    }
  166. enable_interrupts(INT_SSP);  //para imprimir completo priff del main
  167. //enable_interrupts(INT_TIMER0);
  168. //enable_interrupts(INT_TIMER1);
  169. }
  170.  
  171.  
  172. #int_BUSCOL
  173. void  BUSCOL_isr(void)
  174. {
  175.  
  176. }
  177.  
  178.  
  179.  
  180. void main()
  181. {
  182.  
  183.    setup_adc_ports(NO_ANALOGS|VSS_VDD);
  184.    setup_adc(ADC_CLOCK_DIV_2);
  185.    setup_wdt(WDT_OFF);
  186.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  187.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  188.    setup_timer_2(T2_DISABLED,0,1);
  189.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  190.    setup_comparator(NC_NC_NC_NC);
  191.    setup_vref(FALSE);
  192.    enable_interrupts(INT_RTCC);
  193.    enable_interrupts(INT_TIMER0);
  194.    enable_interrupts(INT_TIMER1);
  195.    enable_interrupts(INT_SSP);
  196.    enable_interrupts(INT_BUSCOL);
  197.    enable_interrupts(GLOBAL);
  198. //Setup_Oscillator parameter not selected from Intr Oscillator Config tab
  199.  
  200.    // TODO: USER CODE!!
  201. set_timer0(ventana);
  202. setup_timer_1(T1_DISABLED);  // timer 1 no activo
  203. //set_timer1(0);
  204.  
  205. printf("\n\r Prueba de timer: ");
  206.  
  207.    while(true){
  208.       if(t0==2){
  209.          printf("\n\r -->T0 20ms");
  210.       }
  211.       if(t1==4){
  212.          printf("\n\r -->T1 40ms");
  213.       }
  214.       enable_interrupts(INT_SSP);
  215.       enable_interrupts(INT_TIMER0);
  216.       enable_interrupts(INT_TIMER1);  
  217.    }
  218. }

code cabecera:

Código: C++
  1. #include <18F2550.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT                    //No Watch Dog Timer
  5. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  6. #FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
  7. #FUSES NOPROTECT                //Code not protected from reading
  8. #FUSES NOBROWNOUT               //No brownout reset
  9. #FUSES BORV20                   //Brownout reset at 2.0V
  10. #FUSES NOPUT                    //No Power Up Timer
  11. #FUSES NOCPD                    //No EE protection
  12. #FUSES STVREN                   //Stack full/underflow will cause reset
  13. #FUSES NODEBUG                  //No Debug mode for ICD
  14. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  15. #FUSES NOWRT                    //Program memory not write protected
  16. #FUSES NOWRTD                   //Data EEPROM not write protected
  17. #FUSES IESO                     //Internal External Switch Over mode enabled
  18. #FUSES FCMEN                    //Fail-safe clock monitor enabled
  19. #FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
  20. #FUSES NOWRTC                   //configuration not registers write protected
  21. #FUSES NOWRTB                   //Boot block not write protected
  22. #FUSES NOEBTR                   //Memory not protected from table reads
  23. #FUSES NOEBTRB                  //Boot block not protected from table reads
  24. #FUSES NOCPB                    //No Boot Block code protection
  25. #FUSES MCLR                     //Master Clear pin enabled
  26. #FUSES LPT1OSC                  //Timer1 configured for low-power operation
  27. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  28. #FUSES PLL12                    //Divide By 12(48MHz oscillator input)
  29. #FUSES CPUDIV4                  //System Clock by 4
  30. #FUSES USBDIV                   //USB clock source comes from PLL divide by 2
  31. #FUSES VREGEN                   //USB voltage regulator enabled
  32.  
  33. //timer 0
  34. /*
  35. #DEFINE T0CON 0xFD5     // timer0
  36. #DEFINE T1CON 0xFCD     // timert1
  37.  
  38. #BIT TMR0ON = T0CON.7   // valor enable del timer0 1=on, 0=Off
  39. #BIT RD16 = T1CON.7     // valor enable del timer0 1=on, 0=Off
  40.  
  41. #define TIMER1_ON RD16
  42. */
  43.  
  44. // --- esclavos  --------------------------------
  45. #define S1 0xB0
  46. #define S2 0xB2
  47. #define S4 0xB4
  48. #define S6 0xB6
  49. #define S8 0xB8
  50.  
  51. // ----- define los servos ----------------------
  52. #define sv_0 PIN_B7
  53. #define sv_1 PIN_B6
  54. #define sv_2 PIN_C1
  55. #define sv_3 PIN_C2
  56. #define sv_4 PIN_C0
  57. /*
  58. #define sv_5 PIN_B7
  59. #define sv_6 PIN_B6
  60. #define sv_7 PIN_B5
  61. #define sv_8 PIN_B4
  62. #define sv_9 PIN_B3
  63. */
  64.  
  65. // TIMER 2 exp 16 bit : 65536 tick 0.2us -->13107.2us 1 INT
  66.  
  67. // ---- perido de 20 ms 20000us -------------------------------
  68. //      1 tick ........ 0.2us
  69. //      5 tick ........ 1  us
  70.  
  71. // ----- ventana o cambio motor -------------------------------
  72. //                                      Tick para us en on
  73. //const int16 ventana = 60536;  // 65536 -  5000 = 1ms 1000us
  74. //const int16 ventana = 55536;  // 65536 - 10000 = 2ms 2000us
  75. //const int16 ventana = 50536;  // 65536 - 15000 = 3ms 3000us
  76. const int16 ventana = 45536;  // 65536 - 20000 = 4ms 4000us
  77. //const int16 ventana = 40536;  // 65536 - 25000 = 5ms 5000us
  78. //const int16 ventana = 15536;  // 65536 - 50000 = 10ms 10000us
  79.  
  80.  
  81. //1 tick -------- 0.2us
  82. //x tick -------- y  us
  83.  
  84. // ----- tick para tiempo en ON -------------------------------
  85.  
  86. // --- generico ---------------------
  87. const int16 g_0    = 63036;    //65536 -  2500  0.5ms  500us
  88. const int16 g_90   = 58036;    //65536 -  7500  1.5ms 1500us
  89. const int16 g_180  = 53036;    //65536 - 12500  2.5ms 2500us
  90. //-------------------------------------------------------------
  91.  
  92. // --- mis tick ---------------------
  93.  
  94. //conts inr16 g_1    = .....;    //65536 - .....  .....ms  ...us
  95. //const int16 g_0    = 63036;    //65536 -   600  0.120ms  120us
  96. //const int16 g_90   = 58036;    //65536 -  1875  0.375ms  375us
  97. //const int16 g_180  = 53036;    //65536 -  3150  0.630ms  630us
  98.  
  99. /* en calculos y pruebas..
  100. const int16 g_0    = 63036;    //65536 -   600  0.120ms  120us
  101. const int16 g_15   = 63661;    //65536 - 1875  375us
  102. const int16 g_30   = 63661;    //65536 -   625  0.125ms 375us / 3 = 125us
  103.  
  104. const int16 g_45   = 63661;    //65536 -  ....  0.185ms 370us / 2 = 185us
  105. const int16 g_60   = 63661;    //65536 -  1875  0.185ms 630us / 3 = 210us
  106. const int16 g_75   = 63661;    //65536 -  1875  375us
  107.  
  108. const int16 g_105  = 63661;    //65536 - 1875  375us
  109. const int16 g_120  = 63661;    //65536 - 1875  375us
  110. const int16 g_135  = 63661;    //65536 - 1875  375us
  111.  
  112. const int16 g_150   = 63661;    //65536 - 1875  375us
  113. const int16 g_165   = 63661;    //65536 - 1875  375us
  114. const int16 g_180  = 53036;    //65536 -  3150  0.630ms  630us
  115. */
  116.  
  117. // --- vector inicializacion y angulos servos ----------------------
  118. static int16 valor_PWM[]={g_90, g_0,g_180,0,0,0,0};
  119. static int16 ini_PWM[]={g_90, g_90, g_90, g_90,0,0,0,0}; //8 servos
  120.  
  121. #define Pide_Dato1 2
  122. #define Pide_Dato2 3
  123. #define dato1 4
  124. #define dato2 5
  125.  
  126. #use delay(clock=20000000)
  127. //#define I2C_SCL   PIN_B7
  128. //#define I2C_SDA   PIN_C4
  129. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
  130. #use i2c(Slave,Slow,sda=PIN_B0,scl=PIN_B1,address=0xB0)
  131. //#include "milib.c"
  132.  
  133.  
  134. //--------- milib.c-------------
  135.  
  136. //convierte us en tick de reloj
  137. // 1us ---> 5tick
  138. // xus ---> y tick
  139. int16 t_on(int16 us_on){
  140.    int16 tick_on;
  141.  
  142.       tick_on= 65536 - (us_on * 5);
  143. return tick_on;
  144.  
  145. }
  146.  
  147. bueno no se que pasa..
  148.  
  149. como obtergo los numeros de tick para 1 grado de forma precisa y estable?
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 18 de Agosto de 2012, 10:18:09
  Según esas capturas, estaría muy bien. El tiempo obtenido de 1.54mS debería llevar el servo aproximadamente a la mitad de su recorrido.

 Si la falla está en el circuito real, habría que ver con un osciloscopio real como son las señales obtenidas. Si las señales están bien habría que ver si no hay algún problema de conexionado entre el servo y el pic.

  Si no tienes osciloscopio se puede utilizar la placa de sonido... como la señal es de baja frecuencia no tendrás inconvenientes, podrías colocar un divisor resistivo a la salida del pic para bajar la señal a 1Vpp y luego inyectar la señal en la placa. Hay programas para utilizarla como osciloscopio, pero también puedes recurrir a grabarlas con algún editor de audio y medir el tiempo manualmente.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 18 de Agosto de 2012, 13:18:06
Hola AngelGris

Despues de repasar el circuito, los servos y conexiones
he descubierto el error,  :mrgreen: estaba nuevamente en la variable
de definicion como hice un copiar y pegar y el entorno se colgo, ya no guarde
al arrancar me dejo recuperar pero, no me guardo los cambios y estaba con los angulos
malos  :?, ahora modifique los angulos de extremos centro y funcionan.
despues modicare el pos anterior.

---->> post anterior modificado

Voy a calcular los intermedios...
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 18 de Agosto de 2012, 13:56:35
  Bueno, al menos un problema resuelto... ¿Cómo piensas hacer el movimiento, con un potenciómetro conectado al ADC?
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 18 de Agosto de 2012, 14:07:49
Hola AngelGris

La idea era obtener el algaritmos para obtener los grados en tick
pero de momento esta chungo...tengo el valor de los extremos
y el del centro, pero no logro obterner los puntos intermedios
por regla de tres tampoco sales..

la idea es pasarle los valores por i2c pero para ello debo de conocer
cuantos tick es un grado, sin que vibre o haga cosa raras.

estoy buscando el algaritmo que me relaciona los tick con los us en alto
pensaba que iba a ser mas facil,..

tambien me he dado cuenta que cuando vibran los servos, si reseteas el micro
ya no lo hace no se el porque ..!, hay alguna forma de hacer un reset por software?
y como hacerlo esto solo en el momento que los servos vibran, que no simpre lo hacen?.

a ver si doy con esa relacion.



Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 18 de Agosto de 2012, 14:22:04
  Cuando hice las pruebas en el pasado, en ocasiones me vibraban los servos por falso contacto en el cable de señal del servo. También me pasó que en un par de oportunidades que se solucionó colocando un capacitor del orden de 10uF a la salida del regulador que alimenta al PIC y también 100nF bien cerquita del PIC y 100nF en la alimentación del servo.

  Yo lo hice con un pote y es relativamente sencillo... hay que usar la función de una recta que pasa por 2 puntos.... y = ax +b
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 18 de Agosto de 2012, 15:01:57
Hola AngelGris
si lo de la ecuacion de la recta, le das valores a x para obtener y pero
como relacionas esto con ello.
y=ax+b


yo se que:

      0 grados es 120 us  
    90 grados es 375 us  
  180 grados es 630 us

 com 1us son 5 tick
sabemos :

120us  ----------     600 tick
375us  ----------   1875 tick
630us  ----------   3150 tick

la diferencia entre  630us  - 375us = 255us
y al de                  375us  - 120us = 255us

en tick                  3150  tick -  1875  tick  = 1275 tick
                            1875  tick -   600   tick = 1275 tick

cuantos tick o us para que se incremente un angulo de forma correcta

ambos numero 255 us y 1275 tick terminan en 5 por lo tanto son divisibles
entre 3 , 5 y su producto.

la reacion son esos dos numeros

entre los extremos y el centro hay 255us si dividimos entre 90 nos da 2.833333 perido
asi que para evitar errores tomare la operacion entera junto con lo decimales despues en la resta
lo hare con numeros enteros.

255us / 90º = 2.83us por grado

1 tick  --------  0.2 us
x tick  -------- 2.83333

x=14.1666667 tick   ---<>> 14 tick enteros  un grado.
           

Ya que solo se pueden sumar tick completos.

asi quedo el codigo del main:

Código: C++
  1. //variables i2c
  2. int8 state, comando;
  3. //int8 iic_dato, Direc_master;
  4. int8 direc_Mas_esc, recivo=0;
  5. int8 dato[4];
  6. //int8 dato_1[4];
  7. int8 cnt=0;
  8. int8 angulo;
  9. int8 inclina;
  10. int8 motor_on;
  11.  
  12. //servos pwm soft
  13. int8 servos[]={sv_0,sv_1,sv_2,sv_3,sv_4,0,0,0,0,0};
  14.  
  15.  
  16. //variables timer
  17. int8 cnt_t0=0;
  18. int8 cnt_t1=0;
  19. int1 t0=0;
  20. int1 t1=0;
  21.  
  22. //debug tick
  23. int16 valor;
  24.  
  25. #priority  ssp, timer0, timer1    
  26. /*
  27. #int_RTCC
  28. void  RTCC_isr(void)
  29. {
  30.  
  31. }
  32. */
  33. #int_TIMER0
  34. void  TIMER0_isr(void)
  35. {  
  36.    
  37.    output_high (servos[cnt_t0-1]);             //activo servo
  38.    //ventana de 1 ms cambio de svmotor
  39.      
  40.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   //activo timer1
  41.    //valor = t_on(630); //convierte us en tick --<> no va bien
  42.    
  43.    //printf("\n\r tick: %ld "valor);
  44.    set_timer1(g_0);  //tiempo en alto
  45.    
  46.    set_timer0(ventana);             //ventana desborda cada Xms
  47.    //printf("\n\r cnt_t0: %d"cnt_t0);
  48.    if(cnt_t0==5){ //cambio de ventana
  49.       cnt_t0=0;
  50.       //printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  51.    }
  52.  
  53.    //printf("\n\r cnt_t0: %d "cnt_t0);
  54.    //cnt_t0=cnt_t0+1; //incremta ventana => motor
  55. }
  56.  
  57. #int_TIMER1
  58. void  TIMER1_isr(void)
  59. {
  60. output_low (servos[cnt_t0-1]);     //apago motor
  61. //printf("\n\r OFF servo: %d "cnt_t0-1);
  62. cnt_t0=cnt_t0+1;                 // incremta ventana => motor
  63. setup_timer_1(0);                // desactivo timer 1
  64.  
  65. }
  66.  
  67.  
  68. #int_SSP
  69. void  SSP_isr(void){
  70. //disable_interrupts(INT_SSP);
  71. //disable_interrupts(INT_TIMER0);
  72. //disable_interrupts(INT_TIMER1);
  73. //int8 comando;
  74. //master escribe de esclavo  menor de <80
  75. //master lee de esclavo      mayor de >80
  76.  
  77. state = i2c_isr_state();
  78.    if(state==0)
  79.    {
  80.       direc_Mas_esc=i2c_read();
  81.       if(direc_Mas_esc==S1){
  82.       ////////////////////////////////
  83.       printf("\n\r --> Direccion: %X "direc_Mas_esc); //--- debug mas rapido
  84.       ////////////////////////////////
  85.          recivo=1;
  86.          output_high(PIN_B2);  //---debug rapido
  87.       }
  88.      
  89.       //printf("\n\r Direccion : %X "direc_Mas_esc); //para solo imprime s1
  90.       //if(SSPADD==S1){
  91.       //printf("\n\r state==0 soy S1: %X "SSPADD);
  92.       //}
  93.      
  94.    }
  95.    
  96.    if(state < 0x80)
  97.    {
  98.      
  99.       //iic_dato=i2c_read();
  100.       //comando=iic_dato;
  101.       if(recivo==1){
  102.          dato[cnt]=i2c_read();
  103.          
  104.          // coreccion para lo de error en dato=1
  105.          if(dato[cnt]==10){
  106.            dato[cnt]=1;
  107.          }
  108.          
  109.          if(dato[0]==1){ // control de motor
  110.             output_high(PIN_B6);
  111.             motor_on=1;
  112.          }
  113.          
  114.          if(dato[cnt]!=0){ //control de angulo
  115.             angulo=dato[1];
  116.             inclina=dato[2];
  117.          }
  118.          ///////////////////////
  119.          
  120.          /////////////////////////////
  121.          printf("\n\r dato[%u]:%u"cnt,dato[cnt]);  //-- debug +rapido
  122.          /////////////////////////////
  123.          recivo=0;
  124.          output_low(PIN_B2);  //--- debug rapido
  125.          
  126.          // para resetear almacen dato
  127.          if(dato[cnt]==99){  //cnt resetea en 3 si es 99
  128.            cnt=0;
  129.          }
  130.          else{
  131.            cnt=cnt+1;
  132.          }
  133.          
  134.       }
  135.      
  136.      
  137.      
  138.  
  139.      
  140.  
  141.      
  142.       //Aqui colocas lo que necesites hacer con el dato enviado por el maestro
  143.       //printf("\n\r comando recibo <80: %u"comando);
  144.      
  145.    }
  146.    if(state == 0x80)
  147.    {
  148.     /*
  149.     switch(comando)
  150.       {
  151.          Case Pide_Dato1:
  152.             i2c_write(Dato1);
  153.             output_high(PIN_B7);
  154.             delay_ms(300);
  155.             output_low(PIN_B7);
  156.            
  157.             printf("\n\r Llego dato.");
  158.             break;
  159.          Case Pide_Dato2:
  160.             i2c_write(Dato2);
  161.             output_high(PIN_B2);
  162.             break;
  163.       }
  164.       */
  165.    }
  166. enable_interrupts(INT_SSP);  //para imprimir completo priff del main
  167. //enable_interrupts(INT_TIMER0);
  168. //enable_interrupts(INT_TIMER1);
  169. }
  170.  
  171.  
  172. #int_BUSCOL
  173. void  BUSCOL_isr(void)
  174. {
  175.  
  176. }
  177.  
  178.  
  179.  
  180. void main()
  181. {
  182.  
  183.    setup_adc_ports(NO_ANALOGS|VSS_VDD);
  184.    setup_adc(ADC_CLOCK_DIV_2);
  185.    setup_wdt(WDT_OFF);
  186.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  187.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  188.    setup_timer_2(T2_DISABLED,0,1);
  189.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  190.    setup_comparator(NC_NC_NC_NC);
  191.    setup_vref(FALSE);
  192.    enable_interrupts(INT_RTCC);
  193.    enable_interrupts(INT_TIMER0);
  194.    enable_interrupts(INT_TIMER1);
  195.    enable_interrupts(INT_SSP);
  196.    enable_interrupts(INT_BUSCOL);
  197.    enable_interrupts(GLOBAL);
  198. //Setup_Oscillator parameter not selected from Intr Oscillator Config tab
  199.  
  200.    // TODO: USER CODE!!
  201. set_timer0(ventana);
  202. setup_timer_1(T1_DISABLED);  // timer 1 no activo
  203. //set_timer1(0);
  204.  
  205. printf("\n\r Prueba de timer: ");
  206.  
  207.    while(true){
  208.       if(t0==2){
  209.          printf("\n\r -->T0 20ms");
  210.       }
  211.       if(t1==4){
  212.          printf("\n\r -->T1 40ms");
  213.       }
  214.       enable_interrupts(INT_SSP);
  215.       enable_interrupts(INT_TIMER0);
  216.       enable_interrupts(INT_TIMER1);  
  217.    }
  218. }

y asi su cabecera:

Código: C++
  1. #include <18F2550.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT                    //No Watch Dog Timer
  5. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  6. #FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
  7. #FUSES NOPROTECT                //Code not protected from reading
  8. #FUSES NOBROWNOUT               //No brownout reset
  9. #FUSES BORV20                   //Brownout reset at 2.0V
  10. #FUSES NOPUT                    //No Power Up Timer
  11. #FUSES NOCPD                    //No EE protection
  12. #FUSES STVREN                   //Stack full/underflow will cause reset
  13. #FUSES NODEBUG                  //No Debug mode for ICD
  14. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  15. #FUSES NOWRT                    //Program memory not write protected
  16. #FUSES NOWRTD                   //Data EEPROM not write protected
  17. #FUSES IESO                     //Internal External Switch Over mode enabled
  18. #FUSES FCMEN                    //Fail-safe clock monitor enabled
  19. #FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
  20. #FUSES NOWRTC                   //configuration not registers write protected
  21. #FUSES NOWRTB                   //Boot block not write protected
  22. #FUSES NOEBTR                   //Memory not protected from table reads
  23. #FUSES NOEBTRB                  //Boot block not protected from table reads
  24. #FUSES NOCPB                    //No Boot Block code protection
  25. #FUSES MCLR                     //Master Clear pin enabled
  26. #FUSES LPT1OSC                  //Timer1 configured for low-power operation
  27. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  28. #FUSES PLL12                    //Divide By 12(48MHz oscillator input)
  29. #FUSES CPUDIV4                  //System Clock by 4
  30. #FUSES USBDIV                   //USB clock source comes from PLL divide by 2
  31. #FUSES VREGEN                   //USB voltage regulator enabled
  32.  
  33. //timer 0
  34. /*
  35. #DEFINE T0CON 0xFD5     // timer0
  36. #DEFINE T1CON 0xFCD     // timert1
  37.  
  38. #BIT TMR0ON = T0CON.7   // valor enable del timer0 1=on, 0=Off
  39. #BIT RD16 = T1CON.7     // valor enable del timer0 1=on, 0=Off
  40.  
  41. #define TIMER1_ON RD16
  42. */
  43.  
  44. // --- esclavos  --------------------------------
  45. #define S1 0xB0
  46. #define S2 0xB2
  47. #define S4 0xB4
  48. #define S6 0xB6
  49. #define S8 0xB8
  50.  
  51. // ----- define los servos ----------------------
  52. #define sv_0 PIN_B7
  53. #define sv_1 PIN_B6
  54. #define sv_2 PIN_C1
  55. #define sv_3 PIN_C2
  56. #define sv_4 PIN_C0
  57. /*
  58. #define sv_5 PIN_B7
  59. #define sv_6 PIN_B6
  60. #define sv_7 PIN_B5
  61. #define sv_8 PIN_B4
  62. #define sv_9 PIN_B3
  63. */
  64.  
  65. // TIMER 2 exp 16 bit : 65536 tick 0.2us -->13107.2us 1 INT
  66.  
  67. // ---- perido de 20 ms 20000us -------------------------------
  68. //      1 tick ........ 0.2us
  69. //      5 tick ........ 1  us
  70.  
  71. // ----- ventana o cambio motor -------------------------------
  72. //                                      Tick para us en on
  73. //const int16 ventana = 60536;  // 65536 -  5000 = 1ms 1000us
  74. const int16 ventana = 55536;  // 65536 - 10000 = 2ms 2000us
  75. //const int16 ventana = 50536;  // 65536 - 15000 = 3ms 3000us
  76. //const int16 ventana = 45536;  // 65536 - 20000 = 4ms 4000us
  77. //const int16 ventana = 40536;  // 65536 - 25000 = 5ms 5000us
  78. //const int16 ventana = 15536;  // 65536 - 50000 = 10ms 10000us
  79.  
  80. #define max_v  10 /maxima ventana
  81.  
  82. //1 tick -------- 0.2us
  83. //x tick -------- y  us
  84.  
  85. // ----- tick para tiempo en ON -------------------------------
  86.  
  87. // --- generico ---------------------
  88. //const int16 g_0    = 63036;    //65536 -  2500  0.5ms  500us
  89. //const int16 g_90   = 58036;    //65536 -  7500  1.5ms 1500us
  90. //const int16 g_180  = 53036;    //65536 - 12500  2.5ms 2500us
  91. //-------------------------------------------------------------
  92.  
  93. // --- mis tick ---------------------
  94.  
  95. //conts inr16 g_1    = .....;    //65536 - .....  .....ms  ...us
  96. const int16 g_0    = 64936;    //65536 -   600  0.120ms  120us
  97. const int16 g_90   = 63661;    //65536 -  1875  0.375ms  375us
  98. const int16 g_180  = 62386;    //65536 -  3150  0.630ms  630us
  99.  
  100. //-----------------------------------------------------------------------
  101. // calculos con todos lo decimales y 65536 resta de tick solo parte entera
  102. // 375us -120us = 255us
  103. // 255us  ---<> 90 grados 255 /90 = 2.833333(periodo) cada grado
  104. // 2.8us grado --->> 14 tick por grado(con error de 0.3333)
  105. //------------------------------------------------------------------------
  106. // opero por angulos conocidos
  107. // 5tick = 1us ---<> Tus x5 = Ttick
  108. //------------------------------------------------------------------------
  109. // referencia de 120 us por ser superior a 0 grados
  110.  
  111. //const int16 g_0    = 64936;    //65536 -   600  0.120ms  120us
  112. const int16 g_15   = 64724;    //65536 -  812  255us/6 = 42us  +120us = 162us
  113. const int16 g_30   = 64511;    //65536 - 1025  255us/3 = 85us  +120us = 205us
  114.  
  115. const int16 g_45   = 64299;    //65536 - 1237  255us/2 = 127us +120us = 247us
  116. const int16 g_60   = 64086;    //65536 - 1450  255us/3 = 85us*2+120us = 290us
  117. const int16 g_75   = 63874;    //65536 - 1662  255us/6 = 42us*5+120us = 332us
  118.  
  119. // referecnia de 375us por ser superior a 90 grados
  120. //const int16 g_90   = 63661;    //65536 -  1875  0.375ms  375us
  121. const int16 g_105  = 63449;    //65536 - 2087  255us/6 = 42us  +375us = 417us
  122. const int16 g_120  = 63236;    //65536 - 2300  255us/3 = 85us  +375us = 460us
  123. const int16 g_135  = 63024;    //63536 - 2512  255us/6 = 42us*3+375us = 502us
  124.  
  125. const int16 g_150  = 62811;    //65536 - 2725  255us/3 = 85us*2+375us = 545us
  126. const int16 g_165  = 62599;    //65536 - 2937  255us/6 = 42us*5+375us = 587us
  127. //const int16 g_180  = 62386;    //65536 -  3150  0.630ms  630us
  128.  
  129.  
  130. // --- vector inicializacion y angulos servos ----------------------
  131.  
  132. static int16 valor_PWM[]={g_0, g_45, g_60, g_90, g_120, g_135, g_180};
  133. static int16 ini_PWM[]={g_90, g_90, g_90, g_90,0,0,0,0}; //8 servos
  134.  
  135. #define Pide_Dato1 2
  136. #define Pide_Dato2 3
  137. #define dato1 4
  138. #define dato2 5
  139.  
  140. #use delay(clock=20000000)
  141. //#define I2C_SCL   PIN_B7
  142. //#define I2C_SDA   PIN_C4
  143. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
  144. #use i2c(Slave,Slow,sda=PIN_B0,scl=PIN_B1,address=0xB0)
  145. //#include "milib.c"
  146.  
  147.  
  148. //--------- milib.c-------------
  149.  
  150. //convierte us en tick de reloj
  151. // 1us ---> 5tick
  152. // xus ---> y tick
  153. int16 t_on(int16 us_on){
  154.    int16 tick_on;
  155.  
  156.       tick_on= 65536 - (us_on * 5);
  157. return tick_on;
  158.  
  159. }


ya solo falta daptar el codido para que se modifique
con un vector y este a su vez lo cambiaremos por i2c.



Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 18 de Agosto de 2012, 15:29:19
  Para uso de Potenciómetro la cosa es bien sencilla...

  Tomemos como ejemplo tus datos, el mínimo 120uS y el máximo 630uS.
  Si se utiliza cristal de 20MHz, el tiempo de instrucción (el que contaran los timers) es de 200nS

   Para lograr 120uS, el timer tiene que contar 120uS/200nS = 600. El valor a precargar 65536 - 600 --> 64936
   Para lograr 630uS la cuenta será 630uS/200nS = 3150. El valor a precargar 65536 - 3150 --> 62386

Esos valores son estimados, ya que seguramente habrá que hacer ligeros ajustes.

  Volvamos a la ecuación de la recta.

Y = aX +b

donde "Y" será el valor que tiene que contar el timer (600 para el mínimo y 3150 para el máximo)
"a" sería el valor leído por el ADC. (para el mínimo es 0 y para el máximo es 1023)

usando esa fórmula para el mínimo nos da

600 = 0X + b --> 600 = b, con lo cual ya tenemos el valor de b

volvemos a la fórmula pero para calcular el máximo

3150 = 1023X + 600 --> 3150-600 = 1023X --> X = 2550/1023 --> X = 2.49

por lo tanto la fórmula final nos queda

Y = ((valor ADC) * 2.49 + 600)

precargar del timer = 65536 - Y

-----------

  Para el tema de grados por ticks creo que sería así...

  3150-600 --> 180º --> 2550 = 180º luego

  2550/180 --> 14.16 = 1º
 
Esto implicaría que a partir de 600 (que es el mínimo), si quieres moverte de a 1 º deberás incrementar los ticks en 14.16,

Ejemplo: si tu centro es 375, (90º) si pones 375 + 14.16 = 91º --> 389 = 91º.

Eso, obviamente, será aproximado porque se pierden decimales.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 19 de Agosto de 2012, 10:40:02
Hola AngelGris

modifique algunos pos anteriores y lo que hago es practicamante lo que dices
pero yo cogi todos lo decimales ya que la diferencia puedes ser varios tick

Buena explicacion lo del potenciometro, si señor. ((:-))
muy bien explicado.

Entre linea veo que la resolución del conversor la tienes en 10 bit -->1023
imagino que a mayor resolucion mayor sensibilidad.

El potenciometro que le pones es de 1k o es de otro valor?
¿cual recomendarias?
esto del potenciometro tengo ganas de probarlo....!


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 19 de Agosto de 2012, 11:44:44
Hola AngelGris

modifique algunos pos anteriores y lo que hago es practicamante lo que dices
pero yo cogi todos lo decimales ya que la diferencia puedes ser varios tick


  Sí, es cierto que los decimales pueden generar una variación importante de ticks. Pero de todas maneras recuerda que cuando trabajas con la precarga lo haces con una variable entera por lo tanto no toma en cuenta los decimales.

  A no ser que te manejes con variables float y sólo hagas un cast al momento de cargar el timer. De esa manera el error será un poco menor.

  Si suponemos que el valor por grado es 14.5, al pasarlo a integer es 14. Si lo manejas directamente como integer, dos incrementos darán 28. Pero si lo manejas como float dos incrementos darán 29.



Buena explicacion lo del potenciometro, si señor. ((:-))
muy bien explicado.

Entre linea veo que la resolución del conversor la tienes en 10 bit -->1023
imagino que a mayor resolucion mayor sensibilidad.

El potenciometro que le pones es de 1k o es de otro valor?
¿cual recomendarias?
esto del potenciometro tengo ganas de probarlo....!


  El ADC está en 10 bits porque es la resolución que tiene el PIC. Estoy utilizando un pote de 5K lineal
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 19 de Agosto de 2012, 16:06:01
Hola
ya monte el potenciometro y parece que funciona, :-/
pero encontre algunos problemas, :? en mi caso tenia a mano un potenciometro de 1k
y descubri que con el 600us no se queda en la posicion 0º perpendicular como pasa
si lo hago por variable y tambien he descubierto que en el extremo opuesto no llega a los 180º
le faltan unos 45 grados, lo bueno seria que no se forzase el potenciometro a los extremos y que tampoco
se forzase al servo motor en sus extremo.

En el modo variable lo tengo de tal forma que en sus extremo sobra camino y asi no se fuerza el servo.

He intentado en hacer coincidir el centro del potenciomnetro con el del servo, pero fue imposible.

Intente comparar el problema, con el de algunas emisora, en ellas tienen otros 2 potenciometros para
aumentar la sensibilidad y pense que eso podria ser una solucion.

Seguro que hay otras posibilidades, si ustedes quisieran compartirlas yo las podria conocer...!

Alguna idea de como hacer esto?


Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 20 de Agosto de 2012, 11:54:10
  Es muy raro ello.

  Te muestro un video con un 18F2550, un pote de 10K lineal y un MicroServo E-Sky.
feature=youtu.be

  Fijate que hacia la derecha el servo hace un pequeño salto. En la señal del osciloscopio también se aprecia que cuando el pulso está casi llegando a la mayor duración hace una pequeña falla.
Si ajusto muy finamente el pote, desaparece el pulso. Este mismo defecto lo note en Proteus, por lo tanto es algún inconveniente en el código.

  Aclaro que el servo no está centrado porque estaba colocado en un alerón de un avión de depron, y justamente necesitaba un movimiento diferencial.

  La base de tiempo del osciloscopio está ajustada a 1mV/Div

  La filmación no es muy buena porque está realizada con una cámara fotográfica un tanto viejita.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 20 de Agosto de 2012, 13:12:19
Hola AngelGris

El potenciometro que uso es un piher,
de testos para meterle un palito y fijarlo a un valor

esta es la foto:

modelo PT10LV.

http://www.tme.eu/html/gfx/ramka_294.jpg
http://www.retroamplis.com/WebRoot/StoreES2/Shops/62070367/4BA8/A509/E673/EC99/A4B6/C0A8/28BC/1310/PT10_PIHER.jpg
http://www.tiendaelectronica.com.ve/788-989-home/trimmer-20k.jpg

recuerdo que tambien tengo 1 de eso que giran 300º y de mango muy lardo a lo mejor lo pruebo con el.

http://www.pinchaycompra.com/24383-55-large/potenciometro.jpg

Puede que lo ponga a ver,
de todas formas coloco la funcion que uso para el potenciometro
puede qur yo no le vea el error..

no se que pensar ... me pasan unas cosas mas raras..

cabaecera con la  funcion :

Código: C++
  1. #include <18F2550.h>
  2. #device adc=10
  3.  
  4. #FUSES NOWDT                    //No Watch Dog Timer
  5. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  6. #FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
  7. #FUSES NOPROTECT                //Code not protected from reading
  8. #FUSES NOBROWNOUT               //No brownout reset
  9. #FUSES BORV20                   //Brownout reset at 2.0V
  10. #FUSES NOPUT                    //No Power Up Timer
  11. #FUSES NOCPD                    //No EE protection
  12. #FUSES STVREN                   //Stack full/underflow will cause reset
  13. #FUSES NODEBUG                  //No Debug mode for ICD
  14. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  15. #FUSES NOWRT                    //Program memory not write protected
  16. #FUSES NOWRTD                   //Data EEPROM not write protected
  17. #FUSES IESO                     //Internal External Switch Over mode enabled
  18. #FUSES FCMEN                    //Fail-safe clock monitor enabled
  19. #FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
  20. #FUSES NOWRTC                   //configuration not registers write protected
  21. #FUSES NOWRTB                   //Boot block not write protected
  22. #FUSES NOEBTR                   //Memory not protected from table reads
  23. #FUSES NOEBTRB                  //Boot block not protected from table reads
  24. #FUSES NOCPB                    //No Boot Block code protection
  25. #FUSES MCLR                     //Master Clear pin enabled
  26. #FUSES LPT1OSC                  //Timer1 configured for low-power operation
  27. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  28. #FUSES PLL12                    //Divide By 12(48MHz oscillator input)
  29. #FUSES CPUDIV4                  //System Clock by 4
  30. #FUSES USBDIV                   //USB clock source comes from PLL divide by 2
  31. #FUSES VREGEN                   //USB voltage regulator enabled
  32.  
  33. ...
  34. ...
  35. //---------- para potenciomentro -----
  36. // y = Xa + b
  37. //
  38. // y=tick  a contar
  39. // x= valor del ADC 0-1023
  40. // b=tick del minimo,   (off-set)
  41. //
  42. // valor minio     0º ---> 120us ---> 600 tick
  43. // valor maximo  180º ---> 630us --->3150 tick
  44.  
  45. // ----valor minimo
  46. //  y   =  ( X   * a ) + b
  47. // 600  =  ( 0   * a ) + b  --> b=600
  48.  
  49. // --- valor maximo
  50. //  y   =  X   * a  +  b
  51. // 3150 = 1023 * a  + 600  --> a = (3150 - 600) / 1023
  52. //
  53. // a = 2550 /1023 --> 2.49
  54.  
  55. // Y = ( ((valor ADC) * 2.49) + 600)
  56.  
  57. //precargar del timer = 65536 - Y
  58.  
  59. int16 potenciometro
  60. (int16 min_tick,int16 max_tick,int16 min_res,int16 max_res,int16 valor_adc ){
  61.  
  62. int16 p_tick;
  63.  
  64. p_tick = 65536 - ( (valor_adc * ((max_tick - min_tick)/max_res)) + min_res);
  65.  
  66. return p_tick;
  67. }


y como la implemento en el codigo principal:

Código: C++
  1. //variables i2c
  2. int8 state, comando;
  3. //int8 iic_dato, Direc_master;
  4. int8 direc_Mas_esc, recivo=0;
  5. int8 dato[4];
  6. //int8 dato_1[4];
  7. int8 cnt=0;
  8. int8 angulo;
  9. int8 inclina;
  10. int8 motor_on;
  11.  
  12. //servos pwm soft
  13. int8 servos[]={sv_0,sv_1,sv_2,sv_3,sv_4,0,0,0,0,0};
  14.  
  15.  
  16. //variables timer
  17. int8 cnt_t0=0;
  18. int8 cnt_t1=0;
  19. int1 t0=0;
  20. int1 t1=0;
  21.  
  22. //debug tick
  23. int16 valor, valor1;
  24.  
  25. #priority  ssp, timer0, timer1    
  26. /*
  27. #int_RTCC
  28. void  RTCC_isr(void)
  29. {
  30.  
  31. }
  32. */
  33. #int_TIMER0
  34. void  TIMER0_isr(void)
  35. {  
  36.    
  37.    output_high (servos[cnt_t0-1]);             //activo servo
  38.    //ventana de 1 ms cambio de svmotor
  39.      
  40.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   //activo timer1
  41.    //valor = t_on(630); //convierte us en tick --<> no va bien
  42.    
  43.    valor=read_adc();
  44.    //printf("\n\r ADC: %ld" valor);
  45.    valor1=potenciometro(600,3150,0,1023,valor);
  46.    
  47.    //printf("\n\r tick: %ld "valor);
  48.    //set_timer1(g_0);  //tiempo en alto
  49.    set_timer1(valor1);
  50.    
  51.    set_timer0(ventana);             //ventana desborda cada Xms
  52.    
  53.    
  54.    
  55.    //printf("\n\r cnt_t0: %d"cnt_t0);
  56.    if(cnt_t0==5){ //cambio de ventana
  57.       cnt_t0=0;
  58.       //printf("\n\r -->T0 1ms 20 ventanas  1 perido");
  59.    }
  60.  
  61.    //printf("\n\r cnt_t0: %d "cnt_t0);
  62.    //cnt_t0=cnt_t0+1; //incremta ventana => motor
  63. }
  64.  
  65. #int_TIMER1
  66. void  TIMER1_isr(void)
  67. {
  68. output_low (servos[cnt_t0-1]);     //apago motor
  69. //printf("\n\r OFF servo: %d "cnt_t0-1);
  70. cnt_t0=cnt_t0+1;                 // incremta ventana => motor
  71. setup_timer_1(0);                // desactivo timer 1
  72.  
  73. }
  74.  
  75.  
  76. #int_SSP
  77. void  SSP_isr(void){
  78. //disable_interrupts(INT_SSP);
  79. //disable_interrupts(INT_TIMER0);
  80. //disable_interrupts(INT_TIMER1);
  81. //int8 comando;
  82. //master escribe de esclavo  menor de <80
  83. //master lee de esclavo      mayor de >80
  84.  
  85. state = i2c_isr_state();
  86.    if(state==0)
  87.    {
  88.       direc_Mas_esc=i2c_read();
  89.       if(direc_Mas_esc==S1){
  90.       ////////////////////////////////
  91.       printf("\n\r --> Direccion: %X "direc_Mas_esc); //--- debug mas rapido
  92.       ////////////////////////////////
  93.          recivo=1;
  94.          output_high(PIN_B2);  //---debug rapido
  95.       }
  96.      
  97.       //printf("\n\r Direccion : %X "direc_Mas_esc); //para solo imprime s1
  98.       //if(SSPADD==S1){
  99.       //printf("\n\r state==0 soy S1: %X "SSPADD);
  100.       //}
  101.      
  102.    }
  103.    
  104.    if(state < 0x80)
  105.    {
  106.      
  107.       //iic_dato=i2c_read();
  108.       //comando=iic_dato;
  109.       if(recivo==1){
  110.          dato[cnt]=i2c_read();
  111.          
  112.          // coreccion para lo de error en dato=1
  113.          if(dato[cnt]==10){
  114.            dato[cnt]=1;
  115.          }
  116.          
  117.          if(dato[0]==1){ // control de motor
  118.             output_high(PIN_B6);
  119.             motor_on=1;
  120.          }
  121.          
  122.          if(dato[cnt]!=0){ //control de angulo
  123.             angulo=dato[1];
  124.             inclina=dato[2];
  125.          }
  126.          ///////////////////////
  127.          
  128.          /////////////////////////////
  129.          printf("\n\r dato[%u]:%u"cnt,dato[cnt]);  //-- debug +rapido
  130.          /////////////////////////////
  131.          recivo=0;
  132.          output_low(PIN_B2);  //--- debug rapido
  133.          
  134.          // para resetear almacen dato
  135.          if(dato[cnt]==99){  //cnt resetea en 3 si es 99
  136.            cnt=0;
  137.          }
  138.          else{
  139.            cnt=cnt+1;
  140.          }
  141.          
  142.       }
  143.      
  144.      
  145.      
  146.  
  147.      
  148.  
  149.      
  150.       //Aqui colocas lo que necesites hacer con el dato enviado por el maestro
  151.       //printf("\n\r comando recibo <80: %u"comando);
  152.      
  153.    }
  154.    if(state == 0x80)
  155.    {
  156.     /*
  157.     switch(comando)
  158.       {
  159.          Case Pide_Dato1:
  160.             i2c_write(Dato1);
  161.             output_high(PIN_B7);
  162.             delay_ms(300);
  163.             output_low(PIN_B7);
  164.            
  165.             printf("\n\r Llego dato.");
  166.             break;
  167.          Case Pide_Dato2:
  168.             i2c_write(Dato2);
  169.             output_high(PIN_B2);
  170.             break;
  171.       }
  172.       */
  173.    }
  174. enable_interrupts(INT_SSP);  //para imprimir completo priff del main
  175. //enable_interrupts(INT_TIMER0);
  176. //enable_interrupts(INT_TIMER1);
  177. }
  178.  
  179.  
  180. #int_BUSCOL
  181. void  BUSCOL_isr(void)
  182. {
  183.  
  184. }
  185.  
  186.  
  187.  
  188. void main()
  189. {
  190.  
  191.    setup_adc_ports(AN0|VSS_VDD);
  192.    setup_adc(ADC_CLOCK_DIV_2);
  193.    set_adc_channel(0);
  194.    setup_wdt(WDT_OFF);
  195.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  196.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  197.    setup_timer_2(T2_DISABLED,0,1);
  198.    
  199.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  200.    setup_comparator(NC_NC_NC_NC);
  201.    setup_vref(FALSE);
  202.    enable_interrupts(INT_RTCC);
  203.    enable_interrupts(INT_TIMER0);
  204.    enable_interrupts(INT_TIMER1);
  205.    enable_interrupts(INT_SSP);
  206.    enable_interrupts(INT_BUSCOL);
  207.    enable_interrupts(GLOBAL);
  208. //Setup_Oscillator parameter not selected from Intr Oscillator Config tab
  209.  
  210.    // TODO: USER CODE!!
  211. set_timer0(ventana);
  212. setup_timer_1(T1_DISABLED);  // timer 1 no activo
  213. //set_timer1(0);
  214.  
  215. printf("\n\r Prueba de timer: ");
  216.  
  217.    while(true){
  218.       if(t0==2){
  219.          printf("\n\r -->T0 20ms");
  220.       }
  221.       if(t1==4){
  222.          printf("\n\r -->T1 40ms");
  223.       }
  224.       enable_interrupts(INT_SSP);
  225.       enable_interrupts(INT_TIMER0);
  226.       enable_interrupts(INT_TIMER1);  
  227.    }
  228. }

en proteus al simularlo se atasca un poco
con el potenciometro al 8% ya llega al 0.98
tiene mas rango en la parte del cero que en la de por encima del 0

voy a printer por terminal virtual lo que me lea el conversor ...

me lee 0 y al principio en 0 con letras,
como es posible ....

para printerar int16 es  %lu

en el cabecera le puse #device adc=10
leo por el canal 0 AN0

su configuracion es esta:

  
setup_adc_ports(AN0|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_2);
set_adc_channel(0);


que se me escapa..?

ya empiezan los poltergeist..!.

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 20 de Agosto de 2012, 14:04:43
  A mi entender estás complicando demasiado el código... no tiene sentido llamar a una función para que te devuelva el valor a precargar.

  Tampoco es bueno hacer todo eso dentro de la rutina de interrupción. También debes procurar buscar una buena configuración del ADC. Fijate en el datasheet cuál es la velocidad máxima del ADC para un cristal de 20MHz.

  Creo que si haces ADC_CLOCK_DIV_2, la frecuencia del ADC será 20MHz/2 --> 10MHz --> tiempo TAD = 100nS, siendo que el TAD mínimo -según datasheet- es de 700nS..

  Esta es la muestra de mi código en SDCC.

Código: C
  1. #include <pic18fregs.h>
  2. #include <adc.h>
  3.  
  4. static __code char __at (__CONFIG1L) CONFIG1L = _USBPLL_CLOCK_SRC_FROM_OSC1_OSC2_1L &
  5.                    _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L;
  6. static __code char __at (__CONFIG1H) CONFIG1H = _OSC_HS__USB_HS_1H & _FCMEN_OFF_1H &
  7.                    _IESO_OFF_1H;
  8. static __code char __at (__CONFIG2L) CONFIG2L = _VREGEN_OFF_2L & _PUT_OFF_2L & _BODEN_OFF_2L;
  9. static __code char __at (__CONFIG2H) CONFIG2H = _WDT_DISABLED_CONTROLLED_2H;
  10. static __code char __at (__CONFIG3H) CONFIG3H = _MCLRE_MCLR_OFF_RE3_ON_3H &
  11.                    _PBADEN_PORTB_4_0__CONFIGURED_AS_DIGITAL_I_O_ON_RESET_3H;
  12. static __code char __at (__CONFIG4L) CONFIG4L = _LVP_OFF_4L;
  13.  
  14. unsigned char parte_baja;
  15. unsigned char parte_alta;
  16.  
  17. void timers(void) __shadowregs __interrupt 1       // interrupcion alta prioridad
  18. {
  19.   static unsigned int salida = 1;
  20.   static unsigned char indice = 0;
  21.  
  22.   if ((INTCONbits.TMR0IE) && (INTCONbits.TMR0IF))  //interrupcion por timer0, cada 2mS
  23.   {
  24.     LATB = salida;         // salida correspondiente en 1
  25.     T1CONbits.TMR1ON = 1;  // enciendo el timer1
  26.     TMR0L = 0x4E;          
  27.     TMR0H = 0xCF;          // precargo nuevamente el timer0 (para que desborde cada 2mS)
  28.     salida = salida << 1;  
  29.     indice++;              // incremento el indice para el tiempo en alto
  30.     if (salida == 256)
  31.     {
  32.       salida = 1;
  33.       indice = 0;
  34.     }  
  35.    // precargo el timer1 con el valor correspondiente
  36.     TMR1L = parte_baja;
  37.     TMR1H = parte_alta;
  38.     INTCONbits.T0IF = 0;           // borro el flag interrupcion del timer0
  39.   }
  40.   if ((PIE1bits.TMR1IE) && (PIR1bits.TMR1IF))  // interrupcion timer1, el tiempo en alto
  41.   {
  42.     LATBbits.LATB0 = 0;           // pongo en 0 la salida actual
  43.     T1CONbits.TMR1ON = 0;         // apago el timer1
  44.     PIR1bits.TMR1IF = 0;          // borro el flag de interrupcion del timer1
  45.   }
  46. }
  47.  
  48.  
  49. void main(void)
  50. {
  51.   unsigned int valor_adc;
  52.   unsigned int valor_adc_anterior;
  53.   unsigned int pwm;
  54.  
  55.   TRISB = 0;
  56.  
  57.   // configuro los timers y les precargo un valor
  58.  
  59.   T0CON = 0x08;
  60.   T1CON = 0x80;
  61.   TMR1L = 0x77;
  62.   TMR1H = 0xEC;
  63.   TMR0L = 0x4E;
  64.   TMR0H = 0xCF;
  65.  
  66.   // habilito prioridades de interrupcion
  67.  
  68.   RCONbits.IPEN = 1;
  69.  
  70.   // el timer0 y timer1 alta prioridad
  71.  
  72.   INTCON2bits.TMR0IP = 1;
  73.   IPR1bits.TMR1IP = 1;
  74.   PIE1bits.TMR1IE = 1;
  75.   INTCONbits.TMR0IE = 1;
  76.   INTCONbits.GIEH = 1;
  77.  
  78.   T0CONbits.TMR0ON = 1;   // enciendo el timer0
  79.   adc_open(ADC_CHN_0, ADC_FOSC_16 | ADC_ACQT_4, ADC_CFG_1A, ADC_FRM_RJUST | ADC_INT_OFF | ADC_VCFG_VDD_VSS);
  80.  
  81.   while(1)
  82.   {
  83.     adc_conv();
  84.     while (adc_busy() == 1);
  85.     valor_adc = adc_read();
  86.     if (valor_adc != valor_adc_anterior)
  87.     {
  88.       valor_adc_anterior = valor_adc;
  89.  
  90.      // el calculo es 65536 - ((float)(valor_adc) * 4.887 + 5000)
  91.  
  92.       pwm = 65536- ((float)(valor_adc) * 4.887 + 4948); // uso 4948 para compenzar
  93.       parte_baja = pwm & 0x0FF;
  94.       parte_alta = pwm >> 8;
  95.     }
  96.   }
  97. }

  Fijate que hago la lectura del ADC dentro del main del programa en un ciclo while y no en la interrupción.
En mi caso leo un solo canal del ADC, pero se podría recurrir a un ciclo for para hacer la lectura de los distintos canales.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 20 de Agosto de 2012, 15:40:25
Hola AngelGris
lo delas divisiones lo puse asi
porque en el asistente de proyectos es el minimo no te deja
la opcion de 1:1 ese es el minimo la resolucion 255, 1023, 65536
lo que se corresponde con 8 bit, 10 bit y 16 bits, y lo otro que deja
es el votaje y el tipo de entrada, no hay mas.

En el data del pic18F2550 busque eso de las frecuencias:




     TAD vs. DEVICE OPERATING FREQUENCIES

               AD Clock Source (TAD)                 Maximum Device Frequency

           Operation      ADCS2:ADCS0         PIC18FXXXX     PIC18LFXXXX(4)

1.           2 TOSC           000                         2.86 MHz       1.43 MHz
2.           4 TOSC           100                         5.71 MHz       2.86 MHz
3.           8 TOSC           001                       11.43 MHz       5.72 MHz
4.         16 TOSC           101                       22.86 MHz      11.43 MHz
5.         32 TOSC           010                       45.71 MHz      22.86 MHz
6.         64 TOSC           110                       48.0 MHz        45.71 MHz

RC(3) x11 1.00 MHz(1) 1.00 MHz(2)

Note 1: The RC source has a typical TAD time of 4 ms.
2: The RC source has a typical TAD time of 6 ms.
3: For device frequencies above 1 MHz,
    the device must be in Sleep for the entire conversion or the A/D
    accuracy may be out of specification.
4: Low-power devices only.


si lo quisiera poner lo mas rapido posiblesin que atropelle a nadie
deberia de poner el punto 4. o el tunto 1.,
y el divisor en vez de por dos lo tendria que poner a 16

no estoy muy seguro, mi cristal es de 20mhz no de 22
o esto es otra cosa..

Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: Suky en 20 de Agosto de 2012, 15:53:12
No te pide que lo coloques mas rápido, sino es que esta muy rápido  :? O sea, si en máximo periodo permitido es 700ns, como lo vas a colocar 100ns  :shock: Tiene que ser minimo 7 veces más lento, o fácil coloca el oscilador RC interno  :mrgreen:
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 20 de Agosto de 2012, 15:55:10
Hola AngelGris
lo delas divisiones lo puse asi
porque en el asistente de proyectos es el minimo no te deja
la opcion de 1:1 ese es el minimo la resolucion 255, 1023, 65536
lo que se corresponde con 8 bit, 10 bit y 16 bits, y lo otro que deja
es el votaje y el tipo de entrada, no hay mas.


  A lo que me refiero es que no es necesario hacer una función a la cual pasarle tantos parámetros. Concretamente tu función potenciometro.

  debería dejarte poner simplemente...

Código: C
  1. variable = (float)(ADC) * 2.49 + 600;
  2. precarga = 65536 - variable;

  sin necesidad que pases como variable, el máximo y el mínimo.


En el data del pic18F2550 busque eso de las frecuencias:




     TAD vs. DEVICE OPERATING FREQUENCIES

               AD Clock Source (TAD)                 Maximum Device Frequency

           Operation      ADCS2:ADCS0         PIC18FXXXX     PIC18LFXXXX(4)

1.           2 TOSC           000                         2.86 MHz       1.43 MHz
2.           4 TOSC           100                         5.71 MHz       2.86 MHz
3.           8 TOSC           001                       11.43 MHz       5.72 MHz
4.         16 TOSC           101                       22.86 MHz      11.43 MHz
5.         32 TOSC           010                       45.71 MHz      22.86 MHz
6.         64 TOSC           110                       48.0 MHz        45.71 MHz

RC(3) x11 1.00 MHz(1) 1.00 MHz(2)

Note 1: The RC source has a typical TAD time of 4 ms.
2: The RC source has a typical TAD time of 6 ms.
3: For device frequencies above 1 MHz,
    the device must be in Sleep for the entire conversion or the A/D
    accuracy may be out of specification.
4: Low-power devices only.


si lo quisiera poner lo mas rapido posiblesin que atropelle a nadie
deberia de poner el punto 4. o el tunto 1.,
y el divisor en vez de por dos lo tendria que poner a 16

no estoy muy seguro, mi cristal es de 20mhz no de 22
o esto es otra cosa..



  Esos 22MHz significan que si usas esa configuración, la máxima frecuencia que puedes usar de cristal es justamente 22MHz.

  En tu caso con cristal de 20MHz / 16 --> 1.25MHz --> tiempo 800nS que cumple con la premisa que TAD >= 700nS
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 20 de Agosto de 2012, 20:11:37
Hola

modifique la adquisicion de adc, de la interrupcion al while,
al final la conversion la puse div_16 printeo desde el while
con el potenciometro de 1k en su posicion de %50 en el adc da 40
cuando esta casi al final me pasa de 667 a 1018 y ese es el maximo

si operamos con (1018  *2.49) + 600
sale 3134.82-->redondeando 3135

si el maximo por encima es 3150 eso explicaria que con el potencimentro le faltara un cachito
en uno de sus extremos y sile añadimos que el centro esta desplazado
eso esplica casi los 45 grados hasta 180.

repasare las opreaciones por si me cole en algo, pero se comporta de la misma forma
haciendo sin funcion ...

miestras si se ocurre alguna idea del comportamiento del potenciometro
toda ayuda o idea es bienvenida.

no se si es efecto del refresco ..

por cierto, la señal de pwm en el osciloscopio no se cantea nada no se
si es un efecto del osciloscopio porque la cpu del proteus la tengo saltando de
entre 70% a 95% y de normal por encima del 80%

voy a revisar las cosas...
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: AngelGris en 20 de Agosto de 2012, 21:27:10
Hola

modifique la adquisicion de adc, de la interrupcion al while,
al final la conversion la puse div_16 printeo desde el while
con el potenciometro de 1k en su posicion de %50 en el adc da 40
cuando esta casi al final me pasa de 667 a 1018 y ese es el maximo


  Definitivamente hay algo que NO está bien. Con un pote lineal, a la mitad de su recorrido, el ADC debería leer como muy variable entre 510 y 512, pero nunca tener una lectura de 40.
Título: Re: :: PWM :: CCS :: PIC18F2550 :: SERVOS::
Publicado por: pajaro en 21 de Agosto de 2012, 13:55:32
Hola

El tema del potenciomentro es raro,
pero lo dejo pendiente para cuando me funciones lo del pwm y el i2c.


#################################

      PENDIENTE REVISAR PONTENCIOMETRO

#################################

ya que la idea es pasarle distinto ancho de pulso a las diferentes
salidas y el i2c me lo esta poniendo dificil por problemas raros..