Autor Tema: Dudas con operacion aritmética  (Leído 8773 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Dudas con operacion aritmética
« en: 21 de Marzo de 2015, 08:31:27 »
Código: C
  1. #include <16F88.h>
  2. #device adc=8
  3. #FUSES NOWDT,INTRC_IO,MCLR,PUT,NOBROWNOUT,NOCPD,NOLVP,NOIESO,NODEBUG
  4.  
  5. //--- Constantes ---
  6. #define SERVO_1   PIN_A0   //linea de control por PWM para el servo
  7. #define ADC_SERVO     1    //canal adc que se usa para el potenciometro
  8. //------------------
  9.  
  10. #use delay(clock=4000000)
  11. #use standard_io(a)
  12. #use standard_io(b)
  13.  
  14. //--- Variables ---
  15. int1 flag5RTCC = TRUE;           //indica si se completaron 5 RTCC
  16. int1 flag50mS = FALSE;           //indica si ocurrio interrupcion de timer1
  17. int1 flagPulso_Alto = FALSE;     //indica si esta el pulso en alto
  18. int8 Posicion_Servo = 93;        //donde se posiciona el servo segun la lectura del adc
  19. int8 ContRTCC = 0;               //contador de RTCC
  20. //-----------------
  21.  
  22. //--- Funciones ---
  23. void Calcular_Posicion(void);
  24. //-----------------
  25.  
  26. #int_TIMER0
  27. void TIMER0_isr(void){        //timer que cuenta 20mS
  28. //Timer de 8 bits --> 256 = 1 RTCC
  29. //Pescaler de 1:16
  30. //1 tick cada 16 uS = 0.016mS
  31. //1 RTCC cada 4.0mS (256 - 6 Ticks)
  32. //5 RTCC = 20mS
  33.  
  34.    ContRTCC = ContRTCC + 1;
  35.    set_TIMER0(6);
  36.  
  37.    if(ContRTCC == 5){
  38.       flag5RTCC = TRUE;
  39.       ContRTCC=0;
  40.    }
  41. }
  42.  
  43. #int_TIMER1
  44. void TIMER1_isr(void) {       //timer que cuenta 50mS
  45. //Timer de 16 bits --> 65536 = 1 RTCC
  46. //Pescaler de 1:1
  47. //1 tick cada 1 uS
  48. //1 RTCC cada 50mS (65536 - 15536 Ticks)
  49.  
  50.    set_TIMER1(15535);
  51.    flag50mS = TRUE;
  52. }
  53.  
  54. void main(void) {
  55.    int8 ValTMR0;
  56.  
  57.    setup_adc_ports(sAN1|VSS_VDD);
  58.    setup_adc(ADC_CLOCK_INTERNAL);
  59.    setup_spi(FALSE);
  60.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
  61.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  62.    setup_timer_2(T2_DISABLED,0,1);
  63.    setup_comparator(NC_NC_NC_NC);
  64.    setup_vref(FALSE);
  65.    enable_interrupts(INT_TIMER1);
  66.    enable_interrupts(INT_TIMER0);
  67.    enable_interrupts(GLOBAL);
  68.    setup_oscillator(OSC_4MHZ|OSC_INTRC);
  69.  
  70.    set_adc_channel(ADC_SERVO);
  71.    
  72.         do {
  73. //>-----------------------Movimiento del servo--------------------------------->
  74.  
  75.          //--- Calcula posicion servo segun lectura adc ---
  76.          if(flag50mS == TRUE){
  77.             Calcular_Posicion();
  78.             flag50mS = FALSE;
  79.          }
  80.          //------------------------------------------------
  81.  
  82.          //--- Dispara pulso PWM cuando se completan 5 RTCC ---
  83.                 if(flag5RTCC == TRUE){
  84.                         flag5RTCC = FALSE;
  85.             output_high(SERVO_1);
  86.             flagPulso_Alto = TRUE;
  87.                 }
  88.          //----------------------------------------------------
  89.  
  90.          //--- Baja pulso PWM cuando corresponda ---
  91.                 valTMR0 = get_TIMER0() - 6;
  92.  
  93.                 if((flagPulso_Alto == TRUE) && (valTMR0 > Posicion_Servo)){  //baja el pulso en el tiempo correspondiente a Posicion
  94.             output_low(SERVO_1);
  95.             flagPulso_Alto = FALSE;
  96.          }
  97.          //-----------------------------------------
  98. //<----------------------------------------------------------------------------<
  99.  
  100.         } while(true);
  101. }
  102.  
  103. void Calcular_Posicion(void){
  104.    int16 ValorADC;
  105.    ValorADC = read_adc();
  106.    Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 255);
  107. }
Buenos días, estoy intentando comprender el funcionamiento de este código escrito por Marttyn en este foro y en la función
void Calcular_Posicion(void) esta la operación aritmética
Código: C
  1. Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 255);
pero no consigo comprender de donde sale en valor 31 y 124, por lo que he leído en su post convierte la señal analógica del potenciómetro en ticks para posicionar el servo.

Gracias.
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Dudas con operacion aritmética
« Respuesta #1 en: 21 de Marzo de 2015, 11:01:26 »
Para mi son constantes que permiten ajustar el Offset y el Span (0 y rango) de acuerdo a cada servo. No todos los servos estan centrados con el mismo ciclo del PWM y no todos tienen el mismo recorrido. Algunos responden desde 0.5mseg hasta 1.5mseg, pero otros responden a mas o menos.

Cada Tick del RTCC son 4useg. Dependiendo del servo, responde entre 0 y 2000useg como maximo. Entre 500useg y 1500useg generalmente.
El ADC va de 0 a 255. Entonces posiscion_servo puede devolver entre 31 y 155, que al multiplicarlo por 16useg nos da 496useg y 2480useg

Entonces con esas cte se regula el recorrido del servo.

saludos!
-
Leonardo Garberoglio

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #2 en: 21 de Marzo de 2015, 18:02:14 »
Gracias elgarbe por molestarte en contestar, intentare entender lo que explicas.

Saludos!
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #3 en: 21 de Marzo de 2015, 18:59:07 »
Creo que lo entiendo, voy a intentar realizar dicha operación en ASM, si es posible  :mrgreen:

Miquel_S
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Dudas con operacion aritmética
« Respuesta #4 en: 21 de Marzo de 2015, 20:00:07 »
Deberias hacerlo dividido 256 si lo vas a hacer en ASM, no vas a perder mucha precision.

Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 256);

o que es lo mismo que :

Posicion_Servo = 31 + (int16)((int16)(ValorADC * 31) / 64);

 que es lo mismo que:

Posicion_Servo = 31 ( 1 + ValorADC / 64);

Es decir rotar 6 veces sumarle 1 y multiplicarlo por 31.. este seria lo mas simple
Pero tendrias bastante erro ya que perderias todas las comas. Sino hace la anterior, multiplicalo por 31 y luego dividilo por 64 ( 2^6 )
Y si tiene un multiplicador por HW se hace mucho mas facil aun
« Última modificación: 21 de Marzo de 2015, 20:03:56 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #5 en: 21 de Marzo de 2015, 20:54:25 »
 ;-) Gracias KILLERJC se ara lo que se pueda, voy a intentarlo con la primera opción:

Código: C
  1. Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 256);
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Dudas con operacion aritmética
« Respuesta #6 en: 21 de Marzo de 2015, 21:18:15 »
A ver si lo puedo explicar mejor por si quedan dudas.
El servo para funcionar necesita un PWM con frecuencia de 50Hz (20mseg de período). Variando el tiempo en que esta en ON el PWM se varía la posicion del servo.
Los servos se centran cuando el Ton es de 1mseg. Los servos estan 180° antihorario cuando el Ton es 0mseg. Los servos estan 180° en sentido horario cuando el Ton es de 2mseg.
El tema es que no todos los servos pueden recorrer 180°. Lo comun es tener servos de 90° en cada sentido. Entonces se centran en 1mseg y responden entre 0.5mseg y 1.5mseg.
Lo que hay que conseguir es transformar las 255 cuentas del ADC en tiempo. En el programa han configurado el Tick del RTCC en 16useg:
Código: [Seleccionar]
#int_TIMER0
void TIMER0_isr(void){        //timer que cuenta 20mS
//Timer de 8 bits --> 256 = 1 RTCC
//Pescaler de 1:16
//1 tick cada 16 uS = 0.016mS

En el programa principal, cuando se detectan 5 overflow del RTCC (20mseg) se pone la salida al servo en 1. Para saber cuando hay que poner en 0 ese pin es que usa la funcion por la cual preguntas.
En esta parte del código:
Código: [Seleccionar]
         //--- Baja pulso PWM cuando corresponda ---
  valTMR0 = get_TIMER0() - 6;
 
  if((flagPulso_Alto == TRUE) && (valTMR0 > Posicion_Servo)){  //baja el pulso en el tiempo correspondiente a Posicion
           output_low(SERVO_1);
           flagPulso_Alto = FALSE;
Se obtiene el valor del Timer, que al multiplicarlo por 16useg se obtiene el tiempo en que viene estando la señal en 1. Luego se pregunta, si el valor del timer alcanzó el valor de la cuenta que saca en esa funcion. Si ya llegamos al tiempo puesto por el potenciometro se baja la señal y se sigue repitiendo el proceso.

Como el servo responde entre 0.5mse y 1.5 mseg, esa funcion debería retorna un número entre 500useg/16useg = 31 y 1500useg/16useg=93
O sea que cuando el ADC es 0 debería devolver 31 y cuando el ADC es 255 debería devolver 93.
Si haces (93-31) = 62 es el valor por el que yo creo debería multiplicar. En el ejemplo, multiplica por 124 y no estoy seguro porque, es como que llegaría hasta 2.5mseg, o sea mas de 180° en un sentido... probalo y si no te anda, o para un lado gira mas que para el otro es por ese número...

Saludos
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Dudas con operacion aritmética
« Respuesta #7 en: 21 de Marzo de 2015, 21:40:06 »
;-) Gracias KILLERJC se ara lo que se pueda, voy a intentarlo con la primera opción:

Código: C
  1. Posicion_Servo = 31 + (int16)((int16)(ValorADC * 124) / 256);

Me refiero que a la operacion es lo mismo la primera que la segunda, solo simplifique el 124/256 ( ya que ahora es potencia de 2 ) a 31/64

De esa forma multiplicas por menos, tenes un valor mas pequeño y ocupas menos instrucciones.

Citar
voy a intentar realizar dicha operación en ASM, si es posible

Y es por eso que lo digo.. Ademas en el peor caso:

1023 * 124 = 126852 = 17 bits
1023 * 31 = 31713 = 15 bits

Si lo vas a hacer en ASM y no tenes multiplicador por HW, deberias sumar y sumar eso ( 31 veces ). ocuparias 2 registros Y luego dividir es un borrar carry y 2 rotar ( 1 por cada registro ) a traves del carry a la derecha por cada division por 2.
Lo cual imagino que quedaria bastante corto, segun sea el micro que estes usando, sino pasa el micro y hacemos la funcion en ASM en un ratito.

EDIT: Por que estaba mirando el techo lo hice:
Por si tenes un PIC16F

Código: ASM
  1. ; Realiza esta operacion:
  2. ; 31 + ((ValorADC * 31) / 64)
  3. ;
  4. ; Entrada:  ADRESH y ADRESL ( justificado derecha )
  5. ;
  6. ; Salida:   POSIC_H:POSIC_L ( 16 bits )
  7. ;
  8. ; Registros usados: 5 (3 temporales) - POSIC_H , POSIC_L , TEMP_L , TEMP_H , TEMP
  9. ;
  10.  
  11. ; 31d = 1Fh = 0001 1111
  12. ; Como son todos 1 simplemente roto por esa cantidad y sumo
  13. ;
  14. ; Podia hacerlo de 4 formas a la multiplicacion:
  15. ;  - Sumar 31 veces el resultado del ADC (31 sumas de 16bits )
  16. ;  - Sumar 31 por cada unidad del resultado del ADC (x sumas de 16 bits)
  17. ;  - Realizar ((ADC * 2) * 3 ) * 5 + ADC = ADC * 31 , separo en simples rotaciones y sumas ( *2 = rotacion , *3 = rotacion y suma , *5 = 2 rotacion y suma )
  18. ;  - Sumar las rotaciones de cada 1 - Elegi esta ultima por ser la mas corta en programa aunque lleve un par de ciclos mas (4 sumas de 16bits + rotacion)
  19. ;
  20.  
  21.  
  22. POSICION
  23.         MOVLW   0x04
  24.         MOVWF   TEMP
  25.         MOVF    ADRESH,W
  26.         MOVWF   TEMP_H
  27.         MOVWF   POSIC_H
  28.         MOVF    ADRESH,W
  29.         MOVWF   TEMP_L
  30.         MOVWF   POSIC_L         ;Ya tengo 2^0 realizado
  31.  
  32. MULT
  33.         BCF     STATUS,C        ; Roto registro auxiliar
  34.         RLF     TEMP_L,F
  35.         RLF     TEMP_H,F
  36.         MOVF    TEMP_L,W
  37.         ADDWF   POSIC_L,F       ; Sumo, si hubo acarreo se lo sumo al registro superior
  38.         BTFSC   STATUS,C
  39.         INCF    POSIC_H,F
  40.         MOVF    TEMP_H,W
  41.         ADDWF   POSIC_H,F       ; Directamente sumo, ya que con 10 bits nunca superaria los 16bits aun asi tuviera 1023 o 0x3FF de entrada
  42.         DECFSZ  TEMP,F          ; Termino de multiplicar?
  43.         GOTO    MULT
  44.         MOVLW   0x06            ; Cargo mi division 2^6
  45.         MOVWF   TEMP
  46. DIVI
  47.         BCF     STATUS,C
  48.         RRF     POSIC_H,F
  49.         RRF     POSIC_L,F
  50.         DECFSZ  TEMP,F          ;Termine de dividir?
  51.         GOTO    DIVI
  52.         MOVLW   0x1F            ; Sumo los 31 = 0x1F
  53.         ADDWF   POSIC_L,F
  54.         BTFSC   STATUS,C
  55.         INCF    POSIC_H,F
  56.         RETURN

Tal ves me podria haber ahorrado 2 registros o 1 pero creo que se complicaba mas. Y registros auxiliares/temporales siempre hacen falta.. asi que podes reutilizarlos en otra funcion
Y el codigo ASM que pase se podria modificar para que sea un producto general de 8 * 16 bits
« Última modificación: 22 de Marzo de 2015, 09:21:57 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #8 en: 22 de Marzo de 2015, 06:51:16 »
Gracias a los dos por molestaros en ayudarme a aprender, con ustedes da gusto ir a clase, ahora no puedo pero esta tarde me pongo con ello y iré contando los resultados.

Nuevamente MUCHAS GRACIAS
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #9 en: 22 de Marzo de 2015, 18:01:01 »
Hola, solo una cosa, estoy intentando comprender el código escrito por KILLERJC y me he encontrado con una errata creo que donde dice:
Código: ASM
  1. POSICION
  2. MOVLW   0x04
  3. MOVWF   TEMP
  4. MOVF    ADRESH,W
  5. MOVWF   TEMP_H
  6. MOVWF   POSIC_H
  7. MOVF    ADRESH,W
  8. MOVWF   TEMP_L
  9. MOVWF   POSIC_L   ;Ya tengo 2^0 realizado
el segundo ADRESH,W debería de ser ADRESL,W

Saludos!
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Dudas con operacion aritmética
« Respuesta #10 en: 22 de Marzo de 2015, 18:16:20 »
Si perdon, el codigo le simule y funciona, nomas que usaba 2 registros ADCL y ADCH cuando simulaba (asi antes de llamar a la funcion le cargaba los valores que queria para probarlo) pero luego busque y tome del datasheet ADRESH y copie y pegue solo para ponerlo aca. y me olvide cambiarle la H por la L xD

Empiezo por la multiplicacion:

31d = 0x1F = 0001 1111

si hago ADC * 0x1F
es lo mismo que hacer:

ADC * 0x01 + ADC * 0x02 + ADC * 0x04 + ADC * 0x08 + ADC * 0x10
o que es lo mismo que:
ADC * 2^0 + ADC * 2^1 + ADC * 2^2 + ADC * 2^3 + ADC * 2^4

Son rotaciones. ahi en posicion al guardar en POSIC_x ya estaria haciendo la primera, que es ADC * 2^0 = ADC
En TEMP_x ya tengo el valor del ADC tambien
Roto TEMP_x y ahora tengo el resultado de ADC * 2^1, entonces se lo sumo a lo que ya tenia y asi consecutivamente
Si se produce un carry en la suma como es de 16 bits y le sumo 1 a la parte alta. Una ves que hice todas las multiplicaciones TEMP queda en 0 y paso a la division
La division es simple tambien, solo rotar
Y cuando roto la cantidad suficiente de veces le sumo 31d ( y obviamente me fijo si hay carry ) y listo fin

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

Si se puede simplificar o hacer mas corto, pensandolo de otra forma que recien se me ocurre..
(El caso que hice con mi ASM es mas general, se puede extender a cualquier numero preguntando si bit esta en 0 o cosas asi, este es especifico del valor 31)

Multiplica todo por 32 ( 2^5 ) y restale ADC

ADC * 32 - ADC = ADC * 31

Constaria de 5 rotaciones, guardar y luego restar, esto haria que tal vez no necesites de los TEMP_x ( aunque si llega a variar el resultado del ADC entonces deberias de tener esos TEMP_x para que no varie de ninguna forma )
Tal ves mas corto el programa en tema de ciclos pero igual de largo

El codigo:

Código: ASM
  1. POSICION2
  2.     MOVLW       0x05
  3.     MOVWF       TEMP
  4.     MOVF        ADRESH,W
  5.     MOVWF       TEMP_H
  6.     MOVWF       POSIC_H
  7.     MOVF        ADRESL,W
  8.     MOVWF       TEMP_L
  9.     MOVWF       POSIC_L
  10.  
  11. MULT2
  12.     BCF         STATUS,C        ;Multiplicacion * 32
  13.     RLF         POSIC_L,F
  14.     RLF         POSIC_H,F
  15.     DECFSZ      TEMP,F
  16.     GOTO        MULT2
  17.     MOVF        TEMP_L,W        ; Comienzo del restado POSIC = POSIC - TEMP   (16 bits ambos )
  18.     SUBWF       POSIC_L
  19.     MOVF        TEMP_H,W
  20.     BTFSS       STATUS,C
  21.     INCFSZ      TEMP_H,W
  22.     SUBWF       POSIC_H         ; Fin del restado
  23.     MOVLW       0x06            ;Division
  24.     MOVWF       TEMP
  25. DIV2
  26.     BCF         STATUS,C
  27.     RRF         POSIC_H,F
  28.     RRF         POSIC_L,F
  29.     DECFSZ      TEMP,F
  30.     GOTO        DIV2
  31.     MOVLW       0x1F            ;Suma
  32.     ADDWF       POSIC_L,F
  33.     BTFSC       STATUS,C
  34.     INCF        POSIC_H,F
  35.     RETURN

La diferencia es que este usa 12 ciclos menos que el que pase primero. Este usa 84 ciclos

-----------

Con respecto a las rotaciones pongo un 0 siempre al comienzo en en flag de carry.
asi al rotar el byte superior, si tenia un 1 en el bit0, este queda en el carry, y cuando roto el inferior ese 1 viene del registro alto.
O cuando rotas a la izquierda es lo mismo, mi idea es multiplicarlo por 2 asi que no puede agregarse ningun 1 a la cola ( o parte baja del byte )

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

EDIT:

Se me siguen ocurriendo cosas Como:
31 + ADC * 31/64 =  31 + ADC * (32 - 1)/64 =
31 + 32*ADC/64 - ADC/64 = 31 + ADC/2 - ADC/64

ADC/2 = 1 rotacion
ADC/64 = 6 rotaciones a la derecha de 16 bits o 2 rotaciones a la derecha y tomar el nibble alto del byte bajo o 2 rotaciones a la izquierda y tomar el byte mayor como el byte menor total el otro es 0.

Código: ASM
  1. POSICION3
  2.     MOVF        ADRESH,W
  3.     MOVWF       TEMP_H
  4.     MOVWF       POSIC_H
  5.     MOVF        ADRESL,W
  6.     MOVWF       TEMP_L
  7.         MOVWF   POSIC_L
  8.     BCF         STATUS,C
  9.         RRF     POSIC_H,F
  10.         RRF     POSIC_L,F
  11.     BCF         STATUS,C
  12.         RLF     TEMP_L,F
  13.         RLF     TEMP_H,F
  14.     BCF         STATUS,C
  15.         RLF     TEMP_L,F
  16.         RLF     TEMP_H,W
  17.     MOVWF   TEMP_L
  18.     CLRF    TEMP_H
  19.     MOVF    TEMP_L,W
  20.     SUBWF   POSIC_L
  21.     MOVF   TEMP_H,W
  22.     BTFSS   STATUS,C
  23.     INCFSZ  TEMP_H,W
  24.     SUBWF   POSIC_H
  25.         MOVLW   0x1F
  26.         ADDWF   POSIC_L,F
  27.         BTFSC   STATUS,C
  28.         INCF    POSIC_H,F
  29.         RETURN

27 ciclos aproximadamente. y lo unico que noto es la diferencia en el resultado, segun algunas entradas el decimal cambia el valor, en algunos numeros que lo probe resulta como que le suma 1 al resultado comparandolo con el primer codigo,
aun asi mucho mas rapido. Se opdria mejorar aun mas:
No usar 2 TEMP_x ya que un rotacion mas a POSIC y guardarlo en W + ANDLW 0xF0 + guardar en un TEMP + SWAP (en ves de MOVF para la resta) y resta de 16 - 8 y no 16 -  16bits como esta realizado. Haria mas corto el programa y utilizaria 1 solo registro temporal.

Asi:

Código: ASM
  1. POSICION4
  2.     BCF         STATUS,C        ; Division por 2
  3.     RRF         ADRESH,W
  4.     MOVWF       POSIC_H
  5.     RRF         ADRESL,W
  6.     MOVWF       POSIC_L
  7.     RRF         POSIC_H,W        ; Divido nuevamente por 2, asi poner esos 2 bits del byteH en el byteL pero uso como destino W asi no sobreescribo nada
  8.     RRF         POSIC_L,W
  9.     ANDLW       0xF0                ;Tomo nibble alto del byteL (ADC/64) y guardo en registro temporal, queda en el parte alta
  10.     MOVWF       TEMP
  11.     SWAPF       TEMP,W            ; Lo paso al nibble bajo para que sea correcto antes de restar
  12.     SUBWF       POSIC_L
  13.     BTFSS       STATUS,C          ; Si la resta da 0 le resto uno al byteH
  14.     DECF        POSIC_H,F
  15.     MOVLW       0x1F                ; Sumo 31
  16.     ADDWF       POSIC_L,F
  17.     BTFSC       STATUS,C
  18.     INCF        POSIC_H,F
  19.     RETURN

17/19 ciclos, 1 solo registro temporal, 2 registros de salida

Tendras que ver cuanto es el error maximo que se comete por haber realizado tantos calculos y la sustitucion del 1023 por el 1024 , aunque no deberia ser MUY grande o lo importante creo que seria el valor maximo y minimo,
el minimo es de 31 (0x1F)
el maximo es de 526 (0x20E) para los 2 primeros codigos y 527 (0x20F) para este ultimo

PD: Jamas pense que esa funcion podria llegar a hacerse de 17/19 ciclos.
« Última modificación: 23 de Marzo de 2015, 04:48:32 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #11 en: 23 de Marzo de 2015, 05:03:04 »
 ((:-)) ((:-)) ((:-)) ((:-)) ((:-)) ((:-)) ((:-))
Ya tengo curro para lo que resta de semana para poder asimilar todo lo escrito.

MUCHAS GRACIAS KILLERJC
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Dudas con operacion aritmética
« Respuesta #12 en: 23 de Marzo de 2015, 10:11:50 »
Perdon Miguel ahora que reviso algo estuve haciendo mal.

Es imposible que de 526/527 como maximo cuando el maximo deberia ser 124+31 = 155

Algo hice muy mal, luego lo reviso cuando tenga mas tiempo

EDIT:

Ya se cual fue mi error... me base en un ADC de 10 bits (me equivoque al ver los int 16 de la formula), cuando en realidad la formula esta realizada para un ADC de 8 bits, es correcto el resultado si hubiera un valor de 10bits ahi, pero lo que importa es que cumpla exactamente con el valor del AD
Si el ADC es de 8 bits, se resume a:

Código: ASM
  1. POSICION5
  2.     BCF         STATUS,C        ; Division por 2
  3.     RRF         ADRES,W
  4.     MOVWF       POSIC
  5.     RRF         POSIC,W
  6.     ANDLW       0x30                ; Al dividirlo por 64 solo me importan los 2 bits mas significantes
  7.     MOVWF       TEMP
  8.     SWAPF       TEMP,W            ; Lo paso al nibble bajo para que sea correcto antes de restar
  9.     SUBWF       POSIC,F
  10.     MOVLW       0x1F                ; Sumo 31
  11.     ADDWF       POSIC,F
  12.     RETURN

10 ciclos, dando efectivamente como maximo 0x9B = 155 , con una entrada de 255
Ni siquiera vale la pena el llamado a la subrutina. 4 ciclos de los 10
Mas sorprendido aun, 10 intrucciones para hacer una multiplicacion + una division + una suma
« Última modificación: 23 de Marzo de 2015, 10:36:03 por KILLERJC »

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Dudas con operacion aritmética
« Respuesta #13 en: 23 de Marzo de 2015, 15:33:11 »
Gracias de nuevo, pero voy a intentar trabajar con los 10bits de resolución.

Saludos!
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Dudas con operacion aritmética
« Respuesta #14 en: 23 de Marzo de 2015, 18:21:39 »
Entonces se deberia de modificar la ecuacion a , hay un par de cambios con eso...

31 + (int16)((int16)(ValorADC * 124) / 1024

EDIT:

Es tan asurdo que si queres hacer este cambio solo necesitas cambiar 2 cosas, justificado izquierdo y usar solo el ADRESH xD y el codigo de 8 bits funciona perfecto
« Última modificación: 23 de Marzo de 2015, 19:40:41 por KILLERJC »