He probado la rutina de "recorre y suma 3" que propuso sander y parece que funciona para 8 bits.
Es decir, metiendo 255 en la entrada, la salida alta sale '00000010' (02 en BCD) y en la salida baja '01010101' (55 en BCD) juntos forman el 255.
Inentare modificarla para 24 bits.
Sin embargo aqui me sale otra duda: Los numeros en BCD de la salida, como se pueden pasar a un LCD?.
La rutina que os envie, directamente saca cada numero en ASCII pra apasarlo directamente al LCD, pero no se muy bien como lo consigue...
Buscando y buscando veo que este es un tema bastante recurrente y no me extrana.
Aunque parece facil pero el tema de las matematicas en los PIC es bastante complicado para mi.
Saludos
Antes que nada, debes de ENTENDER que está haciendo tú código, eso es una regla FUNDAMENTAL al momento de programar en ensamblador, si tú mismo no sabes como es que el código funciona, puedes imaginar que sucederá al momento de hacer algo más complejo...
Analiza el problema primero, usa papel y lápiz y razona el proceso que quieres hacer antes que sentarte a codificar o a buscar código "similar" a lo que necesitas...
Preguntate 1ro, ¿Que es el código BCD?, ¿Cual es la diferencia entre BCD y HEXADECIMAL?
Te la pongo resumida: El codigo BCD expresa en NIBBLES (4 bits) un número cuyo valor va de 0 a 9, tal que representan una numeración base 10 como la usamos los humanos.
BCD JAMAS puede valer más de 9 unidades, y al pasar su valor de 9, el nibble se hará 0 y se generara una acarreo BCD, 9 + 1 = 0 "y llevamos 1" <== Acarreo
Por el contrario, el código hexadecimal no es más que una REPRESENTACIÓN NUMÉRICA de un valor en binario, pero usando unidades o valores más entendibles para el ser humano.
El código hexadecimal, representa un NIBBLE (4 bits de datos), tal que posee 16 valores posibles: 2 a la 4 = 16, los cuales se representan así:
DEC BIN HEX BCD
0 0000 0 0000
1 0001 1 0001
2 0010 2 0010
3 0011 3 0011
4 0100 4 0100
5 0101 5 0101
6 0110 6 0110
7 0111 7 0111
8 1000 8 1000
9 1001 9 1001
10 1010 A 0001 0000
11 1011 B 0001 0001
12 1100 C 0001 0010
13 1101 D 0001 0011
14 1110 E 0001 0100
15 1111 F 0001 0101
Acá los números se representan del 0 al 9 como en el código BCD, pero a partir del número 10, se representan como LETRAS de la A a la F
Tal que el número 255 se puede representar así:
255 en decimal
11111111 en binario
0xFF en Hexadecimal
0010 0101 0101 en BCD
Los números hexadecimales como tal NO existen, es solo una manera simplificada de escribir (usando NIBBLES) un valor en binario puro, o sea, cuando nosotros leemos o escribimos valores, es mas fácil entender el número 240 como 0xF0 que si usaramos binario puro: 11110000
Sabiendo esto, y que el código BCD se expresa en NIBBLES, las operaciones que se hacen con ellos SIEMPRE ocupan 4 bits, y un byte, es capaz de guardar 2 digitos BCD.
Ahora bien, la rutina, que no entiendes como te funciona pero funciona, lo que hace para convertir un binario a BCD es lo siguiente:
Si el número binario es mayor a 9, se le suman 6 unidades ¿Por que?
Porque BCD solo puede usar 10 unidades (0 a 9) pero un nibble puede representar 16 valores, tal que:
si tuvieras el número 10 en binario (ocupando 1 byte) = 00001010
10 = 00001010 > 9?
Si, sumas 6 unidades:
10 + 6 = 00010000 <== BCD
00010000 es el valor en BCD, ocupando 2 nibbles, tal que si los separas tendrías: 0001 0000 lo cual significa: 1 decena, 0 unidades
Si te das cuenta, cada nibble representa una potencia de 10, es decir, el primer nibble representa las unidades y el segundo nibble las decenas...
Si tuvieras el # 100 en BCD seria: 0001 00000000 el número ocuparía 3 nibbles y necesitarias 2 bytes para guardar los 3 nibbles (Aunque el 4to nibble = 0)
0001 0000 0000
Centenas Decenas Unidades
Entonces lo que hace tu loop es ajustar cada nibble de cada byte en binario, a su equivalente en BCD sumando de 6 en 6 unidades cada vez que un nibble sea mayor a 9.
Sumar 6 unidades ES LO MISMO que rotar a la izquierda (LO CUAL EQUIVALE A MULTIPLICAR x 2) y sumarle 3.... (3 x 2 = 6) Aunque es lo mismo, me imagino que ese método ha de ser mas rápido que sumar 6 unidades...
Bien, ahora, debes de buscar en google lo que es el codigo ASCII, que no es mas que una serie de tablas, en donde cada letra y símbolo alfanumérico está cotejado con un valor en binario (Las computadoras entienden binario, no alfanumérico).
En las tablas ASCII, encontraras que el número 0, cuando es representado como un CARACTER, tiene un EQUIVALENTE NUMERICO = 48, es decir, cada que tu tecleas el caractér "0" en tu PC, el teclado envía el código 48 (en binario), cuando escribes "1" el teclado envía el código 49 y así para todas los números, las letras mayúsculas, las letras minúsculas, los simbolos !"#$%&/())= etc...
Lo que hace el programa que tienes, una vez que ha obtenido todos los NIBBLES BCD, es simplemente sumarles el ASCII # 48 para convertir el valor BCD en un código ASCII.
La pantalla alfanumérica que estás utilizando, recibe la información a desplegar en ASCII, es por eso que al enviar los datos al LCD, estos deberán estar convertidos en su código ASCII equivalente.
Solo que acá toca observar un tema:
La rutina que utilizas utiliza 1 variable de 1 byte por cada NIBBLE BCD generado, tal que las variables Tenk, Thou, Hund, Tens, Ones Representan:
Tenk: DECENAS de MILLAR
Thou: UNIDADES de MILLAR
Hund: CENTENAS
Tens: DECENAS
Ones: UNIDADES
Sin embargo, no es la manera más eficiente o elegante de hacerlo:
Una conversión binario a BCD te (puede) generar una combinación de nibble tal que por ejemplo, el numero 2159 quedaría convertido así:
0010 0001 0101 1001, lo cual guardado en una serie de variables, llamemosles digit_32 y digit_10 te quedaría así:
digit_32 = 00100001 <= 2 millares, 1 centena
digit_10 = 01011001 <= 5 decenas, 9 unidades...
En una rutina así, para convertir digit_32 y digit_10 a código ASCII se haría lo siguiente:
swapf digit_32,w ; Intercambio los nibbles MSB <=> LSB, ya que primero se envian los millares...
andlw 0x0F ; Enmascaro los bits de los millares, para eliminar los bits de las centenas...
addlw d'48' ; Al sumarle 48 al WORK, el número se ha convertido a un caracter ASCII!
movwf LCD_Value ; LCD_Value es el registro de SALIDA de la rutina Send_LCD
call Send_LCD ; Envio los millares a la pantalla LCD....
movf digit_32,w ; Ahora se enviaran las centenas, no es necesario intercambiar los nibbles
andlw 0x0F ; Enmascaro los bits de las CENTENAS, para eliminar los bits de los MILLARES.
addlw d'48' ; Al sumarle 48 al WORK, el número se ha convertido a un caracter ASCII!
movwf LCD_Value ; LCD_Value es el registro de SALIDA de la rutina Send_LCD
call Send_LCD ; Envio los millares a la pantalla LCD....
swapf digit_10,w ; Intercambio los nibbles MSB <=> LSB, ya que primero se envian las decenas
andlw 0x0F ; Enmascaro los bits de las decenas, para eliminar los bits de las unidades...
addlw d'48' ; Al sumarle 48 al WORK, el número se ha convertido a un caracter ASCII!
movwf LCD_Value ; LCD_Value es el registro de SALIDA de la rutina Send_LCD
call Send_LCD ; Envio los millares a la pantalla LCD....
movf digit_10,w ; Ahora se enviaran las unidades, no es necesario intercambiar los nibbles
andlw 0x0F ; Enmascaro los bits de las unidades, para eliminar los bits de las decenas
addlw d'48' ; Al sumarle 48 al WORK, el número se ha convertido a un caracter ASCII!
movwf LCD_Value ; LCD_Value es el registro de SALIDA de la rutina Send_LCD
call Send_LCD ; Envio los millares a la pantalla LCD....
Listo, eso sería todo, por favor toma en cuenta que una parte CRUCIAL en ensamblador, es DOCUMENTAR el código que haces.
Documentar NO es TRADUCIR los nemotécnicos o lo que estas haciendo: movf var,w ; Muevo la variable var a W (Si el lector NO es tonto, ya se sabe lo que hace movf)
Documentar es escribir en tus propias palabras, lo que ESTAS haciendo o PORQUE lo estas haciendo, tal que algún día, cuando necesites algún código para otro programa, y haya pasado el tiempo, te sea muy fácil saber que hace cada rutina, por que lo hace, cuales son sus variables de entrada, cuales las de salida etc...
Documentar, te ayuda a entender lo que estas haciendo e inclusive es una manera rápida y segura de poder encontrar algún bug durante la programación.
Documentar es un HABITO que a todos nos cuesta al principio, pero es la manera PROFESIONAL de hacerlo: Si algún día vendes un proyecto a una empresa, entregarle un archivo ASM sin documentar es como darles el HEX y dejarlos que se hagan pelotas en saber que demonios hace el programa que te COMPRARON!.
Saludos y ojala te sea de ayuda.