Serielle Schnittstelle HEX

Hallo,

ich bin gerade dabei eine serielle Schnittstelle zu programmieren, über die ich ein Schieberegister ansteuern kann. Ich habe mir schon überlegt, in welchem Format ich die Daten senden möchte:

0x00,0x55,0x07,0x00,0xFF,0xFF //halten an
0x00,0x55,0x07,0x00,0x00,0x00 //halten aus
0x00,0x55,0x07,0x01,0x05,0x64 //blinken
|-Header-|addr|mode|--value--|

Header ist der Anfang, damit das Programm weiß, wo es anfangen muss. Falls der Anfang ein anderer ist, dann soll er die ganze Zeit durch gehen (immer einen Byte weiter).
Addr ist die Adresse, also welcher Ausgang des Schieberegister angesteuert werden soll.
Mode ist der Modus in welcher die LED´s sich befinden sollen. (Es sind noch probeweise LED´s, aber ich habe hier schon Relais rumliegen.)
Value ist der Wert. Entweder wird dort die Zeit für das Blinken angegeben oder ob die LED´s an oder aus sein sollen.

Mein Problem. Wenn ich diese Daten so einlese, dann nimmt er jede Zahl/Buchstabe einzeln und erkennt es nicht als HEX. Wenn ich mir die ausgeben lasse, dann steht dort jede einzelne Stelle als ASCII.
Wie kann ich das am einfachsten lösen. Mit Strings hat es schon geklappt, aber von denen wollte ich mich eigentlich lösen.

Hier mein Programmcode:

bool portBuffer[256];
byte serialBuffer[6];
int latchPin = 2;
int clockPin = 3;
int dataPin = 4;
//byte leds = 0;



void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

}

void fill() {
  // check if data is available
  if (Serial.available() > 0) {
    // read the incoming bytes:
    Serial.readBytes(serialBuffer, 4);

    // prints the received data
    Serial.println("");
    Serial.println("");
    Serial.println("");
    for (int i = 0; i < 4; i++) {
      Serial.print("I received: ");
      Serial.println(serialBuffer[i]);

    }
  }

}

void loop() {
  fill();

}

Also prinzipiell habe ich wahrscheinlich das selbe Problem wie in diesem Post. Werte, (bytes) aus Datei lesen....
Leider konnte ich mir daraus aber keinen Lösungsweg ableiten.

dein Problem ist nicht so sehr das "HEX" sondern wie du die Zeichen einliest.

du sollst jedes Zeichen einzeln einlesen, einen Zähler mitführen damit du weist welche Stelle gerade empfangen wird und beim Empfang des Header den Zähler wieder auf 0 setzen.

Ich rat dir diesen Forum Beitrag zu lesen und umzusetzen

https://forum.arduino.cc/t/serial-input-basics-updated/382007

quick und dirty, ist aber halbwegs stabil auch wenn mal keine führende 0 kommt

bool portBuffer[256];
byte serialBuffer[6];
int latchPin = 2;
int clockPin = 3;
int dataPin = 4;
//byte leds = 0;

const byte header = 0;
byte index = 0;

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

}

void output()
{
  Serial.println();
  for (int i = 0; i < 4; i++) {
    Serial.print("I received: ");
    Serial.println(serialBuffer[i], HEX);
  }
}

void fill() {
  // check if data is available
  if (Serial.available() > 0) {
    char c = Serial.read();

    if (c == header)
    {
      memset(serialBuffer, 0, 4); // buffer löschen
      index = 1; // fürs nächste Zeichen
    }
    else
    {
      serialBuffer[index] = c;
      if (index >= 3)
      {
        output();  // 4 Zeichen ... muss nicht valide sein
        index = 0; // brutal stream abwürgen und von vorne anfangen lassen
      }
      else
      {
        index++;  // vorücken
      }
    }
  }
}

void loop() {
  fill();
}

ach ja, ich habe die Ausgabe auch auf HEX umgestellt, sonst verwirrt das wenn man glaubt "HEX" zu schicken, aber dezimal die Ausgabe macht :wink:

Proof of Concept:
5 Eingaben (die mit der Checkbox HEX auf der rechten Seite)
das erste Telegram ist zu kurz, daher kommt nichts vernünftiges mehr an und die folge Pakete "rücken" nach.
beim ersten richtigen header (Beispiel 4) fängt er sauber wieder an
der letzte 5te wird auch sauber gelesen.

Danke dir, ich schaue mir das mal an und versuche es zu verstehen. :sweat_smile:

naja sind eigentlich nur 6 Zeilen Code ... und 5 Kommentare, also viel mehr will ich da nicht dazuschreiben müssen :wink:

Bei Fragen - frag.

Jetzt noch den Absender hinzufügen und eine Checksumme ans Ende. Dann hast Du hast ein Keyword-Protokoll 2000 gebaut.
Mit dem Header/Format kannst Du dann auch steuern ob eine optionale Länge mitgegeben wird oder diese fix ist.

Also:
Format, Empfänger, Absender, [Nachrichtenlänge], Daten (Modus + Werte), Checksumme

So weißt Du schon wie lang diese Nachricht ist und anhand der Checksumme ob diese korrekt angekommen ist.
Diese "errechnet" sich aus der Summe aller vorigen Bytes, als uint8_t.

Nur mal so als Idee :slight_smile:

Also ich habe mich jetzt ausprobiert und noch ein zwei Änderungen vorgenommen und andere Codes probiert. Hat leider alles nicht geklappt. Brauche ich dafür auch eine zweite Software, so wie du?

Danke ich bin für jegliche Verbesserungsvorschläge zu haben. In meinem Fall ist aber der Absender nicht so wichtig. Die Kommunikation soll in meinem Fall eh nur in eine Richtung verlaufen.

Im Seriellen Monitor kannst du keine Zahlen eingeben. Hex oder sonstwas. Das ist immer ASCII. Deshalb braucht man ein richtiges Terminal Programm

zum Testen wirst du ein vernünftiges Terminalprogramm brauchen.
Denn im Serial Monitor wirst du kein 0x00 senden können - und du hast dir aber 0x00 als Startbyte / Header festgelegt!
Also brauchst du auch etwas das 0x00 senden kann!

Übrigens ist der Absender genauso wichtig. Da wäre es auch mal gut in einem ECHTEN Terminalprogramm zu sehen was der wirklich sendet - ob das tatsächlich
0x00 0x55 0x07 0x00 ... ist

Was ist dein Sender? Ein anderer Arduino ? dann zeig mal deinen Sendersketch oder einen Link auf das Datasheet das das Protokoll beschreibt.

Der vielleicht nicht. Aber die Länge der Nachrichten und die Checksumme.
Und wenn man schonmal dabei ist, kann man ja gleich einem bekannten Protokoll entsprechen :wink:

Oder man arbeitet mit Start- & Endzeichen. Dann empfielt sich aber eher STX (0x02) und ETX (0x03) als 0x00.

Binärinformation verarbeiten können ist natürlich eine tolle Sache.

Alternativ arbeitet man einfach mit lesbarem Text. Dann kann man auch mit simpelsten Mitteln (SerialMonitor, Textdateien) testen.
Da bietet sich '\n' = 0x0A als Endezeichen an und macht ein Startzeichen überflüssig.
mode und addr könnten je 1 (lesbares) byte bleiben, ob du dir für value den Luxus eines größeren Wertes (evtl. gar variabel bis zum EndeZeichen gönnst, musst du wissen.

Erstmal Vorweg danke für die ganzen Antworten.

Ich hatte vor den Arduino von einer Python Frontend anzusteuern. Diese muss ich aber noch realisieren. Ich habe mir jetzt ein Terminalprogramm heruntergeladen wüsste aber nicht, wofür der Absender in meinem Fall eine Bedeutung hat.

Über ein Endzeichen habe ich auch schon nachgedacht. Würde sich da auch ein Enter empfehlen? Das könnte man ja in dem Terminalprogramm einstellen. Also das es automatisch gesendet wird. Wenn es dann zur Frontend kommt, kann ich es ja immer noch ändern.

Ich hatte mit dem Gedanken gespielt, dass ich den merge Byte der values mit 100 multipliziere. Dann habe ich eine min. Zeit für das Leuchten von 0.2s und eine Max. Zeit von 51s. Wenn ich mich nicht komplett irre. Das sollte für meine Anwendungen ja genügen. Zur Not kann man das ja dann immer noch ändern. Vllt könnte ich auch einen Wert übergeben, welcher dann als Multiplikator dient. Das heißt in der Frontend gebe ich einfach die Dauer ein und dann berechnet sich das Programm automatisch den Multiplikator und die dazugehörigen values und übergibt diese im Protokoll. Wäre das auch eine Möglichkeit?

wenn du eh den Sender selber programmieren musst, bin ich da mittlerweile auch bei michael_x

Schicke deine Wert "einach mit lesbaren Text" und schließe mit Zeilenende ab.
KISS: Keep it Small and Simple.

Ein "Enter" Zeichen gibt es nicht. Schau dir mal eine ASCII Tabelle an. Du kannst einstellen dass beim Absenden automatisch ein bestimmtes ASCII Steuerzeichen gesendet wird.
ETX = End of Text. Das ist da schon vorgesehen. Oder war jedenfalls historisch so.

Der Grund weshalb dir Leute ASCII Text empfehlen ist dass es viel einfacher ist. Weil man sicher sein kann dass das Endzeichen nicht im Text vorkommt. Dafür ist die Anzahl der übertragenen Daten höher. Aber das ist in vielen Fällen egal.