Autor Tema: Problema en una variable entero de 16 bits con signo.  (Leído 3359 veces)

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

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Problema en una variable entero de 16 bits con signo.
« en: 04 de Noviembre de 2019, 19:08:55 »
Tengo un programa con una variable signed int16 de tipo global. 

  La uso en una función donde con un pulsador, la variable se incrementa en uno.
  Otro pulsador le resta uno a la misma variable. Va mostrando su valor en una pantalla.

  Todo funciona bien.  Voy incrementando y en pantalla veo 1,2,3,4, etc... 

  Si resto, en pantalla veo, 3,2,1,0,-1,-2,-3..    y así sucesivamente.  Todo correcto.

 El problema viene cuando regreso al main y vuelvo a llamar a la misma función.

  Si la dejé con un valor positivo , al volver a la función conserva intacto el valor.

  Pero si la dejé con un valor negativo , regresa con un 0. Se pierde el valor negativo que tenia.


   Alguna sugerencia.

  Es CCS y un pic18f4550.


Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Problema en una variable entero de 16 bits con signo.
« Respuesta #1 en: 04 de Noviembre de 2019, 20:52:48 »
Tenes algun codigo simple como para verlo?

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema en una variable entero de 16 bits con signo.
« Respuesta #2 en: 05 de Noviembre de 2019, 04:54:18 »
Tenes algun codigo simple como para verlo?

Es un fragmento de un código bastante grande de un compañero del trabajo.  Lo de los pulsadores en verdad lo metí para probar. 

  De todas formas creo que ya he visto lo que pasa, lo verificaré luego cuando llegue.

  La variable la graba en la eeprom interna al terminar la función y al regresar a la función la vuelve a leer de la eeprom interna. Hasta aquí no debería haber problema,  (es un menú de configuración)

 pero lo que me mosquea es que en la rutina de lectura, una vez leída la variable desde dos posiciones y construida con:
Código: C
  1. variable = make16(read_eeprom(27),read_eeprom(28));
  Luego hace esto: 
Código: C
  1. Variable = variable / 10;
  2.  Variable_dec = variable % 10;

  Parece como si descompone la cifra en dos para sacar una mantisa y ahorrarse un float , a saber, luego le preguntaré.

  Para grabar hace lo mismo a la inversa.
Código: C
  1. Variable = (variable * 10) + variable_dec;
  Y luego graba con
Código: C
  1. eeprom(27,make8(variable,1));
  2. eeprom(28,make8(variable,0));
Algo debe cascar ahí con un número negativo seguro pero lo dejé anoche ahí... 
« Última modificación: 05 de Noviembre de 2019, 05:51:52 por remi04 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Problema en una variable entero de 16 bits con signo.
« Respuesta #3 en: 05 de Noviembre de 2019, 06:40:56 »
Si claramente ahi deberia estar el error... Ademas espero que todas las variables sean con signo.

Código: C
  1. variable = make16(read_eeprom(27),read_eeprom(28));

El make16 hace esto (segun manual de CCS):

Código: C
  1. i16 = (int16)(varhigh&0xff)*0x100+(varlow&0xff)

Lo que me preocupa es ese cast a int16, que sin nada se asume unsigned, segun el manual de CCS)

Citar
Parece como si descompone la cifra en dos para sacar una mantisa y ahorrarse un float , a saber, luego le preguntaré.
Estas trabajando con enteros, lo unico que hace ahi es tratar de separar el numero para guardarlo (mostrarlo,etc), pero lo hace mal. Es como si tratara de separar las unidades de las decenas, pero un numero de 16 bits tiene muchos mas digitos.


Para mi lo mas simple va a ser crearle una union (para que no trabaje con punteros). Para que tu compañero lo pueda entender y manejarse, el tema es que luego va a necesitar cambiar donde lo use, pero con un Replace All, se ahorra el tema. Si tu compañero se maneja bien con punteros entonces todo lo que va a continuacion se simplifica mas.

Código: C
  1. struct myStruct {
  2.   int8 b1;
  3.   int8 b2;
  4. }
  5.  
  6. union myUnion {
  7.    signed int16 w
  8.    struct myStruct separado;
  9. }
  10.  
  11. union myUnion variable;

Entonces:

Código: C
  1. // Previo inicializamos variable antes de leer por cualquier cosa:
  2. variable.w = 0;
  3.  
  4. write_eeprom(27,variable.separado.b1);
  5. write_eeprom(28,variable.separado.b2);
  6.  
  7. variable.separado.b1 = read_eeprom(27);
  8. variable.separado.b2 = read_eeprom(28);

Y de usarlo completo los 16 bits, entonces usar variable.w

La pregunta ahora es.... Si planteo algo como separar la decena y la unidad, no creo que plantee mas de 99 y -99, Por lo tanto, ¿por que irse a un numero de 16 bits?

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema en una variable entero de 16 bits con signo.
« Respuesta #4 en: 05 de Noviembre de 2019, 10:06:15 »
Si claramente ahi deberia estar el error... Ademas espero que todas las variables sean con signo.

Código: C
  1. variable = make16(read_eeprom(27),read_eeprom(28));

El make16 hace esto (segun manual de CCS):

Código: C
  1. i16 = (int16)(varhigh&0xff)*0x100+(varlow&0xff)

Lo que me preocupa es ese cast a int16, que sin nada se asume unsigned, segun el manual de CCS)

Citar
Parece como si descompone la cifra en dos para sacar una mantisa y ahorrarse un float , a saber, luego le preguntaré.
Estas trabajando con enteros, lo unico que hace ahi es tratar de separar el numero para guardarlo (mostrarlo,etc), pero lo hace mal. Es como si tratara de separar las unidades de las decenas, pero un numero de 16 bits tiene muchos mas digitos.


Para mi lo mas simple va a ser crearle una union (para que no trabaje con punteros). Para que tu compañero lo pueda entender y manejarse, el tema es que luego va a necesitar cambiar donde lo use, pero con un Replace All, se ahorra el tema. Si tu compañero se maneja bien con punteros entonces todo lo que va a continuacion se simplifica mas.

Código: C
  1. struct myStruct {
  2.   int8 b1;
  3.   int8 b2;
  4. }
  5.  
  6. union myUnion {
  7.    signed int16 w
  8.    struct myStruct separado;
  9. }
  10.  
  11. union myUnion variable;

Entonces:

Código: C
  1. // Previo inicializamos variable antes de leer por cualquier cosa:
  2. variable.w = 0;
  3.  
  4. write_eeprom(27,variable.separado.b1);
  5. write_eeprom(28,variable.separado.b2);
  6.  
  7. variable.separado.b1 = read_eeprom(27);
  8. variable.separado.b2 = read_eeprom(28);

Y de usarlo completo los 16 bits, entonces usar variable.w

La pregunta ahora es.... Si planteo algo como separar la decena y la unidad, no creo que plantee mas de 99 y -99, Por lo tanto, ¿por que irse a un numero de 16 bits?

  Gracias Killer.

  Efectivamente lo que trataba era de separar la ultima cifra solamente, pero tratar el resto como otra cifra. Es decir, si por ejemplo la variable vale 14327, lo que él quería es quedarse con el 1432 por un lado y el 7 en otra variable y luego representarla por ejemplo haciendo  printf("El numero es: %Lu,%u",variable,variable_dec");   y que le aparezca que " El numero es 1432,7". por eso usa 16 bits

 Dice que siempre lo ha hecho así, pero es la primera vez que se le da el caso de necesitar usar negativos y claro, con números negativos eso no puede funcionarle por que cuando el programa fija por ejemplo un "-1" en la variable grande, si luego para guardarla tu la multiplicas por 10  (-1) * 10 = -10;  así sin problema.

   Pero cuando le añade esa mantisa, por ejemplo "7",  la operación que está haciendo es ((-1) * 10) + 7  = -3;

  Luego estaría grabando en la eeprom un -3.

  Cuando luego lee la eeprom y hace la division para separarlas de nuevo lo que hace es:

 (-3) / 10

y eso da -0,3, es decir, cero.

  Luego para la unidad separada hace (-3) % 10 = -3  y como esa variable no está signada, si no que es un entero normal de 8 bits lo que a esa variable se le asigna es 253.

  Por eso se le va a cero el valor grande cuando hace la rutina de grabación/lectura con una cifra negativa.

 Pues nada, si estoy en lo cierto a explicarselo y que lo rediseñe.

« Última modificación: 05 de Noviembre de 2019, 10:24:35 por remi04 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Problema en una variable entero de 16 bits con signo.
« Respuesta #5 en: 05 de Noviembre de 2019, 15:03:08 »
Lo que no comprendo es la decision de desarmar y volver a armar.

Ya que si esta usando el numero de 16bits para no complicarse la vida con la coma. Entonces porque no actuar sobre esa variable, y unicamente para mostrar separa el ultimo digito como hace, con eso deberia tener resuelto esa parte.

Y la otra es el guardado en la EEPROM (con el make16 especialmente), que no se si afectara.
« Última modificación: 05 de Noviembre de 2019, 15:41:08 por KILLERJC »