Modbus ASCII Protocol on UNO

In my project, I am using Modbus ASCII protocol with an arduino uno, MAX485, with 7 data bits and even parity. There are few options for this type, so I simply want to hard-code reading a register.

The server id is 75
The function code is 0x04 (input register)
The register # is 30001 (datasheet)

Here is my code. Note that I am using PuTTY to see the data being sent/response as the serial monitor cannot handle SERIAL_7E1.

'''
// Calculate LRC (Longitudinal Redundancy Check)
byte calculateLRC(String data) {
byte sum = 0;

for (int i = 0; i < data.length(); i++) {
sum += data[i]; // Add the ASCII values of each character
}

// Return the LRC (two's complement of the sum)
byte lrc = (~sum + 1) & 0xFF;
return lrc;
}

void setup() {
// Initialize RE/DE pin (pin 2) to control RS-485 transmission/reception
pinMode(2, OUTPUT); // Set pin 2 as OUTPUT for controlling RE/DE

Serial.begin(19200); // Set baud rate to 19200
Serial.begin(19200, SERIAL_7E1); // 7 data bits, Even Parity, 1 stop bit

String slaveID = "4B";
String functionCode = "04";
String startRegister = "9C40"; // Address of the Input Register (30001 -> 9C40
String quantity = "0001"; // 1 register
String message = ":" + slaveID + functionCode + startRegister + quantity;

byte lrc = calculateLRC(message);
char lrcHex[3];
sprintf(lrcHex, "%02X", lrc);

// Append the LRC to the message
message += lrcHex;

// Append carriage return and line feed
message += "\r\n";

// Enable Transmission by setting RE/DE HIGH
digitalWrite(2, HIGH);
Serial.print(message); // Send message
delay(2000);

digitalWrite(2, LOW); // Disable the transmitter (DE), enable receiver (RE)

}

void loop() {
if (Serial.available()) {
String response = "";

// Read response 
while (Serial.available()) {
  response += (char)Serial.read();
}

// Display response
Serial.print("Response: ");
Serial.println(response);

// : [Slave ID] [Function Code] [Data] [LRC] <CR><LF>
// Extract  data (after function code) and print the register value
if (response.length() > 5) {
  String data = response.substring(4, 8); // Extract the data bytes
  unsigned int registerValue = strtol(data.c_str(), NULL, 16);  // Convert from hex to integer
  Serial.print("Register Value: ");
  Serial.println(registerValue);
} else {
  Serial.println("Error: Invalid response");
}

}
}
'''
The problem is that I'm not getting anything on the serial monitor -- it seems to be stuck in the loop. Is there an easily spotted problem in the code? Or, is there a library anyone is aware of that works with arduino uno AND modbus ascii?

Input register 30001 is 0x0000 in hex, not 9C40.
I have never played with ascii, but I would be surprised if there's not a library compatible with uno.

Oh! That's really helpful.

Here's my updated code (still having problems - the Serial.availabe() line is never true). Note, I also changed to have separate RE & DE connections to ensure that was not an issue, as well as switched to using SoftwareSerial such that the serials were separated on the uno board. Additionally, I have been looking for the past week, and have

#include

SoftwareSerial mySerial(11, 10);

// Function to calculate LRC (Longitudinal Redundancy Check)
byte calculateLRC(String data) {
byte sum = 0;

// Loop through each character in the data string
for (int i = 0; i < data.length(); i++) {
sum += data[i]; // Add the ASCII values of each character
}

// Return the LRC (two's complement of the sum, masked to 1 byte)
byte lrc = (~sum + 1) & 0xFF;
return lrc;
}

void setup() {
// Initialize RE/DE pin (pin 2) to control RS-485 transmission/reception
pinMode(2, OUTPUT); // Set pin 2 as OUTPUT for controlling RE/DE
pinMode(4, OUTPUT);

// Start Serial communication at 19200 baud, 7 data bits, even parity
mySerial.begin(19200); // Set baud rate to 19200
// Serial.swap(); // Swap the default UART for compatibility with specific setups if needed

// Setup the Serial with 7 data bits and even parity
Serial.begin(19200, SERIAL_7E1); // 7 data bits, Even Parity, 1 stop bit

// Slave ID (75) in ASCII hex: 4B
String slaveID = "4B";

// Function Code (Read Input Registers) in ASCII hex: 04
String functionCode = "04";

// Start Register (30001) in ASCII hex: 9C40 (Subtract 1 from the actual register)
String startRegister = "0000"; // Address of the Input Register (30001 -> 0x0000)

// Quantity of Registers to read: 1
String quantity = "0001"; // 1 register

// Construct the Modbus ASCII message without LRC
String message = ":" + slaveID + functionCode + startRegister + quantity;

// Calculate the LRC for the message
byte lrc = calculateLRC(message);

// Convert the LRC to two-character hex string
char lrcHex[3];
sprintf(lrcHex, "%02X", lrc);

// Append the LRC to the message
message += lrcHex;

// Append carriage return and line feed
message += "\r\n";

// Send the message to the serial port (RS-485)

// Enable Transmission by setting RE/DE HIGH
digitalWrite(2, HIGH); // Enable the transmitter (DE)
digitalWrite(4, HIGH);
mySerial.print(message); // Send the message

// Wait a moment to ensure transmission finishes
delay(2000);

// Disable Transmission by setting RE/DE LOW (ready to receive)
digitalWrite(2, LOW); // Disable the transmitter (DE), enable receiver (RE)
digitalWrite(4, LOW);

}

void loop() {
// Check for incoming response from the slave device

if (mySerial.available()) {
String response = "";

// Read the response (we expect a response of at least 5 bytes)
while (mySerial.available()) {
  response += (char)mySerial.read();
  Serial.print("-");
}

// Display the response
Serial.print("Response: ");
Serial.println(response);

// Assuming the response format is:
// : [Slave ID] [Function Code] [Data] [LRC] <CR><LF>
// Extract the data (after function code) and print the register value
if (response.length() > 5) {
  String data = response.substring(4, 8); // Extract the data bytes
  unsigned int registerValue = strtol(data.c_str(), NULL, 16);  // Convert from hex to integer
  Serial.print("Register Value: ");
  Serial.println(registerValue);
} else {
  Serial.println("Error: Invalid response");
}

}
Serial.print(".");
delay(500);
}

please read in the forum introduction how to post code:

afterwards edit your posts and format your code correct in code tags.

After you have updated your code to become readable, also explain how is your setup.
What is this modbus server? Do you have some protocol sheet?
You have softwareserial assigned to pins 11 and 10 with default 8N1.
You have hardwareserial (which is available on USB) set with 7E1.
What's the logic here?