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:
POSICION2
MOVLW 0x05
MOVWF TEMP
MOVF ADRESH,W
MOVWF TEMP_H
MOVWF POSIC_H
MOVF ADRESL,W
MOVWF TEMP_L
MOVWF POSIC_L
MULT2
BCF STATUS,C ;Multiplicacion * 32
RLF POSIC_L,F
RLF POSIC_H,F
DECFSZ TEMP,F
GOTO MULT2
MOVF TEMP_L,W ; Comienzo del restado POSIC = POSIC - TEMP (16 bits ambos )
SUBWF POSIC_L
MOVF TEMP_H,W
BTFSS STATUS,C
INCFSZ TEMP_H,W
SUBWF POSIC_H ; Fin del restado
MOVLW 0x06 ;Division
MOVWF TEMP
DIV2
BCF STATUS,C
RRF POSIC_H,F
RRF POSIC_L,F
DECFSZ TEMP,F
GOTO DIV2
MOVLW 0x1F ;Suma
ADDWF POSIC_L,F
BTFSC STATUS,C
INCF POSIC_H,F
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.
POSICION3
MOVF ADRESH,W
MOVWF TEMP_H
MOVWF POSIC_H
MOVF ADRESL,W
MOVWF TEMP_L
MOVWF POSIC_L
BCF STATUS,C
RRF POSIC_H,F
RRF POSIC_L,F
BCF STATUS,C
RLF TEMP_L,F
RLF TEMP_H,F
BCF STATUS,C
RLF TEMP_L,F
RLF TEMP_H,W
MOVWF TEMP_L
CLRF TEMP_H
MOVF TEMP_L,W
SUBWF POSIC_L
MOVF TEMP_H,W
BTFSS STATUS,C
INCFSZ TEMP_H,W
SUBWF POSIC_H
MOVLW 0x1F
ADDWF POSIC_L,F
BTFSC STATUS,C
INCF POSIC_H,F
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:
POSICION4
BCF STATUS,C ; Division por 2
RRF ADRESH,W
MOVWF POSIC_H
RRF ADRESL,W
MOVWF POSIC_L
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
RRF POSIC_L,W
ANDLW 0xF0 ;Tomo nibble alto del byteL (ADC/64) y guardo en registro temporal, queda en el parte alta
MOVWF TEMP
SWAPF TEMP,W ; Lo paso al nibble bajo para que sea correcto antes de restar
SUBWF POSIC_L
BTFSS STATUS,C ; Si la resta da 0 le resto uno al byteH
DECF POSIC_H,F
MOVLW 0x1F ; Sumo 31
ADDWF POSIC_L,F
BTFSC STATUS,C
INCF POSIC_H,F
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.