Serial Port Test Tool

I'm new here and to Arduino programming & hardware, and am looking forward to learning new skills!

I am working on a non-Arduino project that has to go out the PC (not Mac) USB port through a USB-to-serial converter to some unconventional hardware's serial port (9600,8,N1 communications protocol.).

I would like a piece of hardware that can accept what I send it, display it, and send it back to the PC. This will allow me to test the serial port, cable, and code, which a serial port sniffer cannot do.

[Update]
To be clear, my PC's program is opening the serial port and sending a text (or Hex) string out the serial port. The equipment I have is supposed to echo my request back, followed by the desired data.

The device I envision would accept the text string I send it via the USB port, through the serial converter, display what it received on its own simple display, and resend the string back out the same serial port, back to my PC, where I can verify it received the string I sent it. Thus, simulating bidirectional communications.
[End of Update]

Ideally, it would like to set the port speed and switch between characters and hex, but as a first step, I'll take 9600,8,N,1 and text communications.

Has this been done before? If so, can someone point me to an example. (My searches didn't turn up anything useful.) If it has not been done before, any tips on how to get started would be greatly appreciated!

Bill

There is a tutorial post on the forum all about Serial. That will probably be a good start.

I did a search with duckduckgo using " USB-to-serial converter" and got thousands of hits. some under $10.00 US.

Check the Arduino cookbook most of what you want is in there.

Search for logic analyzers that can display data.

Your topic does not indicate a problem with the Cloud Editor and therefore has been moved to a more suitable location on the forum.

1 Like

9600 bauds, 8N1 is very conventional, that's what you get on an Arduino when you do Serial.begin(9600);

2 Likes

@billre just trying to unpick your requirements here but correct me if I've got it wrong:

You want to use an Arduino to simulate this "unconventional hardware" using a serial port configured for 9600 8N1 - a pretty standard setting for a few decades now.

You want the Arduino to display (perhaps via a second serial port?) what it received from the PC?

The Arduino should respond back to the PC as if it were the "unconventional hardware"?

If so, then using an Arduino to simulate a piece of hardware has likely been done many times over - just not precisely as per your needs.

I would suggest starting by having a read of:

I don't know enough about your requirements to know if this would be an acceptable solution for testing.
You could use another USB-to-serial converter plugged into the same PC. Connect the serial converters to each other (Rx to Tx, Tx to Rx).
Open a terminal emulator on the PC to talk to the second converter.
The terminal emulator will display what the first converter sends, and allow you to type (copy / paste) to send back what was received.

2 Likes

Not pretty clear to me, sorry. For example, what do you mean with "what I send it"? Send data from what to what, and how? You mean type some data on the PC to be sent to Arduino? And "display it" what and where? The data you typed in? And where, on an LCD screen on the Arduino, or sent back via serial?

To help us better understand, I think a drawing (even a simple diagram drawn in pen on a sheet of paper, photographed, and posted here) could help us better than that description. Give it a try!

1 Like

would that meet your needs ?

the code opens up the Serial line at 9600, 8N1
it listens to what's coming in and echo it forward

so if you were to connect the Arduino Rx to the PC's Serial adaptor and the Arduino Tx to the "unconventional hardware's serial port Rx" then you would have a "man in the middle" sniffing what's going on. this would work on a Mac or PC or whatever appears as an UART running at 9600 bauds, 8N1.

Here I made the bytes being displayed on an LCD screen in a pretty crude way since it's scrolling so you can only see the last 4 bytes, not very useful but just a proof of concept

click to see the code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2025 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/


#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
const uint8_t nbCols = 20;
const uint8_t nbRows = 4;
hd44780_I2Cexp lcd;



void lcdLog(const char *format, ...) {
  static char framebuffer[nbRows][nbCols + 1];
  static byte currentLine = 0;
  va_list args;
  va_start(args, format);
  if (currentLine >= nbRows) {
    for (byte line = 1; line < nbRows; line++) strlcpy(framebuffer[line - 1], framebuffer[line], nbCols + 1); // shift lines up
    vsnprintf(framebuffer[nbRows - 1], nbCols + 1, format, args); // add the new line
    lcd.clear();
    for (byte line = 0; line < nbRows; line++) {
      lcd.setCursor(0, line);
      lcd.print(framebuffer[line]);
    }
  } else {
    vsnprintf(framebuffer[currentLine], nbCols + 1, format, args);
    lcd.setCursor(0, currentLine);
    lcd.print(framebuffer[currentLine]);
    currentLine++;
  }
  va_end(args);
}


void setup() {
  Serial.begin(9600); // 9600 bauds, 8N1
  int result = lcd.begin(nbCols, nbRows);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }
  lcd.clear();
  Serial.println("OK");
}

void loop() {
  if (Serial.available()) {
    byte r = Serial.read();
    Serial.write(r); // pass the byte down the chain

    if (isprint(r)) lcdLog("Hex: %02X, char: %c", r, (char) r);
    else {
      switch (r) {
        case 0x00: lcdLog("Hex: %02X, ctrl: NUL", r); break;  // Null
        case 0x01: lcdLog("Hex: %02X, ctrl: SOH", r); break;  // Start of Heading
        case 0x02: lcdLog("Hex: %02X, ctrl: STX", r); break;  // Start of Text
        case 0x03: lcdLog("Hex: %02X, ctrl: ETX", r); break;  // End of Text
        case 0x04: lcdLog("Hex: %02X, ctrl: EOT", r); break;  // End of Transmission
        case 0x05: lcdLog("Hex: %02X, ctrl: ENQ", r); break;  // Enquiry
        case 0x06: lcdLog("Hex: %02X, ctrl: ACK", r); break;  // Acknowledge
        case 0x07: lcdLog("Hex: %02X, ctrl: BEL", r); break;  // Bell
        case 0x08: lcdLog("Hex: %02X, ctrl: BS", r); break;   // Backspace
        case 0x09: lcdLog("Hex: %02X, ctrl: TAB", r); break;  // Horizontal Tab
        case 0x0A: lcdLog("Hex: %02X, ctrl: LF", r); break;   // Line Feed
        case 0x0B: lcdLog("Hex: %02X, ctrl: VT", r); break;   // Vertical Tab
        case 0x0C: lcdLog("Hex: %02X, ctrl: FF", r); break;   // Form Feed
        case 0x0D: lcdLog("Hex: %02X, ctrl: CR", r); break;   // Carriage Return
        case 0x0E: lcdLog("Hex: %02X, ctrl: SO", r); break;   // Shift Out
        case 0x0F: lcdLog("Hex: %02X, ctrl: SI", r); break;   // Shift In
        case 0x10: lcdLog("Hex: %02X, ctrl: DLE", r); break;  // Data Link Escape
        case 0x11: lcdLog("Hex: %02X, ctrl: DC1", r); break;  // Device Control 1
        case 0x12: lcdLog("Hex: %02X, ctrl: DC2", r); break;  // Device Control 2
        case 0x13: lcdLog("Hex: %02X, ctrl: DC3", r); break;  // Device Control 3
        case 0x14: lcdLog("Hex: %02X, ctrl: DC4", r); break;  // Device Control 4
        case 0x15: lcdLog("Hex: %02X, ctrl: NAK", r); break;  // Negative Acknowledge
        case 0x16: lcdLog("Hex: %02X, ctrl: SYN", r); break;  // Synchronous Idle
        case 0x17: lcdLog("Hex: %02X, ctrl: ETB", r); break;  // End of Block
        case 0x18: lcdLog("Hex: %02X, ctrl: CAN", r); break;  // Cancel
        case 0x19: lcdLog("Hex: %02X, ctrl: EM", r); break;   // End of Medium
        case 0x1A: lcdLog("Hex: %02X, ctrl: SUB", r); break;  // Substitute
        case 0x1B: lcdLog("Hex: %02X, ctrl: ESC", r); break;  // Escape
        case 0x1C: lcdLog("Hex: %02X, ctrl: FS", r); break;   // File Separator
        case 0x1D: lcdLog("Hex: %02X, ctrl: GS", r); break;   // Group Separator
        case 0x1E: lcdLog("Hex: %02X, ctrl: RS", r); break;   // Record Separator
        case 0x1F: lcdLog("Hex: %02X, ctrl: US", r); break;   // Unit Separator
        case 0x7F: lcdLog("Hex: %02X, ctrl: DEL", r); break;  // Delete
        default: lcdLog("Hex: %02X", r); break;
      }
    }
  }
}

1 Like

I'm not looking for a USB to serial converter, I have a hand full of those already. Re-read my post.

Thanks for the reply.

I updated my original post with the following. Hopefully that clears up what I'm looking to do.

Bill

[Update]
To be clear, my PC's program is opening the serial port and sending a text (or Hex) string out the serial port. The equipment I have is supposed to echo my request back, followed by the desired data.

The device I envision would accept the text string I send it via the USB port, through the serial converter, display what it received on its own simple display, and resend the string back out the same serial port, back to my PC, where I can verify it received the string I sent it. Thus, simulating bidirectional communications.
[End of Update]

How does it differ from the Communications/SerialPassthrough built-in-example?

https://docs.arduino.cc/built-in-examples/communication/SerialPassthrough/

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  if (Serial.available()) {        // If anything comes in Serial (USB),
    Serial1.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  }

  if (Serial1.available()) {       // If anything comes in Serial1 (pins 0 & 1)
    Serial.write(Serial1.read());  // read it and send it out Serial (USB)
  }
}

What sort of "simple display" do you envision?

You are describing a loop back module, but with a display. Not sure I've ever seen one off the shelf, but easy to create with an Arduino+ LCD.

Dave, thanks for the reply. Unfortunately, the solution you recommended won't work as the program that sends the data also must receive the reply via the same channel/port.

Bob, that's exactly what I need. Only I don't yet know enough about Arduino hardware and programming to pull it off. Certainly, someone must have done that before?

Sounds like:

void setup() {
  Serial1.begin(9600);
}

void loop() {
  if (Serial1.available()) 
  {        
    // If anything comes in Serial port, read it and send back

    char c = Serial1.read();
    Serial1.write(c);  

    // and also display on LCD
    lcd.print (c);
  }
}

edit; if you are receiving data by RS232 converter then best to avoid using Serial.

1 Like

Dave, that is close, but as I read it, it receives on one serial port and replies on a second port. I need it to reply out the same port it received the text from.

Now, I could be wrong....

It would receive the reply on the same COM port that it sent on, like this:

1 Like

Ok but we're just trying things but it's still an almost incomplete description of your goals.
Please answer my questions from post #9, including a drawing of the connections and data flow....

1 Like