Go Down

Topic: Pasar de un tipo de variable a otro (Read 1 time) previous topic - next topic

Sergegsx

Aug 26, 2011, 03:46 pm Last Edit: Aug 26, 2011, 03:57 pm by Sergegsx Reason: 1
Hola, me gustaria abrir este post para analizar los metodos de pasar de un tipo de variable a otro.
Estoy teniendo muchos problemas con mi pantalla LCD ya que cuando le envio datos para mostrar si no tengo las variables perfectamente definidas y segun espera la libreria, me cuelga el programa.
Le he metido muchiiiiiisimas horas y algo he avanzado, a ver si entre todos me ayudais a terminar de pulirlo porque sigue dandome problemas
El titulo del post no menciona nada de LCD porque en principio este post deberia servir para cualquier caso.
Al tema...

La libreria de mi pantalla LCD I2C realiza esta función.
Code: [Select]

// **************************************************************
// sends string
// **************************************************************
void BV4618_I::puts(char *s)
{
char *sp=s;  
 Wire.beginTransmission(_i2adr);
 // send *s as bytes of date
 while(*sp)
   Wire.send(*(sp++));
 Wire.endTransmission();
}  



Esto funciona sin problemas ya que es un simple string y es el ejemplo mas sencillo.
Code: [Select]

di.puts("Hello World");


A partir de ahi empiezan los problemas cuando la sentencia que le envio no es como quiere.
Esto funciona, no entiendo porque ya que si currentMillis es 12345 el resultado de la división es 12.345 que es un float en lugar de un long ????¿?¿?¿?
Code: [Select]

unsigned long currentMillis;
char time_str[4];  // Define as a string (4 bytes)
currentMillis = millis();

di.puts(ltoa (currentMillis/1000, time_str, 10));


Esto funciona y tampoco entiendo porque, ya que apparentPower es un double y no un long para usar ltoa
Code: [Select]

double apparentPower;
char time_str[4];  // Define as a string (4 bytes)
...
     di.rowcol(2,1);
     di.puts(ltoa(apparentPower, time_str, 10));   di.puts(" Watts ");


Esto lo aprendi ayer y me ha ayudado mucho ya que esto me funciona en un programa por separado donde solo haya este codigo.
Code: [Select]

char lcd_data[70];
 di.rowcol(1,1);
 
float horas = time/3600000;
long segminuto = ((time - (int)horas*3600000));
int minutos = (segminuto / 60000);
int segundos = ((segminuto - minutos*60000) / 1000);
// coge todos los segundos y le resta los segundos correspondientes a las horas de "horas"
// de esta resta nos quedan los segundos sin contar las horas (es decir los segundos hacia
// la proxima hora completa

 sprintf(lcd_data,"Time: %0d:%02d:%02d",(int)horas,minutos,segundos);
 di.puts(lcd_data);


En cambio ahora quiero hacer eso mismo en un proyecto y se me bloquea el programa. Si descomento estas lineas el programa entero funciona perfecto.
Code: [Select]

char uptime_data[4];

             float horas;
                   horas = ((float)currentMillis/3600000.0);
             long minutos;
                  minutos = currentMillis - (int)horas*3600000;  
                                    
             int horass;
                 horass = (int)horas;
             
               sprintf(uptime_data,"T: %0d  ",horass);
               di.puts(uptime_data);


He leido mucho de tipos de variables pero no termino de saber que pasa.
Se que hay mucho aquí, pero si alguien tiene alguna sugerencia igual puede ayudarme.
gracias

Sergegsx

#1
Aug 26, 2011, 03:56 pm Last Edit: Aug 26, 2011, 04:02 pm by Sergegsx Reason: 1
por lo que veo si intento realizar muchos calculos en una misma linea me da mas problemas, ahora lo he pasado a esto y por serial me aparece bien, pero al descomentar la linea que lo envia al LCD se bloquea

Code: [Select]

             int horas;
                   horas = (int)((float)currentMillis/3600000.0);
             long minutos;
                  minutos = (int)horas*3600000;  
                  minutos = currentMillis - minutos;
                  minutos = (int)((float)minutos / 60000.0);
             int iminutos = (int)minutos;    
             Serial.print(horas);Serial.print(":");Serial.print(iminutos);Serial.println();

               sprintf(uptime_data,"T: %0d  ",(int)horas);
               di.puts(uptime_data);



si quito:
Code: [Select]

               sprintf(uptime_data,"T: %0d  ",(int)horas);
               di.puts(uptime_data);


por serial me aparece bien, pero si se lo envio al LCD se bloquea, y eso que solo estoy enviado "horas"
importante: creo que es el sprintf lo que falla ya que si comento esa linea si que funciona.
lo que no enteindo es que en principio estoy haciendo lo mismo que en los ejemplos anteriores,no?

curro92



Hola,
Creo que estás machacando memoria, y eso origina resultados imprevisibles:
Code: [Select]

char uptime_data[4];           
sprintf(uptime_data,"T: %0d  ",horass);

defines una  cadena char uptime_data[4] de 4 bytes (3 caracteres + null), y luego le estás metiendo una 'T', un ':', un espacio, uno o dos caracteres de la hora y dos espacios, en total  6 o 7 caracteres!
Prueba definiendo
char uptime_data[10]; 

Dukatus

La solución mas practica es reescribir la libreria y sobrecargar el metodo en cuestion.
Te pongo un trozo de codigo de la libreria que tengo hecha para mi pantalla.
Code: [Select]

void LCD128x64Class::Write(char* st)
{
 Serial1.print(st);
}

void LCD128x64Class::Write(int st)
{
 Serial1.print( st, DEC );
}

void LCD128x64Class::Write(long st)
{
 Serial1.print(st, DEC );
}

void LCD128x64Class::Write(float st)
{
 static char * valor = "         ";
 valor = dtostrf( st, 4, 2, valor );
 Serial1.print(valor);
}

void LCD128x64Class::Write(float st, int decimales)
{
 static char * valor = "         ";
 valor = dtostrf( st, 4, decimales, valor );
 Serial1.print(valor);
}

Lo mismo que yo e sobrecargado el metodo Write tu puedes hacerlo con tu metodo puts(char *s).

Saludos.

Sergegsx

#4
Aug 26, 2011, 04:31 pm Last Edit: Aug 26, 2011, 04:37 pm by Sergegsx Reason: 1



Hola,
Creo que estás machacando memoria, y eso origina resultados imprevisibles:
Code: [Select]

char uptime_data[4];          
sprintf(uptime_data,"T: %0d  ",horass);

defines una  cadena char uptime_data[4] de 4 bytes (3 caracteres + null), y luego le estás metiendo una 'T', un ':', un espacio, uno o dos caracteres de la hora y dos espacios, en total  6 o 7 caracteres!
Prueba definiendo
char uptime_data[10];  



mm... bien visto, sin duda eso puede ser uno de los problemas. pero sigue sin funcionar.

Code: [Select]

int horas;
               horas = (int)((float)currentMillis/3600000.0);
char uptime_data[10];
               sprintf(uptime_data,"%d%d",(int)horas,(int)horas);
               di.puts(uptime_data);


he dejado al margen iminutos a ver si consigo que al menos me aparezca 2 veces hora.

Sergegsx


La solución mas practica es reescribir la libreria y sobrecargar el metodo en cuestion.
Te pongo un trozo de codigo de la libreria que tengo hecha para mi pantalla.

Lo mismo que yo e sobrecargado el metodo Write tu puedes hacerlo con tu metodo puts(char *s).

Saludos.



sin duda creo que esa es la solución final, pero ahora mismo me viene un poco grande hacer eso ya que si estoy teniendo tantos problemas con unas conversiones y mostrarlo en pantalla, todavia no me veo reescribiendo la libreria.
en el enlace este dicen que van a hacerlo en el futuro, pero no cuento con ello ya que lo pusieron hace mucho tiempo. http://doc.byvac.com/index.php5?title=Talk:Arduino_BV4618

adjunto la libreria, no para que me la reescribas sino por si hay algo que yo no veo y hace que no funcione el programa, aunque creo que tengo un lio absoluto en las conversiones.

gracias por vuestra ayuda

Sergegsx

Pregunta...
Es posible que a lo largo del programa cuando he utilizado código tipo el siguiente, este "dañando" la memoria y que luego aunque haga una conversión bien, falle ????

Code: [Select]

double apparentPower;
char time_str[4];  // Define as a string (4 bytes)
...
      di.rowcol(2,1);
      di.puts(ltoa(apparentPower, time_str, 10));   di.puts(" Watts ");



Tengo el proyecto al 99% a falta de tan solo imprimir en el LCD una linea con el tiempo que lleva el arduino encendido (uptime).
y de paso a ver si aprendo a hacer bien las conversiones y sacarlas por LCD.

os agradezco mucho la ayuda.

Sergegsx

lo que has dicho curro de machacar la memoria me ha llevado a comentar todo el codigo que menciono en mi primer mensaje de "funciona pero no se porque"
y ahora el tema de las horas ya funciona,
voy a seguir investigando pero puede que tuviese un codigo que "funcionaba" pero que estropeaba cosas por dentro de la memoria y hace que el programa se bloquee en otros trozos de codigo
no se si me explico.

Sergegsx


La solución mas practica es reescribir la libreria y sobrecargar el metodo en cuestion.
Te pongo un trozo de codigo de la libreria que tengo hecha para mi pantalla.
Code: [Select]

void LCD128x64Class::Write(char* st)
{
 Serial1.print(st);
}

void LCD128x64Class::Write(int st)
{
 Serial1.print( st, DEC );
}

void LCD128x64Class::Write(long st)
{
 Serial1.print(st, DEC );
}

void LCD128x64Class::Write(float st)
{
 static char * valor = "         ";
 valor = dtostrf( st, 4, 2, valor );
 Serial1.print(valor);
}

void LCD128x64Class::Write(float st, int decimales)
{
 static char * valor = "         ";
 valor = dtostrf( st, 4, decimales, valor );
 Serial1.print(valor);
}

Lo mismo que yo e sobrecargado el metodo Write tu puedes hacerlo con tu metodo puts(char *s).

Saludos.



Dukatus cuando tienes esa funcion llamada en todos los casos igual, como decide cual tiene que ejecutar cuando es llamada? Que hace mirar lo que estas enviando y en base a eso escoger entre ellas?
cuando llamas a la funcion le indicas el tipo?
LCD.Write(float 123.24)
o solo envias el numero?

acabo de ver que usas "dtostrf", a ver si puedo adaptar mi libreria y hacer lo mismo y asi no tengo que hacer cosas como esta en el codigo del programa.
Code: [Select]

float coste;
      coste = (emon.sumakw/1000)*preciokwh;    // por decidir donde lo meto
      int costedecimales = (coste - (int)coste) * 100;
      sprintf(coste_data,"%0d.%02d E  ",(int)coste,costedecimales);  //d - el argumento es tratado como un integer y presentado como un número decimal (con signo).
      di.puts(coste_data);


seria pillar esto y adaptarlo,no?
Code: [Select]

// **************************************************************
// sends char
// **************************************************************
void BV4618_I::putch(char c)
{
  Wire.beginTransmission(_i2adr);
  Wire.send(c);
  Wire.endTransmission();


// **************************************************************
// sends string
// **************************************************************
void BV4618_I::puts(char *s)
{
char *sp=s; 
  Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();



Sergegsx

bueno Arduino me esta matando !!
Si no fuese poco con los cuelgues del programa debido a las conversiones, ayer el "ethernet shield" decidio que dejaba de funcionar. no se si abrir post para esto o no, el tema es que no funciona ni el ejemplo "webclient" que viene con arduino pero si el "webserver", es decir que si tiene que acceder a internet no funciona, pero por lo demas si, increible.

como solucion para no dejar mi proyecto sin registrar datos me puse a escribir como un loco codigo para usar la memoria SD del "ethernet shield" y guardar los datos ahi.
lo basico funciona pero vuelvo al mismo PROBLEMA:

algo hago mal en las conversiones ya que el codigo funciona cogido con pinzas. es decir, ahora mismo tal como esta funciona. pero si añado un simple Serial.println o lo que sea, ya no va bien y se reinicia.

os puedo poner todo el codigo pero es larguisimo, alguien ve algo que yo no?

Code: [Select]

void saveSD(){

  DateTime now = RTC.now();
//  long power = emon.apparentPower;  // tambien he probado a pasarlo a long con cast pero tmb se ralla.
 
//  double apparentPower = 1234.56;
 
//*************************** 

  char s[32];
  dtostrf(emon.apparentPower, 4, 2, s);

/*
char s[32];
Serial.println(dtostrf(-1.0001, 2, 5, s));
*/

String dataString = String(now.unixtime()) + ";" + String(s);

//  String dataString = " Hello ethernet";             // con esta linea va bien siempre
//String dataString = String(count) + ";" + String(count);// + String(charapparentPower);    // + ";230;0.95;1;45";     pretendia que guardase mas valores pero en cuanto habilito mas codigo se reinicia
//***************************

  //Open a file to write to
  //Only one file can be open at a time
  File dataFile = SD.open("loga.txt", FILE_WRITE);
        if(dataFile)
        {
          dataFile.println(dataString);
          dataFile.close();
          Serial.println(dataString);
        }
        else
        {
          Serial.println("Couln't access file");
        }

count++;
}



ahora lo tengo almacenando el unixtime stamp y solo 1 parametro ya que si pongo mas se reinicia.
no se si pedir otra ethernet, pero no lo entiendo proque iba perfectamente.

Go Up