DS18B20 Byte Wert in HEX umwandeln und in einem String anhängen.

Hallo Community,

Ich Spiele ein wenig mit meinem Arduino Nano V3.0, einem DS18B20 Sensor und einem SD-Card Shield herum.

Jetzt möchte ich gerne die Sensor ID mit der in der .ini Datei vergleichen.
Aber leider kann ich die DeviceAddress nicht als HEX Code in eine Liste / String speichern um es danach zu vergleichen.

Und wenn ich sprintf nehmen möchte, hängt sich das Programm auf meinem Arduino auf.

Der Code sieht so aus und es zeigt mir auch den HEX Code an mit Serial.print, aber leider bekomme ich den HEX code nicht in ein Array oder in den String rein.

Im String bekomme ich nur 16161616.

// Sensoruuid Ausgeben
char getuuid(DeviceAddress deviceAddress)
{
  String strsuuid;
  int sindex = 0;
  byte shex[9];
  strsuuid = String("");

  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) ("0");
    Serial.println(deviceAddress[i], HEX);
    shex[sindex++] = (deviceAddress[i]);
  }
  
  for (int s = 0;s < sindex;s++) {
    strsuuid += (shex[s], HEX);
    Serial.println(shex[s]);
  }
  
  Serial.println();
  Serial.print(F("String ausgabe : "));
  Serial.print(strsuuid);
}

Die derzeitige Ausgabe:

28
65
48
B
5
0
0
40

(
e
H
String ausgabe : 1616161616161616

Wie bekomme ich das hin, dass mein Array z.b.: array[0] = 286548B50040 so aussieht?

Danke

Das ist Murks, macht (hoffentlich) garnichts:

   if (deviceAddress[i] < 16) ("0");

Wenn die Ausgabe sowieso über Serial läuft, kannst Du alle Elemente des Strings auch einzeln mit Serial.print() ausgeben, Zahlen auch in Hex. Dann brauchst Du überhaupt keinen String mehr.

Zum Vergleichen kannst Du ebenso die Vergleichsadresse als Zahl (oder mehrere Zahlen) speichern und die vergleichen, ohne Umwandlung in Text.

DrDiettrich:
Das ist Murks, macht (hoffentlich) garnichts:

   if (deviceAddress[i] < 16) ("0");

Wenn die Ausgabe sowieso über Serial läuft, kannst Du alle Elemente des Strings auch einzeln mit Serial.print() ausgeben, Zahlen auch in Hex. Dann brauchst Du überhaupt keinen String mehr.

Zum Vergleichen kannst Du ebenso die Vergleichsadresse als Zahl (oder mehrere Zahlen) speichern und die vergleichen, ohne Umwandlung in Text.

Danke für den Hinweis, das mit der if Anweisung ist nichts.

Aber das andere von dir geht mir jetzt nicht ganz ein.
Ich möchte den gleichen String (Sensor ID) in einer INI Datei finden und den Wert davon Auslesen.

Beispiel:

ini.getValue("sensors", <gesuchter Schlüssel / Sensor ID>, sensorVal, bufferLen);

Dazu muss ich aber die byte Ausgabe von der Sensor ID in HEX umwandeln und es in eine Zeile bringen ?
Also statt so:

28
65
48
B
5
0
0
40

müsste ich es so hinbringen

286548B50040

um es in eine andere Funktion einzusetzen.

Du kannst auch Arrays wie sie sind mit memcmp() (memory compare) vergleichen. DeviceAddress ist nur ein typedef auf ein Byte Array mit 8 Bytes. Wenn man dann den Vergleichsschlüssel auch in eine Byte Array schreibt (bzw. in eine DeviceAddress Variable) kann man schön vergleichen.

Ansonsten ist gerade hierfür die String Klasse totaler Quatsch, da die Konvertierungs-Funktionen für Hex fehlen. Mit C Strings gibt es strtoul() (string to unsigned long) um einen String als Hex formatiert in einen Integer zu konvertieren und ultoa() (unsigned long to ascii) in die andere Richtung. Wobei es auch keine große Sache ist sich selbst eine Konvertierungs-Funktion für ein einzelnes Hex-Byte zu schreiben.
Eine andere Option wäre die PString Bibliothek mit der man print() auch für char Arrays machen kann.

Das einfachste ist es den String auf der SD Karte so zu schreiben, dass die einzelnen Bytes entweder mit Kommas getrennt sind oder dafür sorgen dass jedes Byte immer zwei Zeichen hat (also führende Nullen). Da liest man die 8 Hex-Bytes nacheinander ein, konvertiert jedes in einen Integer und schreibt diesen in das Array. Danach memcmp() und fertig.
Also anders herum wie du es bisher machst.

Brawn1:
Aber leider kann ich die DeviceAddress nicht als HEX Code in eine Liste / String speichern um es danach zu vergleichen.

Anbei kleines Beispielprogramm:

char* hex02str(byte b)
{
 static char str[]="02"; // RAM für einen 2-Zeichen string reservieren.
  snprintf(str,sizeof(str),"%02x",b);
  return str;
}
void setup() {
  Serial.begin(9600);
  // put your setup code here, to run once:
  byte addr[]={1,1,2,13,23,45,127,255};
  char linebuf[16]="";
  for (int i=0;i<8;i++)
    strcat (linebuf,hex02str(addr[i]));

 // jetzt steht der formatierte String im  char-Array "linebuf"
 Serial.println(linebuf);   

}

void loop() {
  // put your main code here, to run repeatedly:

}

Im Beispielprogramm passiert folgendes (alles in der setup-Funktion:

  • Deklaration und Initialisierung eines 8-Byte-Arrays namens "addr".
  • Anschließend werden diese 8 Bytes im String "linebuf formatiert", jedes Byte 2-stelling hex formatiert hintereinander
  • Am Ende von setup wird der linebuf-String einfach auf Serial ausgegeben.
  • es konnte aber auch ein Stringvergleich mit der strcmp-Funktion gemacht werden.

Bei char Arrays immer an das abschließende Null-Zeichen denken! Dafür muß das Array 1 Zeichen länger sein, und bei variablen Strings muß \0 im Code angehängt werden, sonst funktionieren die Standard-Funktionen nicht.

Ob snprintf() eine Lösung ist, oder zu viel Speicher verbrät, wäre noch herauszufinden. Eine einfache Hex-Konvertierung kann man mit einem char Array mit den Hex-Zeichen basteln:

const char HexChars[] = "0123456789ABCDEF"; //noch PROGMEM hinzufügen

Hier mal anders herum. String von der SD Karte auslesen, direkt in DeviceAddress konvertieren und zwei DeviceAddress vergleichen. Man sieht auch wie man einfach Hex-Zahlen per Hand konvertieren kann.

Den String auf der SD Karte dabei unbedingt mit führenden Nullen formatieren! Also dafür sorgen dass er immer 16 Zeichen hat. Zwei Zeichen pro Hex-Byte. Sonst geht es nicht. Also z.B. "0900AABBCCDDEEFF". In der Test-Datei steht nur das:

9900AABBCCDDEEFF

Und man sieht auch wie man sehr einfach ein Hex-Byte selbst von ASCII nach Integer wandeln kann

#include <DallasTemperature.h>
#include <SD.h>

DeviceAddress sensor1 = { 0x99, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
DeviceAddress sensor2 = { 0x11, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };

void setup()
{
  Serial.begin(9600);
  SD.begin();

  DeviceAddress compareAdr;
  get_id_from_SD("test.txt", compareAdr);
  Serial.print(F("von SD: ")); print_address(compareAdr);

  Serial.println();

  Serial.print(F("vergleiche: ")); print_address(sensor1);
  compare_adressses(sensor1, compareAdr);

  Serial.println();

  Serial.print(F("vergleiche: ")); print_address(sensor2);
  compare_adressses(sensor2, compareAdr);
}

void loop()
{
}

void compare_adressses(DeviceAddress adr1, DeviceAddress adr2)
{
  if (memcmp(adr1, adr2, sizeof(DeviceAddress)) == 0)
    Serial.println(F("gleich"));
  else
    Serial.println(F("nicht gleich"));
}

void get_id_from_SD(const char* filename, DeviceAddress destination)
{
  File file = SD.open(filename, FILE_READ);
  if (file)
  {
    char hexbyte[2];

    for (int i = 0; i < 8; i++)
    {
      hexbyte[1] = file.read();
      hexbyte[0] = file.read();

      destination[i] = hex_to_decimal(hexbyte);
    }

    file.close();
  }
}

byte hex_to_decimal(char hexbyte[2])
{
  byte value = 0;

  for (int i = 1; i >= 0; i--)
  {
    char c = hexbyte[i];

    if (c >= '0' && c <= '9')
      value += (c - 48);
    else if (c >= 'A' && c <= 'F')
      value += (c - 55);
    else if (c >= 'a' && c <= 'f')
      value += (c - 87);

    if (i == 1)
      value *= 16;
  }

  return value;
}

void print_address(DeviceAddress adr)
{
  for (int i = 0; i < 8; i++)
  {
    Serial.print(adr[i], HEX);
    Serial.print(',');
  }
  Serial.println();
}

Wenn jemand so etwas wie INI Files implementieren möchte, dann ist es schon richtig, die Schlüsselworte als Texte zu vergleichen. Das Ergebnis ist ebenfalls ein Text, z.B. ein Pointer nach dem "=" im Zeilenpuffer.

Entschuldigung für die späte Rückmeldung.

Vielen dank für die Hilfe, ich hab es jetzt so gelöst wie @Jurs gezeigt hat.
Da es genau das ist was ich machen wollte.

Hier der Code Ausschnitt mit dem ich es jetzt gemacht habe.

char* hex02str(byte b)
{
 static char str[]="02"; // RAM für einen 2-Zeichen string reservieren.
  snprintf(str,sizeof(str),"%00x",b);
  return str;
}

// get sensor comment
char getsensorcomment(DeviceAddress deviceAddress) {
  IniFile ini(filename);
  char lbuf[16]="";
  for (uint8_t i = 0; i < 8; i++)
  {
    strcat(lbuf,hex02str(deviceAddress[i]));
  }
  
  if (!ini.open()) {
    Serial.print(F("Ini file "));
    Serial.print(filename);
    Serial.println(F(" does not exist"));
    errorsign(8);
    while (1)
    ;
  }
  if (ini.getValue("sensor", lbuf, sensortxt, bufferLen)) {
    Serial.print(F("Sensor Comment : "));
    Serial.println(sensortxt);
    tempfile.write(sensortxt);
  } else {
    Serial.println(F("Could not read ini with Sensor comment"));
  }
  ini.close();
}

Danke