Empfangener hex-String in ASCII umwandleln

Hallo Leute,

ich komme gerade nicht weiter, vielleicht kann mir jemand weiter helfen. Es geht um folgendes, ich empfange über die serielle Schnittstelle eine Zeichenkette mit 32 Zeichen. Dabei handelt es sich um hex-Werte, welche ich als ASCII-Zeichen darstellen möchte.

Beispiel, folgendes wird empfangen:
FL022020202053544552454F20202020

Die ersten vier Zeichen müssen ignoriert werden, danach bilden immer jeweils zwei Zeichen einen hex-Wert:
20 20 20 20 53 54 45 52 45 4F 20 20 20 20
Werden die hex-Werte in ASCII umgewandelt, ergibt das das Wort STEREO

Ich lese die Daten der seriellen Schnittstelle in ein char array ein. Probleme habe ich jetzt jedoch dabei, jeweils zwei Zeichen zu einem hex-Wert zusammenzufassen und den Wert dann auszugeben.

Ich stelle mir das so vor, buffer[4] + buffer[5] zusammenfassen und mit Serial.write ausgeben. Muss ich aber wohl noch ein “0x” voranstellen, damit die beiden Werte als Hex-Wert erkannt werden? Jemand eine Idee um das elegant zu lösen?
Ziel ist es später, die Daten im lesbaren Format über ein LCD auszugeben.

Danke, Gruß

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

void loop()
{
  static char buffer[80];                               //Anzahl der einzulesenden Zeichen
  int laenge = (readline(Serial.read(), buffer, 80));    //laenge = Anzahl der eingegebenen Zeichen
  if (laenge > 0) {
    Serial.print("Eingabe: ");
    Serial.println(buffer);
    Serial.print("Anzahl Zeichen: ");
    Serial.println(laenge);    
    Serial.println("----------------------");

    if (strncmp(buffer, "FL02", 4) == 0)
    {
      Serial.println("Zeichenkette erkannt:");
      Serial.println(buffer+4); 
    }
  }
}


// Funktion zum Einlesen der seriellen Eingabe, Rückgabewert entspricht der Anzahl der Zeichen
int readline(int readchar, char *buffer, int len)
{
  static int pos = 0;
  int rpos;

  if (readchar > 0) {
    switch (readchar) {
    case '\n': // Ignore new-lines
      break;
    case '\r': // Return on CR
      rpos = pos;
      pos = 0;  // Reset position index ready for next time
      return rpos;
    default:
      if (pos < len-1) {
        buffer[pos++] = readchar;
        buffer[pos] = 0;
      }
    }
  }
  // No end of line has been found, so return -1.
  return -1;
}

Guten Abend,

Du kannst dir vielleicht mit einer C-Funktion etwas zusammenbauen. strtol bietet dir genau das was du suchst.
Wenn du der Funktion dein Zeichenkette zum umwandeln gibst kannst du das Ergebnis direkt in einen char casten

char toHex(char *a)
{
        /* hier brauchst du sogar nur eine Zeile und kannst die Variablendeklaration auslassen */
	char zeichen = (char)strtol(a,NULL,16);
	return zeichen;
}
        /* Beispielhaft für deinen Fall beginnend mit dem fünften Wert */
        char hexWert[3];
	for(unsigned int i = 4; i < strlen(buffer) - 1; ++i)
	{
		hexWert[0] = buffer[i];
		hexWert[1] = buffer[++i];
		hexWert[2]  ='\0';
		result = toHex(hexWert);
	}

Sicher gibt es schönere Wege. Wollte dir nur strtol ans Herz legen.
In meinBuchstabe steht nun dein gewünschtes Zeichen drin.

Spexx:
Ich stelle mir das so vor, buffer[4] + buffer[5] zusammenfassen und mit Serial.write ausgeben. Muss ich aber wohl noch ein “0x” voranstellen, damit die beiden Werte als Hex-Wert erkannt werden? Jemand eine Idee um das elegant zu lösen?
Ziel ist es später, die Daten im lesbaren Format über ein LCD auszugeben.

Decodierung des codierten Strings “an Ort und Stelle” unter Zerstörung des ursprünglichen (codierten) Strings:

void decodeString(char* input)
{
  int i;
  for (i=0;i<strlen(input);i=i+2)
  {
    char c=input[i];
    if (c>='A') input[i/2]=16*(10+c-'A'); else input[i/2]=16*(c-'0');
    c=input[i+1];
    if (c>='A') input[i/2]+=(10+c-'A'); else input[i/2]+=(c-'0');
  }
  input[i/2]='\0';
}

void setup() {
  char input[]="FL022020202053544552454F20202020";
  Serial.begin(9600);
  decodeString(&input[4]); // input ab 4. Zeichen decodieren
  Serial.println(&input[4]);
}

void loop() 
{}

Der String wird ab der vierten Stelle decodiert, und genau dort beginnt auch der decodierte String.
Vorteil: Kein zusätzlicher RAM-Verbrauch für den decodierten String.

Denkbar wäre natürlich auch eine Funktion, die den decodierten String in einem anderen char-Array ausgibt, so dass der codierte String auch noch nach der Decodierung verfügbar ist.

Super, danke euch beiden das hat mir schon weiter geholfen, habe es damit nun hinbekommen. Gehen denn alle C-Funktionen mit dem Arduino oder gibt es da noch Einschränkungen?

@jurs
Dein Code funktioniert super, ich habe jedoch die Umrechnung noch nicht ganz verstanden. Wie ist denn die Logik, gibt es irgendwo eine Erklärung zu dieser 'Formel'? Und was bewirkt das &-Zeichen vor dem Array?

Spexx:
Gehen denn alle C-Funktionen mit dem Arduino oder gibt es da noch Einschränkungen?

Nicht alle. Es gebt außerdem einige nicht-ISO-C Funktionen. Und printf() z.B. ist etwas abgespeckt.

Was wirklich vorhanden ist siehst du hier:
http://www.nongnu.org/avr-libc/user-manual/modules.html

Da ist für allem math.h, string.h, stdlib.h und stdio.h relevant

Spexx:
@jurs
Dein Code funktioniert super, ich habe jedoch die Umrechnung noch nicht ganz verstanden. Wie ist denn die Logik, gibt es irgendwo eine Erklärung zu dieser 'Formel'? Und was bewirkt das &-Zeichen vor dem Array?

Zur Decodierung schaust Du Dir am besten mal eine ASCII-Tabelle an!

Um eine dezimale Ziffer vom ASCII-Code zur Zahl zu decodieren, ziehe ich vom ASCII-Code der Ziffer einfach den ASCII-Code der Ziffer Null ab und erhalte die Zahl als c-'0'

Und da im Hex-Code A für 10, B für 11, C für 12 etc. steht, verfahre ich dort genau so, außer dass ich noch 10 dazuzähle und die entsprechende Zahl aus dem ASCII-Code erhalte als 10+c-'A'

Der Gesamtcode einer zweistelligen Hex-Zahl ergibt sich zu "16* erste_Zahl + zweite_Zahl".

Das &-Zeichen ist der Adressoperator, mit dem ich einen Zeiger auf ein bestimmtes Zeichen im String übergebe. Statt dass ich die Funktion mit dem Anfang des Strings "input" aufrufe, wofür man auch "&input[0]" schreiben könnte, rufe ich die Funktion mit einem Zeiger auf das Zeichen mit dem Index 4 auf als "&input[4]", weil ja die ersten vier Zeichen überlesen und nicht beachtet oder decodiert werden sollen.

Ich schließe mich hier mal an obwohl ich nicht weiß ob ich hier richtig bin.

Ich benutze Tintenpatronen mit eingebautem Eeprom auf dem ein paar Werte gespeichert werden. Diese Werte würde ich gerne mit dem Arduino auslesen. Es handelt sich um ein Onewire Eeprom DS2431 1024bit
Datenblatt:

Mit einem Sketch den ich im Netz gefunden habe kann ich diese Eeproms auch auslesen aber ich weiß nicht wie diese Daten codiert sind und wie ich das umrechnen kann. Hat jemand eine Idee wie ich das rausbekommen kann?

Hier ist der Sketch:

#include <OneWire.h>

OneWire  ds(2);    // 1-wire on pin 2
byte     addr[8];  // Contains the eeprom unique ID
void setup(void)
{
  Serial.begin(9600);
}
  
void loop(void) 
{
  byte i;
  byte dat[13];

  SearchAddress(addr);

  dat[0] = 0x01;
  dat[1] = 0x02;
  dat[2] = 0x03;
  dat[3] = 0x04;
  dat[4] = 0x05;
  dat[5] = 0x06;
  dat[6] = 0x07;
  dat[7] = 0x08;
  
  WriteRow(0,dat);
  ReadAllMem();    //print all mem content
  
  while(1);
}

void SearchAddress(byte* address) //Search for address and confirm it
{
  int i;
  if ( !ds.search(address))
  {
    Serial.print("No device found.\n");
    ds.reset_search();
    delay(250);
    return;
  }
  
  Serial.print("ADDR= ");
  for( i = 0; i < 8; i++)
  {
    Serial.print(address[i], HEX);
    Serial.print(" ");
  }

  if ( OneWire::crc8( address, 7) != address[7])
  {
      Serial.print("CRC is not valid, address is corrupted\n");
      return;
  }
  
  if ( address[0] != 0x2D) 
  {
      Serial.print("Device is not a 1-wire Eeprom.\n");
      return;
  }
  Serial.println();
}

void WriteReadScratchPad(byte TA1, byte TA2, byte* data)
{
  int i;
  ds.reset();
  ds.select(addr);
  ds.write(0x0F,1);  // Write ScratchPad
  ds.write(TA1,1); 
  ds.write(TA2,1); 
  for ( i = 0; i < 8; i++)
    ds.write(data[i],1);  
  
  ds.reset();
  ds.select(addr);    
  ds.write(0xAA);         // Read Scratchpad
  
  for ( i = 0; i < 13; i++)     
    data[i] = ds.read();
}

void CopyScratchPad(byte* data)
{
  ds.reset();
  ds.select(addr);
  ds.write(0x55,1);  // Copy ScratchPad
  ds.write(data[0],1); 
  ds.write(data[1],1);  // Send TA1 TA2 and ES for copy authorization
  ds.write(data[2],1); 
  delay(25); // Waiting for copy completion
  //Serial.print("Copy done!\n");
}

void ReadAllMem()
{
  int i;
  ds.reset();
  ds.select(addr);
  ds.write(0xF0,1);  // Read Memory
  ds.write(0x00,1);  //Read Offset 0000h
  ds.write(0x00,1);
  
  for ( i = 0; i < 128; i++) //whole mem is 144 
  {
    Serial.print(ds.read(), HEX);
    Serial.print(" - ");
    Serial.println(ds.read(), DEC);
  }
  Serial.println();
}

void WriteRow(byte row, byte* buffer)
{
  int i;
  if (row < 0 || row > 15) //There are 16 row of 8 bytes in the main memory
    return;                //The remaining are for the 64 bits register page
    
  WriteReadScratchPad(row*8, 0x00, buffer);
  
  /*  Print result of the ReadScratchPad
  for ( i = 0; i < 13; i++) 
  {
    Serial.print(buffer[i], HEX);
    Serial.print(" ");
  }
  */
  CopyScratchPad(buffer);
  
}

Heraus bekomme ich folgendes:

ADDR= 2D CB 78 B0 A 0 0 18
3759959D14729F62F1393BFD31138A9581C46863C15BF7D69FA13849864C7BEB000000000000F0FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000

Und diese Daten sind darin verborgen:

Kann mir jemand dabei helfen?

Gruß

Hat niemand eine Idee oder einen Ansatz? :cold_sweat:

Gruß

Hallo Scherheinz,

die Infos dafür sind ein bisschen mau. Vielleicht kannst du noch weitere Infos dazugeben.

Druckerhersteller/Patrone? Das Problem ist, es ist nicht genau angegeben, wie diese Daten verarbeitet werden sollen. Hab mal Stichprobenartig nach bestimmten Zeichenfolgen gesucht, jedoch nichts gefunden.

Habe da testweise nach dem HEX Wert von 45 (Füllstand) gesucht

Hey!
Ist schwierig an Informationen zu kommen. Es handelt sich um einen Industrie Tintenstrahldrucker von Videojet. Der Verdünner in der Kartusche nennt sich Make up V710 D. Ich hab ungefähr 30 von den Chips herumliegen könnte also noch alle auslesen aber ich denke da gibt's keine Gemeinsamkeiten. Außerdem weiß ich nicht welche Wert auf den Chips drauf sind.
Eigentlich macht es keinen Sinn solche Daten großartig zu verschlüsseln, kann doch nix Kompliziertes sein oder????