Autor Tema: Miembros de estructuras son imprimidos con errores después de guardarlos  (Leído 2649 veces)

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

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Hola a todos, estoy usando un PIC25FJ256GA106 para hacer varias cosas y una de esas cosas es un menú, en ese menú estoy configurando la hecha y hora leyendo los caracteres a través de un teclado alfanumérico para luego imprimirlos al mismo tiempo en una pantalla LCD, el proceso de leer y guardar los datos trabaja bien pero estoy teniendo algunos problemas en algunos campos imprimiendo los caracteres.

Los caracteres son guardados en la siguiente estructura:
 
Código: [Seleccionar]
typedef struct /* Estructura para almacenar la fecha */
{ /* y hora del dispositivo. La */
uint8_t ano[4]; /* estructura está pensada para */
uint8_t mes[2];
uint8_t dia[2];
uint8_t hora[2];
uint8_t minuto[2];
uint8_t segundo[2];
} tiempo;

La función para seleccionar el miembro de la estructura a usar es la siguiente

Código: [Seleccionar]
char* Alma_RTC(uint8_t numParam, uint8_t dato)/* Función para el almacenamiento*/
{ /* de los datos en las estructuras */
static uint8_t contDato = 0, temp = 1;/* correspondientes. */
char *exporta = 0;
if(temp != numParam) /* Se reinicia contDato si se cambia */
{ /* parámetro a llenar en la estructura*/
contDato = 0; /* para configurar el reloj del */
} /* sistema. */
switch(numParam) /* Llema el parámetro en función de la*/
{ /* función seleccionada. */
case 1:
{
if(contDato <= 3)
{
RTC.ano[contDato] = dato;
exporta = (char*) RTC.ano;
contDato++;
}
}
break;
case 2:
{
if(contDato <= 1)
{
RTC.mes[contDato] = dato;
exporta = (char*) RTC.mes;
contDato++;
}
}
break;
case 3:
{
if(contDato <= 1)
{
RTC.dia[contDato] = dato;
exporta = (char*) RTC.dia;
contDato++;
}
}
break;
case 4:
{
if(contDato <= 1)
{
RTC.hora[contDato] = dato;
exporta = (char*) RTC.hora;
contDato++;
}
}
break;
case 5:
{
if(contDato <= 1)
{
RTC.minuto[contDato] = dato;
exporta = (char*) RTC.minuto;
contDato++;
}
}
break;
case 6:
{
if(contDato <= 1)
{
RTC.segundo[contDato] = dato;
exporta = (char*) RTC.segundo;
contDato++;
}
}
break;
}
temp = numParam; /* Se asigna numParam a temp para
* comparar en la próxima entrada a la
* función. */
return exporta;
}
 

donde cada caso es para el miembro específico de la estructura, numParam almacena la posición del miembro a llenar y dato almacena el cacater (número) presionado.

la función que imprime el mensaje en el LCD es la siguiente

Código: [Seleccionar]
void Mensaje_Ent(char *mensaje) /* Función para imprimir el mensaje */
{ /* sin animaciones. */
while(*mensaje)
{
Envia_Com_RAM4b(*(mensaje++));
retardo_us(40);
}
}

Notar que la parte importante de Mensaje_Ent es el puntero el cual almacena el contenido del arreglo.

la función que almacena la data en los miembros está escrita como sigue
 
Código: [Seleccionar]
valor = Alma_RTC(contParam,boton);
Mensaje_Ent((char*) valor);

 
 
The function Mensaje_Ent was tested and worked very well with other type of data because I'm using it for print all the menu titles but in some cases -exactly the cases where I'm printing the content of the structure members- like the one shown after the ss: field in the attached image -Impresiones LCD- I wrote "99" since the array is the dimension 2 but it prints 99,, I don't know if the function is not seeing the EOF character or anything else is happening.

https://ibb.co/XtBtSRR

Si veo la memoria de datos el "99," está guardado en memoria como se ve en la siguiente memoria encerrado en un círculo azul

https://ibb.co/XtBtSRR
 
Puede alguien ayudarme a resolver este problema?.

Gracias de antemano por la ayuda.
« Última modificación: 11 de Marzo de 2020, 23:44:21 por vra »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Miembros de estructuras son imprimidos con errores después de guardarlos
« Respuesta #1 en: 12 de Marzo de 2020, 07:13:11 »
Bueno.....

Respecto al codigo, lo considero una muy mala implementacion. Generalmente lo ingresado en el teclado es para luego ser trabajado, mejor tenerlo como enteros y luego lo paso a strings cuando lo voy a mostrar.
Hacerlo con una estructura y luego direccionarlo como si se tratara como un array usando un switch case gigante y una funcion que admite un INDICE, es otro indicio que eso NO debía ser una estructura, sino un array de punteros.

Y finalmente:

Citar
I wrote "99" since the array is the dimension 2 but it prints 99,,

Y si,, es obvio el problema, para mostrar los datos utiliza esto:

Citar
while(*mensaje)

Donde espera el caracter nulo al final de una string. Pero si vos tenes 2 lugares para guardar caracteres, y los ocupas a los dos con '9' entonces no te queda lugar para el caracter nulo, siempre deberias tener 1 mas para el caracter nulo... Ejemplo "1234" en realidad ocupa 5 lugares de memoria, uno para cada caracter y uno para el caracter nulo.

Pero eso esta limitado por esa estructura que maneja chars, lo cual lo vuelvo a decir, si hubieran sido ints, no hubiera existido problemas, ya que al final antes de enviar lo convertis a string en un array un poco mas grande y lo envias.


PD: Las imagenes son las mismas al final.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Miembros de estructuras son imprimidos con errores después de guardarlos
« Respuesta #2 en: 13 de Marzo de 2020, 20:41:02 »
Bueno.....

Respecto al codigo, lo considero una muy mala implementacion. Generalmente lo ingresado en el teclado es para luego ser trabajado, mejor tenerlo como enteros y luego lo paso a strings cuando lo voy a mostrar.
Hacerlo con una estructura y luego direccionarlo como si se tratara como un array usando un switch case gigante y una funcion que admite un INDICE, es otro indicio que eso NO debía ser una estructura, sino un array de punteros.

Y finalmente:

Citar
I wrote "99" since the array is the dimension 2 but it prints 99,,

Y si,, es obvio el problema, para mostrar los datos utiliza esto:

Citar
while(*mensaje)

Donde espera el caracter nulo al final de una string. Pero si vos tenes 2 lugares para guardar caracteres, y los ocupas a los dos con '9' entonces no te queda lugar para el caracter nulo, siempre deberias tener 1 mas para el caracter nulo... Ejemplo "1234" en realidad ocupa 5 lugares de memoria, uno para cada caracter y uno para el caracter nulo.

Pero eso esta limitado por esa estructura que maneja chars, lo cual lo vuelvo a decir, si hubieran sido ints, no hubiera existido problemas, ya que al final antes de enviar lo convertis a string en un array un poco mas grande y lo envias.


PD: Las imagenes son las mismas al final.

Gracias por tus consejos, efectivamente el problema era por el caracter nulo.

Referente al tema de la implementación si, es de novato, me encuentro aprendiendo a programar con este proyecto y aún no se hacer muchas cosas, de hecho tengo problemas con la forma de manejar los punteros ya que aún me cuesta entenderlos totalmente.

En ese caso pondré atención a tu comentario sobre el amacenamiento como enteros y después convertirlo a strings.

En cuanto al switch-case gigante como dices, ese switch-case utiliza las opciones numeradas para manejar condiciones de borde de impresión y solo la opción "default" es la que se encarga de almacenar e imprimir ya que eestoy mostrando los datos en vivo mientras se están almacenando; se que está la función getc de stdio.h pero en lo poco que he leído aún no he encontrado como usarla con un tecladito alfanumérico de matriz (de los que venden para prototipos), cualquier otro consejo en este sentido es bienvenido.

Lo del arreglo de punteros aún no lo se manejar pero lo investigaré para mejorar mi implementación.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Miembros de estructuras son imprimidos con errores después de guardarlos
« Respuesta #3 en: 13 de Marzo de 2020, 21:12:36 »
Citar
Referente al tema de la implementación si, es de novato, me encuentro aprendiendo a programar con este proyecto y aún no se hacer muchas cosas, de hecho tengo problemas con la forma de manejar los punteros ya que aún me cuesta entenderlos totalmente.

Pensalo simple...
Un puntero es solamente una direccion de memoria. Asi que si lo tratas como una variable entonces estas cambiando a la direccion que apunta.
Para acceder a lo que esta apuntando solo le agregas el *. Y es todo lo que deberias saber sobre punteros...

Citar
se que está la función getc de stdio.h pero en lo poco que he leído aún no he encontrado como usarla con un tecladito alfanumérico de matriz (de los que venden para prototipos), cualquier otro consejo en este sentido es bienvenido.

Usualmente las funciones de las librerias standard de C por ahi no estan implementadas....
Asi que casi siempre es mejor generar uno mismo la funcion, o si el fabricante provee un API para el manejo de los modulos mejor.
pero Microchip al menos en estos PICs lo considero mas sensato hacerlo uno mismo.

La funcion que te comento que podes usar para pasar de un entero a un string es sprintf.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Miembros de estructuras son imprimidos con errores después de guardarlos
« Respuesta #4 en: 17 de Marzo de 2020, 18:27:24 »
Citar
Referente al tema de la implementación si, es de novato, me encuentro aprendiendo a programar con este proyecto y aún no se hacer muchas cosas, de hecho tengo problemas con la forma de manejar los punteros ya que aún me cuesta entenderlos totalmente.

Pensalo simple...
Un puntero es solamente una direccion de memoria. Asi que si lo tratas como una variable entonces estas cambiando a la direccion que apunta.
Para acceder a lo que esta apuntando solo le agregas el *. Y es todo lo que deberias saber sobre punteros...

Citar
se que está la función getc de stdio.h pero en lo poco que he leído aún no he encontrado como usarla con un tecladito alfanumérico de matriz (de los que venden para prototipos), cualquier otro consejo en este sentido es bienvenido.

Usualmente las funciones de las librerias standard de C por ahi no estan implementadas....
Asi que casi siempre es mejor generar uno mismo la funcion, o si el fabricante provee un API para el manejo de los modulos mejor.
pero Microchip al menos en estos PICs lo considero mas sensato hacerlo uno mismo.

La funcion que te comento que podes usar para pasar de un entero a un string es sprintf.

Gracias por la info pero estaba viendo lo siguiente, el usar arreglos de cadenas significa que lo que debo hacer primero es asignarle una cadena por defecto para que lo dimensione o me va a dar problemas luego, no recordaba que de esa manera había definido los textos de los menú proncipal o secundario lo cual es lo primero que se imprime al encender el sistema.

Lo otro es lo siguiente, las funciones que imprimen y almacenan los datos en la estructura están implementadas de esa forma en el case "default" para que impriman en tiempo real lo que voy escribiendo en el teclado y almacenando, de lo contrario tendría que ir imprimiendo mediante un contador para que no imprima los caracteres por defecto guardados cuando defino el arreglo hasta que los llene por completo o los guardo primero en una variable temporal la cual es la que se imprime y cuando termine de llenarla entonces la paso al arreglo para almacenar, esto último me pareció más complicado de hacer, es correcta mi interpretación o estoy equivocado?.

Lo que si debo cambiar de plano es como llamo a las funciones de almacenamiento e impresión de datos en la pantalla.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Miembros de estructuras son imprimidos con errores después de guardarlos
« Respuesta #5 en: 17 de Marzo de 2020, 20:18:01 »
Citar
una variable temporal la cual es la que se imprime y cuando termine de llenarla entonces la paso al arreglo para almacenar

Correcto, Y si es un poco engorroso.

Citar
Gracias por la info pero estaba viendo lo siguiente, el usar arreglos de cadenas significa que lo que debo hacer primero es asignarle una cadena por defecto para que lo dimensione o me va a dar problemas luego, no recordaba que de esa manera había definido los textos de los menú proncipal o secundario lo cual es lo primero que se imprime al encender el sistema.

Si quisieras no tocar demasiado tu programa, solo deberias modificar una sola cosa, hacerlo asi:

Código: C
  1. typedef struct /* Estructura para almacenar la fecha */
  2. { /* y hora del dispositivo. La */
  3. uint8_t ano[5]; /* estructura está pensada para */
  4. uint8_t mes[3];
  5. uint8_t dia[3];
  6. uint8_t hora[3];
  7. uint8_t minuto[3];
  8. uint8_t segundo[3];
  9. } tiempo;

Y asegurarte que ano[4], y todos los demas [2] sean si o si cero, Asi termina el string.
Esto es el minimo cambio que deberias realizar.

Es cierto que es mas comodo usar una estructura para lo que planteas. Pero implica tener un puntero a lo que estas modificando para mostrar eso unico. Suponete que lo hacemos con "indices" entonces no tiene sentido hacer una estructura, lo podemos plantear como arrays, te doy un ejemplo sin probar y sin reventarme demasiado la cabeza..

Declaracion de las variables...
Código: C
  1. uint8_t tiempo[6], auxiliar;
  2. uint8_t *temp;
  3.  
  4. enum tiempo_e {ANO,MES,DIA,HORA,MINUTO,SEGUNDO};
  5. char salida[10];

tiempo mantiene todos los valores del RTC, como imagino que queres manejarte con nombres entonces cree un enum para que pueda usarlo, auxiliar es tu array donde vas a cargar los datos en formato de entero, *temp es solo un puntero para asegurarme de saber cual se esta modificando. Finalmente salida es tu string donde tendrias el mensaje a enviar con tu funcion.
Código: C
  1. tiempo[tiempo_e.ANO] = 20;
  2.     tiempo[tiempo_e.MES] = 3;
  3.     tiempo[tiempo_e.DIA] = 17;
  4.     tiempo[tiempo_e.HORA] = 19;
  5.     tiempo[tiempo_e.MINUTO] = 31;
  6.     tiempo[tiempo_e.SEGUNDO] = 00;

Para cargar valores, asi tambien podes usar el enum para pasarlo como indice..

Para actualizar el string de "salida"

Código: C
  1. void actualizarString(uint8_t indice){
  2.     if (&tiempo[indice] == temp)
  3.     {
  4.         sprintf(salida, "%u",auxiliar);
  5.     } else {
  6.         sprintf(salida, "%u",tiempo[indice]);
  7.     }
  8. }
Como ves si estoy modificando algun valor, entonces precargo temp con su direccion, de esa forma puedo saber cual se esta modificando, y en caso de que se este modificando, mostraria el valor temporal ( auxiliar ) y no el del array.

Y finalmente si tenes ese valor "auxiliar" como un string y no como un entero, la carga al array se podria complicar un poco. Entonces pense en una funcion que te permita realizarlo, Ojo que espera un 0 al final de lo cargado:

Código: C
  1. void Cargar_stoi(uint8_t indice, uint8_t *text){
  2.     // Paso de texto a numero, hasta que llegue un 0
  3.     uint8_t i;
  4.     for(i=0; *text != 0; text++) {
  5.         tiempo[indice] *= 10;
  6.         tiempo[indice] = *text-'0';
  7.     }
  8. }

Finalmente usarias:

Código: C
  1. Mensaje_Ent(salida)

Para imprimirlo... Es decir actualizas el string salida y lo imprimis. Lo que va a determinar si es mas pesado el programa, va a ser cuantas veces lo imprimis, deberias ser consciente que si no cambia no deberias imprimirlo.