TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Nocturno en 02 de Octubre de 2008, 02:35:34

Título: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 02 de Octubre de 2008, 02:35:34
Aprovechando el éxito que obtuve al preguntar Algoritmo para cargar un registro en serie "por la izquierda" (http://www.todopic.com.ar/foros/index.php?topic=23213.0), hoy os planteo la optimización de otro algoritmo.
En esta ocasión se trata de una función que se alimenta de dos variables para generar pulsos Quadrature como estos:
(http://digital.ni.com/public.nsf/ad0f282819902a1986256f79005462b1/d60556bf06fb8a9a862572d8005eaa3a/$FILE/encoder-phase.gif)

Las variables son:

Aquí una propuesta de algoritmo, que ya funciona, y con el que soy capaz de generar una señal de 42,8KHz trabajando a 12MIPS. Estoy seguro que podemos acelerarla un huevo, a ver qué decis.

Código: Javascript
  1. void EnviaPulsosQuadrature() {
  2.    while (PulsosEncoder--) {
  3.    
  4.       switch (IndQuad%4) {                
  5.          case 0b00:                      
  6.             output_low (PIN_B6);
  7.             output_low (PIN_B5);
  8.             break;
  9.          case 0b01:
  10.             output_high (PIN_B6);
  11.             output_low (PIN_B5);
  12.             break;
  13.          case 0b10:
  14.             output_high (PIN_B6);
  15.             output_high (PIN_B5);
  16.             break;  
  17.          case 0b11:
  18.             output_low (PIN_B6);
  19.             output_high (PIN_B5);
  20.             break;
  21.       }
  22.       if (Sentido)              
  23.         IndQuad++;
  24.       else
  25.         IndQuad--;
  26.    }
  27. }
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: RedPic en 02 de Octubre de 2008, 16:33:59
Prueba con esto con tu nuevo osciloscopio (pronunciado con retintín) y dime algo, payo.  :mrgreen:

Código: C#
  1. #bit ENCODER_A = 0xF81.6 // PIN_B6 si es un 18F4550
  2. #bit ENCODER_B = 0xF81.5 // PIN_B5 si es un 18F4550
  3.  
  4. void EnviaPulsosQuadrature(int16 PulsosEncoder, int1 Sentido){
  5.  
  6.    int8 IndQuad=0;
  7.  
  8.    while (PulsosEncoder--) {
  9.       ENCODER_A=(bit_test(IndQuad,1)+Sentido);
  10.       ENCODER_B=(bit_test(IndQuad,1)+bit_test(IndQuad+1,0));
  11.       IndQuad++;
  12.    }
  13. }
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 03 de Octubre de 2008, 01:30:48
Tal y como está funciona a 66KHz  :-/ pero no cambia de sentido.
Voy revisando
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 03 de Octubre de 2008, 02:37:33
Ná, olvídalo, que funcionó bien a la primera. Es que estoy acarajotao.

(http://img242.imageshack.us/img242/940/haciaunladoqm2.jpg)

(http://img364.imageshack.us/img364/9214/haciaelotroov8.jpg)

Muchas gracias, Don Diego.

P.D.: en la esquina superior derecha está la frecuencia


Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Kid_Bengala en 03 de Octubre de 2008, 07:22:14
Todo ello hecho con tu NUEVO OSCILOSCOPIOOOO  :mrgreen:

saludos de antonio
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: MLO__ en 03 de Octubre de 2008, 10:39:49
Oye Nocturno ..... no me digas que el calibrador Bernier Digital que tienes lo usas para .... medir el ancho de los pulsos  :D :D :D

Muy buena compra ... felicitaciones

saludos
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 03 de Octubre de 2008, 15:58:47
Bueno Manolo, estuve meditandoló...

Como yo soy un freaky y vos lo que buscás es velocidad, automáticamente lo razoné en assembler. Lo posteo y después lo intento pasar a C, pasa que hay que ir mirando el codigo assembler que genera. Si no me equivoco, esta rutina debería ser unas cuantas veces mas rapida que las anteriores...

Eso sí. Me tomé el lujo de agregar una variable auxiliar de 8 bits llamada "sequence", y hay que inicializarla al inicio del programa:


Código: ASM
  1. #DEFINE X       PORTB,6
  2. #DEFINE Y       PORTB,5
  3.  
  4.  
  5.         movlw   0xCC
  6.         movwf   sequence
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13. Girar   movf    PulsosEncoder,f
  14.         btfsc   STATUS,Z
  15.         return
  16.  
  17.         btfss   Sentido,0               //0=Izq,1=Der
  18.         goto    Der
  19.                
  20. Izq     rlf     sequence,w
  21.         rlf     sequence,f
  22.  
  23.         btfss   sequence,1
  24.         bcf     X
  25.         btfsc   sequence,1
  26.         bsf     X
  27.  
  28.         btfss   sequence,0
  29.         bcf     Y
  30.         btfsc   sequence,0
  31.         bsf     Y
  32.  
  33.         decfsz  PulsosEncoder,f
  34.         goto    Izq
  35.         return
  36.  
  37. Der     rrf     sequence,w
  38.         rrf     sequence,f
  39.  
  40.         btfss   sequence,1
  41.         bcf     X
  42.         btfsc   sequence,1
  43.         bsf     X
  44.  
  45.         btfss   sequence,0
  46.         bcf     Y
  47.         btfsc   sequence,0
  48.         bsf     Y
  49.  
  50.         decfsz  PulsosEncoder,f
  51.         goto    Der
  52.         return
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 03 de Octubre de 2008, 16:30:57
Inicializo sequence a 0xCC, o sea, en binario: 11001100. Si ahora lo ubico de manera circular:


                                         0     0
                                      1           1
                                      1           1
                                         0     0

Y ahora digo que X= PORTB.6 e Y= PROTB.5, entonces:

                                         X     Y
                                         0     0
                                      1           1
                                      1           1
                                         0     0

y asigno a X e Y el valor que figura inmediatamente debajo de ellos(en la figura anterior, X=0 e Y=0).

Ahora con las rotaciones hago girar la ruedita esta...(vamos en sentido antihorario)

(1era rotacion)

                                         X     Y
                                         0     1
                                      0           1
                                      1           0
                                         1     0

(2da rotacion)

                                         X     Y
                                         1     1
                                      0           0
                                      0           0
                                         1     1

(3era rotacion)

                                         X     Y
                                         1     0
                                      1           0
                                      0           1
                                         0     1


(4ta rotacion)

                                         X     Y
                                         0     0
                                      1           1
                                      1           1
                                         0     0


y en sentido horario sería similar...

Bueno, a la noche veo si lo programo para C(siempre y cuando interese)...

Saludos.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 03 de Octubre de 2008, 17:24:48
Vamos, vamos, que va a salir algo bonito. Me ha encantado lo del circulito.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 03 de Octubre de 2008, 22:23:48
Bueno, encontré otras opciones(usando un goto) que va más rápido y demás cosillas...pero ya se torna un poco pseudoassembler asi que para mantenerlo sencillo y bueno...a ver a cuánto furula(y si es que furula :))

Sequence es un int8 que debe ser inicializado con el valor 0xCC(o el que corresponda a la 1era posicion del cuadrante)
Como sé que sos de usar variables globales, PulsosEnconder y Sentido son globales aquí.

Código: C#
  1. void EnviaPulsosQuadrature3(){
  2.    while(PulsosEncoder--){
  3.       if(Sentido) rotate_right(&Sequence,1); else rotate_left(&Sequence,1);
  4.       ENCODER_A = bit_test(Sequence,1);
  5.       ENCODER_B = bit_test(Sequence,0);      
  6.    }
  7. }

Saludos
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 04 de Octubre de 2008, 01:06:32
¡Espectacular, Don Bruno!
¡Hemos subido a 91KHz!, más del doble de cuando empezamos.

¿Quién da más?

P.D.: soy partidario de variables globales porque el código sale más pequeño y se ejecuta más rápido, aunque sé que no es lo más apropiado dentro de una etiqueta de programación correcta.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 04 de Octubre de 2008, 21:53:09
Uff Manolo!
Va a estar difícil superar eso.
La puedo acelerar un poco, pero queda un poco menos elegante...
A ver si las armo...

Saludos.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 05 de Octubre de 2008, 01:47:44
Hay una forma de acelerarlo aún más, que me obligaría a cambiar el esquema del circuito, pero lo mismo me animo: si pongo las salidas en un puerto que no esté utilizando, con rotar el puerto tengo suficiente, no será necesario luego asignar ningún valor a los pines de salida.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 05 de Octubre de 2008, 07:33:45
Es una idea muy buena! No pense que podías modificarlo hasta ese punto...

El algoritmo que publiqué antes tiene 13 instrucciones asm que son las que generan las ondas. Esta que posteo ahora tiene 11(y podrían ser 10, pero no logro que el CCS utilice la instrucción decfsz para agilizar el decremento de PulsosEncoder) siempre y cuando a PulsosEnconder la declares como un int8.
Destaco que este algoritmo solo funciona para los pines RB5 y RB6.

Código: C#
  1. void EnviaPulsosQuadrature(){
  2.    if(Sentido){
  3.       Otra_Der:
  4.       rotate_right(&Sequence,1);
  5.       PORTB= (Sequence & 0b01100000) | (PORTB & 0b10011111);
  6.       if(--PulsosEncoder!=0) goto Otra_Der;
  7.    }else{
  8.       Otra_Izq:
  9.       rotate_left(&Sequence,1);
  10.       PORTB= (Sequence & 0b01100000) | (PORTB & 0b10011111);
  11.       if(--PulsosEncoder!=0) goto Otra_Izq;
  12.    }
  13. }

Y debo admitir, que fuera de la posibilidad que mencionaste, no exíste(por lo que estudié) manera de bajar el algoritmo de 10 instrucciones en assembler.

Adjunto el código assembler que genera de salida..(CCS Versión 4.058)

Código: ASM
  1. .................... void EnviaPulsosQuadrature(){
  2. ....................    if(Sentido){
  3. 0004:  BTFSS  06.0
  4. 0006:  BRA    0022
  5. ....................       Otra_Der:
  6. ....................       rotate_right(&Sequence,1);
  7. 0008:  RRNCF  07,F
  8. ....................       Aux= PORTB;
  9. 000A:  MOVFF  F81,08
  10. ....................       Aux&=0b10011111;
  11. 000E:  MOVLW  9F
  12. 0010:  ANDWF  08,F
  13. ....................       PORTB= (Sequence & 0b01100000) | Aux;
  14. 0012:  MOVF   07,W
  15. 0014:  ANDLW  60
  16. 0016:  IORWF  08,W
  17. 0018:  MOVWF  F81
  18. ....................       if(--PulsosEncoder!=0) goto Otra_Der;
  19. 001A:  DECF   05,F
  20. 001C:  BZ    0020
  21. 001E:  BRA    0008
  22. ....................    }else{
  23. 0020:  BRA    003A
  24. ....................       Otra_Izq:
  25. ....................       rotate_right(&Sequence,1);
  26. 0022:  RRNCF  07,F
  27. ....................       Aux= PORTB;
  28. 0024:  MOVFF  F81,08
  29. ....................       Aux&=0b10011111;
  30. 0028:  MOVLW  9F
  31. 002A:  ANDWF  08,F
  32. ....................       PORTB= (Sequence & 0b01100000) | Aux;
  33. 002C:  MOVF   07,W
  34. 002E:  ANDLW  60
  35. 0030:  IORWF  08,W
  36. 0032:  MOVWF  F81
  37. ....................       if(--PulsosEncoder!=0) goto Otra_Izq;
  38. 0034:  DECF   05,F
  39. 0036:  BZ    003A
  40. 0038:  BRA    0022
  41. ....................    }
  42. .................... }
  43. 003A:  GOTO   011E (RETURN)

P.D: O acaso estas usando C18?  :?

Saludos.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 06 de Octubre de 2008, 02:44:32
¡Bravo, Bruno, has vuelto a conseguirlo!

Ahora volamos a 187,5KHz

(http://img508.imageshack.us/img508/406/quadrature187jc2.jpg)

He probado a rotar directamente sobre el puerto B pero no he conseguido que funcione. De todas formas, ya me doy por satisfecho y no seguiré intentándolo. Gracias a todos los que me habéis ayudado.

Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Kid_Bengala en 06 de Octubre de 2008, 13:44:42
Como te gusta fardar con tu nuevo osciloscopio ehhh jejeje  :P

Por cierto, que estais intentando hacer, mover la los pulsos a la izquierda, bueno moverlos, que el siguiente pulso este mas desplazado a la izquierda ¿o como?.

saludos de antonio
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 06 de Octubre de 2008, 13:55:05
Es que estoy encantado con él :D

Lo que ves en la pantalla es una señal generada para alimentar a otro dispositivo, que está preparado para recibir información de un encoder de cuadratura (http://ar.geocities.com/valdezda/microcontroladores/encoderrot.htm).
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 06 de Octubre de 2008, 15:42:27
Me alegro Manolo! :)

He probado a rotar directamente sobre el puerto B pero no he conseguido que funcione.

¿Lo que sigue no funciona?

Código: C#
  1. void EnviaPulsosQuadrature(){
  2.    if(Sentido){
  3.       Otra_Der:
  4.       rotate_right(&PORTB,1);
  5.      
  6.       if(--PulsosEncoder!=0) goto Otra_Der;
  7.    }else{
  8.       Otra_Izq:
  9.       rotate_left(&PORTB,1);
  10.       if(--PulsosEncoder!=0) goto Otra_Izq;
  11.    }
  12. }

Obviamente PORTB debería ser declarado como un byte previamente(#byte PORTB = 0xF81) y configurado TODO como salidas y FIXED_IO.
Además, deberías inicializar a PORTB con el valor 0x99(0b10011001) para comenzar desde 00 con RB5 y RB6.

Exitos y no ha sido nada amigo.

P.D. ese osciloscopio está porno(es decir, hermoso).

Saludos.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: Nocturno en 06 de Octubre de 2008, 15:47:17
Sí, lo probé exactamente como tú has puesto ahí, pero no perdí mucho tiempo, así que seguro que se me escapó una tontería.

Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 06 de Octubre de 2008, 15:59:03
Hmmm...mirando el codigo asm de salida, me atrevería a decir que debería funcionar. No sería la primera vez que hago algo así y ha funcionado...
Ahora, de lograrlo, la frecuencia sería muy superior a la actual(según mis cálculos sería de 1.5Mhz)

A la espera de ver si lo pruebas...

Saludos.
Título: Re: Generando N pulsos Quadrature con dirección
Publicado por: BrunoF en 06 de Octubre de 2008, 16:01:42
He probado a rotar directamente sobre el puerto B pero no he conseguido que funcione. De todas formas, ya me doy por satisfecho y no seguiré intentándolo.

Joer, me había perdido esa última oración. Ok. Será 187.5Khz entonces...