Autor Tema: variable float a BCD  (Leído 6838 veces)

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

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
variable float a BCD
« en: 31 de Mayo de 2019, 08:52:02 »
saludos amigo... en esta ocacion vengo a pedirles algo de información y es la siguiente, supongan que se tiene una variable de tipo FLOAT y se desea graficar eso en un 7 segmentos, entonces como se pasa eso a BCD, aclaro las rutinas BCD las conozco y se usarlas, lo que desconozco, es como se encuentra codificado en binario dentro de la variable FLOAT el punto decimal y los los valores a la derecha del punto... si alguien puede ayudar y muchas gracias... 

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:variable float a BCD
« Respuesta #1 en: 31 de Mayo de 2019, 10:09:29 »
Transforma float a entero y de entero a BCD.

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #2 en: 31 de Mayo de 2019, 11:31:27 »
como?.. multiplicando?

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:variable float a BCD
« Respuesta #3 en: 31 de Mayo de 2019, 12:25:43 »
Depende de la aplicación. Tendrás que convertir float a int:
  float fnumber = 25.36;
  int number = (int) fnumber;

Otra manera fácil es hacer un sprintf() y convertir las cifras en BCD.

Si quieres investigar los floats aquí puedes hacerlo:
AN575. IEEE 754 Compliant Floating Point Routines
http://ww1.microchip.com/downloads/en/appnotes/00575.pdf

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #4 en: 31 de Mayo de 2019, 12:36:07 »
Depende de la aplicación. Tendrás que convertir float a int:
  float fnumber = 25.36;
  int number = (int) fnumber;

Otra manera fácil es hacer un sprintf() y convertir las cifras en BCD.

Si quieres investigar los floats aquí puedes hacerlo:
AN575. IEEE 754 Compliant Floating Point Routines
http://ww1.microchip.com/downloads/en/appnotes/00575.pdf


intente con sprintf() pero me da error me dice q no puedo acceder a esta función en mi versión FREE de xc8...

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:variable float a BCD
« Respuesta #5 en: 31 de Mayo de 2019, 12:47:13 »
#include <stdio.h>

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #6 en: 31 de Mayo de 2019, 13:03:38 »
multiples errores....


C:\Program Files (x86)\Microchip\xc8\v1.45\sources\common\doprnt.c:1229: warning: (373) implicit signed to unsigned conversion
C:\Program Files (x86)\Microchip\xc8\v1.45\sources\common\doprnt.c:1232: warning: (373) implicit signed to unsigned conversion
output.c:23: warning: (520) function "_BCD" is never called
output.c:59: warning: (520) function "_FORMAT" is never called
output.c:65: warning: (520) function "_PRINT_DATO" is never called
:0: error: (1347) can't find 0x45 words (0x45 withtotal) for psect "text8" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x42 words (0x42 withtotal) for psect "text13" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x3B words (0x3b withtotal) for psect "text20" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x38 words (0x38 withtotal) for psect "maintext" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x34 words (0x34 withtotal) for psect "text21" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x28 words (0x28 withtotal) for psect "stringtext1" in class "STRCODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x28 words (0x28 withtotal) for psect "text12" in class "CODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x27 words (0x27 withtotal) for psect "stringtext2" in class "STRCODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x27 words (0x27 withtotal) for psect "stringtext3" in class "STRCODE" (largest unused contiguous range 0x25)
:0: error: (1347) can't find 0x1C words (0x1c withtotal) for psect "text6" in class "CODE" (largest unused contiguous range 0x10)
:0: error: (1347) can't find 0x19 words (0x19 withtotal) for psect "text1" in class "CODE" (largest unused contiguous range 0x10)
:0: error: (1347) can't find 0x16 words (0x16 withtotal) for psect "text24" in class "CODE" (largest unused contiguous range 0x10)
:0: error: (1347) can't find 0x14 words (0x14 withtotal) for psect "text25" in class "CODE" (largest unused contiguous range 0x10)
:0: error: (1347) can't find 0x8 words (0x8 withtotal) for psect "idataBANK1" in class "CODE" (largest unused contiguous range 0x7)
:0: error: (1347) can't find 0x8 words (0x8 withtotal) for psect "text19" in class "CODE" (largest unused contiguous range 0x7)
:0: error: (1347) can't find 0x6 words (0x6 withtotal) for psect "inittext" in class "CODE" (largest unused contiguous range 0x2)
:0: error: (1347) can't find 0x6 words (0x6 withtotal) for psect "clrtext" in class "CODE" (largest unused contiguous range 0x2)
(908) exit status = 1
nbproject/Makefile-default.mk:211: recipe for target 'dist/default/production/punta2.0.X.production.hex' failed
make[2]: Leaving directory 'C:/Users/mak_p/Desktop/punta logica2.0/punta2.0.X'
nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
make[1]: Leaving directory 'C:/Users/mak_p/Desktop/punta logica2.0/punta2.0.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
make[2]: *** [dist/default/production/punta2.0.X.production.hex] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

BUILD FAILED (exit value 2, total time: 24s)

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #7 en: 31 de Mayo de 2019, 13:06:27 »
Depende de la aplicación. Tendrás que convertir float a int:
  float fnumber = 25.36;
  int number = (int) fnumber;



esta función la probe pero de echo quita por completo el 0.36 del numero 25.36, cierto?o hice algo mal?... si es asi que elimina los decimales no me sirve de echo debo imprimir los decimales en el 7 segmentos... 

Desconectado Robert76

  • PIC24F
  • *****
  • Mensajes: 577
Re:variable float a BCD
« Respuesta #8 en: 31 de Mayo de 2019, 15:12:54 »
Entonces multiplica los números por 100, si todos poseen dos decimales, antes de procesar.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:variable float a BCD
« Respuesta #9 en: 31 de Mayo de 2019, 17:42:23 »
Si el número tiene decimales variables, puedes multiplicar por 10 varias veces hasta que valga de 1000 a 9999
El punto decimal lo pones en una de las cifras dependiendo de las veces que multiplicaste por 10.

Hay mucho trucos, depende de lo que quieras hacer.


Respecto a los errores, te voy a dar un consejo que vale un millón:

Regla de oro número 1 para programar:
1. Haz una función sencilla, con pocas líneas, más de 10  son muchas.
2. Pruébala hasta que no tenga errores de ningún tipo.
3. Añade más líneas y vuelve al punto 2

Saludos.

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #10 en: 01 de Junio de 2019, 14:54:05 »
Si el número tiene decimales variables, puedes multiplicar por 10 varias veces hasta que valga de 1000 a 9999
El punto decimal lo pones en una de las cifras dependiendo de las veces que multiplicaste por 10.

Hay mucho trucos, depende de lo que quieras hacer.


Respecto a los errores, te voy a dar un consejo que vale un millón:

Regla de oro número 1 para programar:
1. Haz una función sencilla, con pocas líneas, más de 10  son muchas.
2. Pruébala hasta que no tenga errores de ningún tipo.
3. Añade más líneas y vuelve al punto 2

Saludos.


si bueno los errores solo salen al poner la linea sprintf(),...

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #11 en: 01 de Junio de 2019, 15:02:03 »
Entonces multiplica los números por 100, si todos poseen dos decimales, antes de procesar.
yo uso en estos momentos esa técnica yo multiplico el resultado del ADC por 300 y divido por 1023 para darle formato de 0 a 300 siendo el ultimo dígito lo q va despues del punto decimal... luego tomo ese numero y hago el BCD y asi lo estoy haciendo de hace un tiempo el problema radica en que al usar variable de 32bits para hacer esa multiplicación estoy usando muchísima memoria del pic casi 10% de un pic con 7k   de memoria eso sumado a la rutina BCD llega a ocupar 18%... por eso buscaba un método más eficiente pues no me alcaza la memoria para el resto del proyecto.... 

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:variable float a BCD
« Respuesta #12 en: 01 de Junio de 2019, 17:16:37 »
Creo que Lo estas pensando mostrar en 5 displays por lo que parece (ya que queres 2 digitos despues de la coma)... entonces.... porque complicarse con flotantes? Porque no usar enteros con un poquito de error tal ves ?

En ves de dividirlo... Solo multipliquemos y dividamos rotando....


Con esto lo logras (cualquiera de los 2):

Código: C
  1. ResultadoEntero = (lecturaADC*29) + ((lecturaADC*19)>>6);  //o
  2. ResultadoEntero = (lecturaADC*30) - ((lecturaADC*45)>>6);

Obviamente esto te va a dar un resultado donde los 5 digitos enteros sean tus valores. Los 3 primeros tus digitos son los de ANTES de la coma, y los 2 que le siguen los que estan despues de la coma.
Algunos valores:

Código: C
  1. Tu formula = lecturaADC *300 /1024
(Aclaro que modifique el 1023 por 1024 ya que me permite simplificar el numero)

Código: [Seleccionar]
ADC   Tuformula      MiFormulaResta       MiFormulaSuma
1        0.2929          30                        29
10      2.929           293                        292
100    29.296         2930                      2929
500    146.484       14649                    14648
1023  299.707        29971                   29970

Pasarlo a BCD deberia ser muy sencillo teniendo esto ya. El algoritmo de BCD si tu problema es el espacio, no lo hagas con divisiones, hacelo con sucesivas restas, y va a ocupar mucho menos. Y observa que con trabajar con numeros enteros de 16 bits sin signo es suficiente incluso al multiplicarlos. 4 for y estaria realizado :P


Algo asi:

Código: C
  1. entero = Valor que te dio la formula anterior;  
  2.  
  3.   for(decmil=0;entero>=10000; entero-=10000, decmil++);
  4.   for(mil=0;entero>=1000; entero-=1000, mil++);
  5.   for(cien=0;entero>=100; entero-=100, cien++);
  6.   for(diez=0;entero>=10; entero-=10, diez++);
  7.   unidad = entero;


Me ocupa 191(suma)/196(resta) words en un PIC16 (19% de PIC16F84A que posee 1.75KB), un programita con solo eso, si el tuyo posee 7KB entonces deberia ocupar un 5%.... dependiendo del PIC es el tamaño que va a quedar. Sino la simple es cambiar el micro, si ya tenes problemas con esta cantidad de codigo.

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

Por si te interesa en como llegue a esos numeros de arriba, fue asi...
Tu idea es que te de un numero con 2 lugares luego de la coma y 3 antes, por lo tanto yo no quiero la coma, entonces debo multiplicarlo por 100.
Pero es lo mismo que si antes hacia:

\frac{lectura*300*100}{1024} = \frac{lectura*30000}{1024}

Pero.... observo que 30000 / 1024 es 29 con algo... por lo tanto puedo tomar 2 formas de realizarlo..... Ir por el 30 o por el 29

Si voy por el 30, me queda que 1024 * 30 = 30720, por lo que me quedan 720

\frac{lectura*(30720 - 720)}{1024} = \frac{lectura*30720}{1024}-\frac{lectura*720}{1024}

Pero simplificando....

\frac{lectura*720}{1024} = \frac{lectura*45}{64}

Me queda:

lectura*30-\frac{lectura*45}{64}

La otra forma es ir por el 29 y sumar... 29*1024= 29696 por lo que me falta 304

\frac{lectura*(29696 + 304)}{1024} = \frac{lectura*29696}{1024}+\frac{lectura*304}{1024}

Simplificando..

\frac{lectura*304}{1024} = \frac{lectura*19}{64}

Me queda...

lectura*29 + \frac{lectura*19}{64}

Codigo Final:

Código: C
  1. entero = (lecturaADC*29) + ((lecturaADC*19)>>6);
  2.  
  3.   for(decmil=0;entero>=10000; entero-=10000, decmil++);
  4.   for(mil=0;entero>=1000; entero-=1000, mil++);
  5.   for(cien=0;entero>=100; entero-=100, cien++);
  6.   for(diez=0;entero>=10; entero-=10, diez++);
  7.   unidad = entero;

PD: Observaras que al tener 1024 en la formula, ese es el error que comentaba, ya no vas a tener mas 300.00 como maximo sino 299.70, pero va a ser 0 si es que la lectura es 0.
Es decir el error va creciendo a medida que el la lectura llega a 1023, donde es maximo y es de 0.3 (0.29 para la resta), se podria reducir el error a costa de mas codigo aunque no parece tener demasiado sentido. PERO si queres que se reduzca, se puede hacer un pequeño cambio en el codigo y reducir el error a 0.1. Y no vamos a dividir el algoritmo de BCD

Maximo error en los valores 340,681 y 1022, donde el error es de 0.1 aproximadamente. Pero tu inicio es 00000, y tu final es 30000 si o si. (Recorda que tenes la coma 2 lugares desde el digito mas a la derecha)
Código: C
  1. for(decmil=0;lecturaADC>=341; lecturaADC-=341, decmil++);
  2.  
  3.   entero = (lecturaADC*29) + ((lecturaADC*19)>>6);
  4.  
  5.   for(mil=0;entero>=1000; entero-=1000, mil++);
  6.   for(cien=0;entero>=100; entero-=100, cien++);
  7.   for(diez=0;entero>=10; entero-=10, diez++);
  8.   unidad = entero;

PD2: Crear una multiplicación con sumas sucesivas genera muy poca ganancia de espacio, y es una perdida de tiempo.
« Última modificación: 02 de Junio de 2019, 10:48:48 por KILLERJC »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Re:variable float a BCD
« Respuesta #13 en: 02 de Junio de 2019, 05:55:41 »
el problema radica en que al usar variable de 32bits para hacer esa multiplicación estoy usando muchísima memoria del pic casi 10% de un pic con 7k   de memoria eso sumado a la rutina BCD llega a ocupar 18%... por eso buscaba un método más eficiente pues no me alcaza la memoria para el resto del proyecto....

Entonces no utilices sprintf porque ocupa mucho.


Otra fórmula que puedes utilizar:

  Resultado = ADC * 300 / 1024 = ADC * 75 / 256 = ADC * (25/4) * (3/64) = (((ADC * 25)>>2) * 3)>>6

Que se puede simplificar con una sola multiplicación de números enteros de 16bit sin signo:

  Resultado = ((unsigned int)ADC * 25)>>1
  Resultado = (Resultado + (Resultado >> 1) + 32) >> 6

El +32 es para redondear.
« Última modificación: 02 de Junio de 2019, 06:05:11 por Picuino »

Desconectado mak_paint

  • PIC12
  • **
  • Mensajes: 62
Re:variable float a BCD
« Respuesta #14 en: 02 de Junio de 2019, 13:35:45 »
excelentes sugerencias muchas gracia a ambos, les aclaro un poco los detalles por q no me explique bien:

Creo que Lo estas pensando mostrar en 5 displays por lo que parece (ya que queres 2 digitos despues de la coma)... entonces.... porque complicarse con flotantes? Porque no usar enteros con un poquito de error tal ves ?



lo que deseo son dos enteros y un decimal después de la coma (quizás pueda poner 2)... fijate si mi resultado ADC es digamos 512
hago esto: 512*300/1023=
                153.600/1023=
                150,14
como verás para manejar esos numeros debo usar una variable de 32 bit... luego sacó el BCD de esos numero y al imprimir en el display lo que hago es tomar los primeros dos dígitos como entero y el tercero como decimal, así que 150,14 lo muestro así: 15,0 con eso me basta...otro
ADC=800
        800*300/1024=234,60 yo muestro 23,4...
« Última modificación: 02 de Junio de 2019, 15:01:03 por mak_paint »