Serielle Daten an Nadeldrucker DL3700

Hallo,

das ist mein erster Post. Bisher konnte ich mir immer selbst irgendwie helfen. Diesesmal bräuchte ich etwas Unterstützung bei meinem Problem. Ich möchte einen Nadeldrucker DL3700 mit einem Arduino Mega ersetzen und den am Arduino Mega empfangenen Text bearbeiten/formatieren sodass ich diesen auf einem Display anzeigen kann.

Der Master sendet im 25 Sekunden Takt die Sequenz STX,ENQ,ETX an den Drucker die ich mit einem ACK als Rückantwort bestätigen muss damit der Master nicht auf Störung geht.

Wenn eine Nachricht an den Drucker gesendet wird fängt die Sequenz mit STX,ESC,r,NUL an worauf die Nachricht in mehreren Zeilen ausgegeben wird. Ende jeder Zeile ist mit CR,LF und der Anfang der nächsten Zeile beginnt mit einem ETX worauf ich mit einem ACK antworten muss damit die nächste Zeile vom Master gesendet wird. Pro Nachrichtenzeile kommen 80 Zeichen rein wobe CR,LF nicht eingerechnet wird.

Da ich Anfänger bin, bin ich gerade am herumprobieren und versuche mich in die Serielle Schnittstelle einzuarbeiten. Generell, Code lesen und verstehen kann ich zu 60%.

Mein Codeschnipsel mit dem ich gerade arbeite sendet das ACK auf die Anfrage STX,ENQ,ETX vom Master zurück, das klappt. Leider klappt der zweite Teil mit der Sequenz STX,ESC,r,NUL nicht.

//**********************************************************************************
//Printer Emulator

#include <Arduino.h>

char Request_Printer[2]={0x0002,0x0005};                       //  Master sends "STX,ENQ,ETX" and requests "Is Printer connected?
char ETX[1]={0x0003};
char MSG_start[3]={0x0002,0x001b,0x0072};                      //  Master sends "STX,ESC,r,NUL"  That´s the Message Startcondition
char NUL[1]={0x0000};                                          

void setup() {
  Serial1.begin(4800, SERIAL_7E1);                             //  Set Baud Rate, Data Bits, Parity and Stop Bit
}

void loop() {
    
   
     if (Serial1.available()> 0)                              // Check if something in the UART RX Buffer
    {
        if(Serial1.findUntil(Request_Printer, ETX)) {         // Test the received buffer for "STX,ENQ,ETX"
            
            Serial1.print("ACK");                             /* If Received Data contains "STX,ENQ,ETX", give an "ACK" back
                                                                  so the Sender knows the "Printer" is still connected */
        
        }
        
        if(Serial1.findUntil(MSG_start, NUL)) {               // Test the incoming Data for "STX,ESC,r,NUL"
            
            Serial1.print("MSG Start");                       // If there is an match on "STX,ESC,r,NUL" just print "MSG Start"
        
        }
    }
}

Kann mir jemand sagen warum der zweite Teil nicht klappt?
Wie würdet Ihr die "Aufgabe" strategisch lösen?
Damit meine ich z.b. (so in etwa dachte ich)

  • Buffer anlegen 10 Zeichen lang für Sequenzen
  • Buffer anlegen 100 Zeichen lang für Nachrichten
  • immer nach vier eingegangenen Zeichen im Buffer_10 nach den Sequenzen STX,ENQ,ETX und
    STX,ESC,r,NUL suchen.
    if STX,ENQ,ETX -> sende ACK
    if STX,ESC,r,NUL speichere alle eingehenden Zeichen in den Buffer 100 und gib diese an das
    Display aus.

Beste Grüße,

mnemonic

Ich fass das mal für mich zusammen.
INPUT: STX, ENQ, ETX -> OUTPUT: ACK
INPUT: STX, ESC, 'r', NUL, "80 Zeichen TEXT", CR, LF, ETX, -> OUPUT: ACK
INPUT: "80 Zeichen TEXT", CR, LF, ETX, -> OUPUT: ACK
INPUT "80 Zeichen TEXT", CR, LF
Damit wären drei Zeilen Text gekommen und die Übertragung beendet.

Zwischenfrage: Die erste Sequenz kommt immer im 25-Sekundentakt, oder unterbricht der ETX aus der zweiten Sequenz die Anfrage?
Oder kurz: Nach dem letzten ETX wird erst nach weiteren 25Sekunden die Anfrage gesendet?

ich sehe da zwei Status:
IDLE ... während dessen ab und an ein STX,ENQ,ETX kommt
AUSGABE ... die durch STX,ESC,r,NUL gestartet wurde.

im IDLE würde ich jedes Zeichen einlesen. bei jedem STX Buffer leeren.
und nach 3 bzw 4 Zeichen überprüfen ob eine der zwei Startsequenzen vorliegt.

generell empfehle ich dir zunächst die Serial Input Basics durchzuarbeiten:
Serial Input Basics - updated - Using Arduino / Introductory Tutorials - Arduino Forum

Danke für die Antwort,

Wenn der Master nach z.B. drei Zeilen (oder mehr) fertig ist geht das Siel mit dem "STX, ENQ, ETX -> OUTPUT: ACK" nach 25 Sekunde wieder von vorne los. Dazwischen schiebt der Master immer nach meinem ACK auf das ETX die nächste Zeile Nachrichtentext raus. Stupide Wiederholungen nach 25 Sek gibts nur wenn keine Nachricht an den Drucker ansteht.

Beste Grüße,

Danke für den Input und die Quelle zum Tutorial! Werde ich mir gleich ansehen.

Beste Grüße,

Ok, damit funkt da nichts zwischen...
Na das sollte doch machbar sein. Mal sehen, ob sich was ergibt :wink:

Ich hab mal was gebastelt.
Nur auf dem Seriellen Monitor.

Um da nicht ganz quer zu gehen, habe ich auf einem UNO einen Sender gebaut, der eine "lebst Du noch" Anforderung sendet und in unregelmäßigen Abständen einen text.

Sieht erstmal nicht so schlecht aus. Ist noch nicht Optimal, aber ich hab ne Handvoll Kommentare drin :wink:
Ich wüsste gerne, was beii Dir raus kommt...

// Forensketch: Nadeldrucker Ausgabe ersetzen
// https://forum.arduino.cc/t/serielle-daten-an-nadeldrucker-dl3700/993372/7
const byte NUL = 0x00;
const byte STX = 0x02;
const byte ETX = 0x03;
const byte ENQ = 0x05;
const byte ACK = 0x06;
const byte LF  = 0x0A;
const byte CR  = 0x0D;
const byte ESC = 0x1B;

char zeile[85] = {'\0'};                 // Zwischenspeicher zum einlesen
char printSeq[3] = {ESC, 'r'};           // Druckzeile Anfang
uint8_t charPos;                         // Merker für neues Zeichen

const uint8_t displayZeilen = 5;         // Für Ringspeicher
char ausgabe[displayZeilen][85] = {'\0'};// Ringspeicher für Ausgabe
uint8_t ausgabePos;
bool neueZeile;


void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  // Serial1.begin(4800);
  Serial1.begin(4800, SERIAL_7E1);
}

void loop()
{
  readSerial1();
  if (neueZeile) printOut();
}

void zeileLeeren()
{
  charPos = 0;                               // Merker löschen
  memset(zeile, '\0', sizeof(zeile));        // Zeile leeren
}

void auswertung(char &myChar)
{
  switch (myChar)
  {
    case STX:                                // Start Message
      zeileLeeren();
      break;
    case  ETX:                               // wenn Ende Message
      Serial.print("ETX ");
      Serial.print(zeile);
      if (charPos == 1 &&                    // ACK Anforderung
          zeile[0] == ENQ)                   // muss das Zeichen vorher stimmen
      {
        Serial1.write(ACK);                  // Antwort
        Serial.println(F("ACK gesendet"));
      }
      else if (charPos > 1 &&                // oder lange Zeile
               zeile[charPos - 1] == LF)     // dann war vorher Zeilenende?
      {
        Serial1.write(ACK);                  // Antwort
        Serial.println(F("Zeilen ACK gesendet"));
      }
      else // Dieser Teil kann evtl. ausgeklammert werden
      {
        Serial.println(F("falsches MessageEnde erkannt"));
        for (byte b = 0; b < sizeof(zeile); b++)  // Ausgabe der fehlerhaften zeile
          hexPrint(zeile[b]);
        Serial.println();
        zeileLeeren();
      }
      break;
    case NUL:                                // Einleitung zu druckende Zeile
      if (!strcmp(zeile, printSeq))
      {
        Serial.println(F("Druckzeile kommt"));
        zeileLeeren();
      }
      break;
    case CR:
      strncpy(ausgabe[ausgabePos], zeile,
              sizeof(ausgabe[ausgabePos]));  // Zeile geht in Ausgabeblock
      ausgabePos++;                          // Nächste Zeile festlegen
      if (ausgabePos >= displayZeilen)       // Größer als der Block?
        ausgabePos = 0;                      // Dann fang an von vorn
      neueZeile = true;                      // Ausgabe anmelden
      break;
    default:
      zeile[charPos] = myChar;               // Zeile füllen
      charPos++;
      break;
  }
}
//
void readSerial1()
{
  if (Serial1.available() > 0)
  {
    char readChar = Serial1.read();
    auswertung(readChar);
  }
}
//
void hexPrint(const char zeichen)
{
  Serial.print("0x");
  if (zeichen < 15)
    Serial.print('0');
  Serial.print(zeichen, HEX);
  Serial.print(", ");
}
//
void printOut()
{
  // Gibt alle Zeilen aus - die neueste als Letzte
  uint8_t myPos = ausgabePos;                   // Zwischenspeicher
  if (myPos == 0)                               // Speicher ist gerade umgelaufen
  {
    for (; myPos < displayZeilen; myPos++)
      Serial.println(ausgabe[myPos]);
  }
  else                                          // Ausgabe von / bis
  {
    for (; myPos < displayZeilen; myPos++)      //
      Serial.println(ausgabe[myPos]);
    for (myPos = 0; myPos < ausgabePos; myPos++)
      Serial.println(ausgabe[myPos]);
  }
  Serial.println();
  neueZeile = false;
}

Ich war eben mit dem geistigen Input von noiasca in Post #3 beschäftigt und hab jetzt erst gelesen, dass Du hier Code geposted hattest. Respekt! Ich bin für jeden Input dankbar! Ich bin aber auch keinen Falls abgeneigt Tutorials durchzuarbeiten. "Learning" geht halt nicht ohne "doing".
C/C++ ist für mich schwierig zu verstehen da ich mit Assembler auf HC(S)08 Prozessoren angefangen habe. C/C++ lesen und halbwegs verstehen geht ja noch aber schreiben und das auch noch wenn man die Befehle nicht alle weiss/kann ist für mich noch ziemlich heavy.

Ich werde Deinen Code gleich mal durcharbeiten. Herzlichsten Dank auf jeden Fall! Das ist eine große Hilfe!

Beste Grüße,

Wie gesagt, ist noch nicht ganz komplett.
Zwischen dem Punkt, wo festgestellt wird, das das nächste eine zu druckende Zeile und der Übergabe dieser an die Ausgabe, fehlt noch eine Plausibilitätsprüfung.
Ich will erstmal nur wissen, ob die Ausgaben kommen da Du in deinem Ausgangspost ja mit der Druckzeile Deine Probleme hattest.

Da hab ich mal eine "Gute Nacht Lektüre" - Jeden Abend ein paar Seiten und nur wissen, was drinn steht....
Hier das pdf runterladen. :slight_smile:

Danke für den Link! Das ist genau der richtige Anstoß den ein Uhrwerk braucht um zu ticken zu beginnen. Die Ausgaben kommen an. Danke dafür! An der Formatierung will ich nochwas feilen und würde später nochmal hier hin kommen um zu Fragen wenn ich muss/darf...

Danke nochmal und

Beste Grüße,

Dann ist hier die Reise erstmal zu Ende.
Die Plausibilität solltest noch einbauen.
Freut mich, geholfen zu haben.

Na denne.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.