Comportamento strano stringa da float

Ciao a tutti,

ho fatto uno sketch per avere un log su NAS di un sensore DHT22 per temperatura ed umidità tramite un ESP32.

La stranezza sta nel fatto che la conversione con dtostrf, al momento di scrivere sul file di testo sul NAS, tira fuori caratteri strani (sempre gli stessi), oltre che ingarbugliare la prima stringa.

di seguito la funzione che converte e scrive sul NAS:

void printTempHum(float t, float h){

char te[4];
dtostrf(t,2,1,te);
Serial.println(te);

char hu[4];
dtostrf(h,2,1,hu);
Serial.println(hu);

ftp.Write("  ");
ftp.Write(te);
Serial.println(te);
ftp.Write("  ");
ftp.Write(hu);
Serial.println(hu);
}

Questo invece è quello che mi ritrovo sul serial monitor:
27.3
48.7
Write File
Write File
27.348.7,"�?,"�?�8�?XA�? ��p"�?
Write File
Write File
48.7,"�?,"�?�8�?XA�? ��p"�?

Come si vede, le variabili convertite, prima di essere scritte sul NAS, sono corrette, ma dopo la scrittura cambiano completamente.

Qui invece quello che viene scritto nel file di testo sul NAS:
27.348.7,"û?,"û?°8ü?XAü? á€p"û? 48.7,"û?,"û?°8ü?XAü? á€p"û?

Ovviamente sul NAS sono scritte coerentemente a quanto stampato sul serial monitor dopo la scrittura.

Qualche suggerimento?

Grazie anticipatamente a chi mi risponderà.

Prova a dichiarare le variabili hu e te più grandi. Mi sa che sfori dall'array.

Sfora sicuro, perché il punto conta come carattere, quindi 27.3 sono 4 caratteri a cui si deve aggiunge spazio per il terminatore, quindi:

char te[5] = { 0 };
char hu[5] = { 0 };

Ciao.

Certo come il sole che sorge ad Est

Ma prima di sforare almeno i primi caratteri di almeno una variabile dovrebbero essere giusti

Sono perplesso...

Direi: vediamo tutto il codice

Come ti ha già suggerito @Maurotec manca il terminatore di stringa (carattere '\0').
È evidente anche dal log che hai postato.

Grazie a tutti.

In effetti è bastato portare a 5 il valore della dimensione degli array, ed adesso i caratteri scritti sul file di testo sono corretti.

Mi rimane una curiosità, ovvero: il terminatore '\0' va inserito solo quando la stringa è formata da una somma di caratteri?
Nel mio caso, non ho inserito il terminatore, e comunque la conversione avviene correttamente.

Grazie nuovamente per avermi aiutato.

Ciao @Salvorhardin ,eccolo.

#include <WiFi.h>
#include <ESP32_FTPClient.h>
#include <WiFiUdp.h>
#include <time.h>
#include <SimpleDHT.h>

const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* ntpServer = "pool.ntp.org";
const char* tz = "CET-1CEST,M3.5.0/2,M10.5.0/3";

#define _DHTPIN 13
SimpleDHT22 dht22(_DHTPIN);


char ftp_server[] = "IP_NAS";
char ftp_user[]   = "USER_NAS";
char ftp_pass[]   = "PWD_NAS";

unsigned long t1;
struct tm timeinfo;

float temp, hum;

ESP32_FTPClient ftp (ftp_server,ftp_user,ftp_pass, 5000, 2);


void setup()
{
  Serial.begin( 115200 );

  WiFi.begin(ssid, password);
    Serial.println("Connecting Wifi...");
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }

  Serial.println("");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  //timeClient.begin();
  configTzTime(tz, ntpServer);
  printLocalTime();

  t1 = millis();

 }

void loop() {
  if ((millis() - t1) > 120000) {

dht22.read2(&temp, &hum, NULL);
Serial.println(temp);
Serial.println(hum);

ftp.OpenConnection();
ftp.ChangeWorkDir("/Public/");
 delay(1000);
  ftp.InitFile("Type A");
  ftp.AppendFile("Report.txt");
    printLocalTime();
    delay(100);
    printTempHum(temp, hum);
  ftp.Write("\n");
  Serial.println("NL");
  ftp.CloseFile();
  ftp.CloseConnection();


  t1 = millis();
    }
  }


void printLocalTime(){
  
  if(getLocalTime(&timeinfo)){
 
  Serial.println(&timeinfo, "%A, %b %d %Y %H:%M:%S");
  
  char dataora[20];
      strftime(dataora, sizeof(dataora), "%Y-%m-%d %H:%M:%S", &timeinfo); 
      Serial.println(dataora);

  ftp.Write(dataora);
  
 }
}

void printTempHum(float t, float h){

char te[5];
dtostrf(t,2,1,te);
Serial.println(te);

char hu[5];
dtostrf(h,2,1,hu);
Serial.println(hu);

ftp.Write(" ");
ftp.Write(te);
Serial.println(te);
ftp.Write("°C ");
ftp.Write(hu);
Serial.println(hu);
ftp.Write("%");

}

Se hai altri suggerimenti sull'altra parte del codice, sappi che saranno beneaccetti.

Il terminatore serve per sapere quando è "finita" la stringa, altrimenti si va a leggere oltre con i risultati che hai già visto.
Nel tuo caso il terminatore viene aggiunto dalla funzione dtostrf.

Le stringhe classiche del 'C' sono in reltà degli array di char ... tali array vanno dimensionati in modo che ci sia lo spazio per tutti i caratteri necessari, più un carattere dove dovrà essere presente il carattere 0x00 che indica, alle funzioni che utilizzano quell'array di caratteri, dove fermarsi (senza di esso non saprebbero dove finisce la stringa di caratteri).

Quindi, la regola è: dimensione dell'array = numero massimo di caratteri + 1. Lo 0x00 va messo dove finisce la stringa, quindi, se tu riservi un array di caratteri di 10 char potrai metterci dentro anche parole più corte di 9 caratteri, purché le termini con 0x00.

Esempio per array di 10 char:

"CIAO" : 0x43 0x49 0x41 0x4F 0x00 0x?? 0x?? 0x?? 0x?? 0x??

"123456789" : 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x00

Alcune funzioni del 'C', che operano su stringhe classiche, aggiungono loro il carattere 0x00 al risultato che danno, altre non lo fanno ... occorre sempre andare a leggere il reference della funzione per capire come si comporta.

Spero di aver chiarito, almeno in parte, il tuo dubbio ...

Guglielmo

P.S.: 0x?? indica un valore casuale presente nello spazio di memoria riservato per l'array.

Adesso leggendo mi si sono chiariti i dubbi

Prima non mi era chiaro, nel tuo esempio, chi stampava cosa

Il programma mi sembra ben fatto, ma ho una domanda
Perché su FTP usi il write invece che il print?
Le prime due trasmissioni dovrebbero uscire "sporche"
I valori numerici non "passano" per una write

Innanzitutto, grazie per l'interessamento.

In effetti non ho ben studiato la libreria, ma da quel poco che ho visto, non c'è la funzione print.

E comunque, visto la conversione da numero a stringa, la write non scrive un numero, ma appunto una stringa.

Mmmm ... mi sa che la usa il metodo stesso ...

void ESP32_FTPClient::Write(const char * str) {
  FTPdbgn(F("Write File"));
  if(!isConnected()) return;
  
  GetDataClient()->print(str);
}

Guglielmo

Si, avevo visto questo metodo. Ma il print è usato in tanti altri metodi.

Immagino in quelli che usano un char * (stringa classica del 'C') ... :roll_eyes:

Guglielmo

La cosa mi sembra confusa

Di solito non è la print a chiamare la write?