Si, por supuesto que hay una logica detras todos los programas que pase. Todo parte de funcion matematica que pasaste, buscando distintas combinaciones.
Como ves en mis primeros programas podrias dividir el programa en 3 partes, multiplicacion por 31 , division por 64 y luego la suma (en el ultimo tambien pero no tan explicito), luego le buscamos un poco mas la vuelta para generar otra ecuacion, que fue la de reemplazar el 31 por (32 -1) en la formula y que es equivalente. Asi no era necesario multiplicar, sino solamente dividir por numeros potencia de 2. Incluso en el comentario de mi primer programa puse algunas cosas que se me ocurrieron:
; Podia hacerlo de 4 formas a la multiplicacion:
; - Sumar 31 veces el resultado del ADC (31 sumas de 16bits )
; - Sumar 31 por cada unidad del resultado del ADC (x sumas de 16 bits)
; - 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 )
; - Sumar las rotaciones de cada bit en 1 del multiplicador - Elegi esta ultima por ser la mas corta en programa aunque lleve un par de ciclos mas (4 sumas de 16bits + rotacion)
Luego se me ocurrio lo de hacer el (32-1) y ahi cambio y se simplifico mucho mas
La explico como funcionan o como es que llegas a esas operaciones...
Tanto para 8 bits de ADC (este ultimo era para la funcion que es 124/256 o 31/64 ojo) como para 10 bits ( este te la explico para cuando es 124/1024 = 31/256 =
8bits ADC:Formula utilizada:
31 + (ADC * 124 ) / 256 (8 bits)
Esta formula como ya explique se puede escribir como 31 + ADC/2 - ADC/64
Tomando el 31 como (32 -1) , aplicando la propiedad distributiva y simplificando nuevamente, hasta aqui solo el manejo de simples ecuaciones.
ADC = xxaa aaan (Resultado del ADC)
ADC/2 = 0xxa aaaa (Valor a conseguir)
ADC/64 =0000 00xx (Valor a conseguir)
Lo primero que hago es rotar a la derecha ( dividir por 2) y guardo es decir ya tengo mi ADC/2 guardado, luego tengo que restarle ADC/64 si observas yo denote a los 2 bits mas significativos como
XX que es lo unico que "sobrevive" a esa division
POSIC= ADC/2
Si roto una ves mas ADC/2 (sin importar el carry) este me quedaria: u0xx aaaa ( u de indefinido segun el carry anterior, podria haberlo puesto a 0, es una instruccion mas y sin sentido ya que luego le hago un AND a ese valor)
Luego una AND con 0011 0000 quedandome 00xx 0000 y guardo en TEMP .
TEMP = ADC/64 * 16
Cuando voy a restar, realizo el cambio de nibble W = 0000 00xx = ADC/64 y resto.
POSIC = ADC/2 - ADC/64
Esto jamas me va a dar negativo por que si tengo cualquiera de los bits significativos en 1, ADC/2 va a ser mucho mayor que ADC/64 por eso quite la parte donde pregunto por el carry en la resta.
Luego sumo 31 o que es igual a 0x1F
POSIC = 31 + ADC/2 - ADC /64
Tampoco pregunto por si hay carry debido a 2 cosas, suponiendo el peor de los casos de ADC = 1111 1111 , al rotarlo queda 0111 1111 , ademas se le resta 3 y le tendrias que sumar casi 128 para que se produzca un overflow. Asi que jamas va a suceder.
10 bits ADC:Funcion ( sigo manteniendo el maximo de 155 )
El mismo caso de antes, simplifico , tomo 31 como 32 -1 , distribuyo y simplifico nuevamente
31 + ADC * 124 / 1024 = 31 + ADC/8 - ADC/256
= 31 + ADC * 2
-3 - ADC *2
-8Usando
justificado derecha como veniamos haciendo quedaria:
ADCH = 0000 00xx (Resultado del ADC)
ADCL = aaaa annn (Resultado del ADC)
ADC/8 = 0000 0000 0xxa aaaa (Valor a conseguir)
ADC/256 = 0000 0000 0000 00xx (Valor a conseguir)
Si observas con el caso anterior la parte baja ADCL es igual que en el caso de 8 bits a pesar que cambian los divisores. Y solo trabajariamos con 8 bits
Cosas interesantes a notar. ADC/256 = ADCH (1 instrucciones) lo cual es super simple de sacar , pero para llegar a ADC/8 tengo que rotar 3 veces (7 instrucciones ya que son de 16bits 2 rotaciones), los bits marcados con nnn no "sobreviven"
Para simplificar se me ocurrio usar el
justificado izquierda y observo que solo la parte alta es de mi interes, nuevamente denoto como
nnn como los bits que no me interesan o que serian eliminados por la operacion
ADCHji = xxaa aaan
ADCLji = nn00 0000
ADCHji/2 = 0xxa aaaa ( Lo mismo que ADC/8 del otro justificado, pero ahora con una sola rotacion - 3 instrucciones, consegui el mismo valor pero con menos instrucciones )
ADCHji/4 = u0xx aaaa ( Igual que antes hago una AND con 0x30 y luego un SWAP antes de restar, equivalente a ADC/256 , este ya no es tan facil como antes que era ADCH sino que volvemos a lo mismo que hice con 8 bits - 3 instrucciones )
Aprovecho el justificado para que los bits esten en otro lugar y tratar de rotar lo menos posible.
Luego hago lo mismo sumo 31 nuevamente, se aplica todo lo demas siempre 0xxa aaaa va a ser mayor que 0000 00xx , por lo tanto no hay carry en la resta. Y tampoco va a excederse de 8 bits por que deberia sumarle en el peor de los casos un numero mayor a 128. Ademas seria imposible ya que el maximo dado por la ecuacion se encuentra en 155 ( 8 bits )
La ultima funcion esta bastante resumida. Si observas uno de los post que puse, cuando llegue con esta idea comenze rotando y necesitando cerca de 27 ciclos, luego con esta explicacion o rebuscado logre reducirlo aun mas
¿no es mas fácil por ejemplo sumar 20 + 20 que dividir 20 entre dos para después sumarle 30?
No entendi, podrias explicarlo con un ejemplo o una formula ?
EDIT:
Tu ejemplo pierde forma cuando supones esto:
x1 = A + A = 2A
y la otra es:
x2 = A/2 +30
Si A = 40,y uso esa misma logica : x1 = 80 y x2= 50
Para en el unico punto que se intersectan es con A = 20
x1 = x2
2A = A/2 +30
2A - A/2 = 30
3A/2 = 30
A = 30 * 2 / 3
A = 20
En fin no es la misma ecuacion. Y ya no se a donde te dirigias con esa pregunta...
Dio la suerte que esta funcion sea algo simple
Con respecto a los valores yo
DEBO sumar 31, en el codigo que estamos haciendo te recuerdo la formula:
Posicion_Servo = 31 + (ValorADC * 124) / 256);
Lo unico rebuscado es la forma de multipicar y dividir aprvechandose que se esta en binario y con registros de 8 bits, la suma se hace normalmente.
Y en fin espero demostrar que no es/fue cuestion de prueba y error. O valores al azar.
Y que te sea util xD