MAX485 TTL to RS-485 Modules for soil NPK sensor

Ok, so here's a different version of the original code that now uses the AltSoftSerial library from PJRC - see link in code.

// Crude demo code to read NPK Soil sensor based on the How 2 Electronics code at
// https://how2electronics.com/measure-soil-nutrient-using-arduino-soil-npk-sensor/
// but without the display.
//
// Use with caution as I don't have the real sensor, just simulated it using WinModbus.
//
// Uses PJRC AltSoftSerial library which is better than the standard SoftwareSerial library
// Get it here: https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
//
// All pin numbers are for an Arduino UNO.

#include <AltSoftSerial.h>

// RO to pin 8 & DI to pin 9 when using AltSoftSerial
#define RE 6
#define DE 7

const byte nitro[] = {0x01, 0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c};
const byte phos[] = {0x01, 0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc};
const byte pota[] = {0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0};

byte values[11];
AltSoftSerial mod;

void setup() {
  Serial.begin(9600);
  mod.begin(9600);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);

  // put RS-485 into receive mode
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  delay( 1000 );
}

void loop() {
  byte val1, val2, val3;
  Serial.print("   Nitrogen: ");
  val1 = nitrogen();
  Serial.print(" = ");
  Serial.print(val1);
  Serial.println(" mg/kg");
  delay(250);

  Serial.print("Phosphorous: ");
  val2 = phosphorous();
  Serial.print(" = ");
  Serial.print(val2);
  Serial.println(" mg/kg");
  delay(250);

  Serial.print("  Potassium: ");
  val3 = potassium();
  Serial.print(" = ");
  Serial.print(val3);
  Serial.println(" mg/kg");
  Serial.println();
  Serial.println();
  delay(5000);
}

byte nitrogen() {
  // clear the receive buffer
  mod.flushInput();

  // switch RS-485 to transmit mode
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);

  // write out the message
  for (uint8_t i = 0; i < sizeof(nitro); i++ ) mod.write( nitro[i] );

  // wait for the transmission to complete
  mod.flush();
  
  // switch RS-485 to receive mode
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  // crude delay to allow response bytes to be received!
  delay(100);

  // read in the received bytes
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

byte phosphorous() {
  mod.flushInput();
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);
  for (uint8_t i = 0; i < sizeof(phos); i++ ) mod.write( phos[i] );
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  delay(100);
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

byte potassium() {
  mod.flushInput();
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);
  for (uint8_t i = 0; i < sizeof(pota); i++ ) mod.write( pota[i] );
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  delay(100);
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

The output from the code when talking to the simulated sensor (using WinModbus) now looks like:

   Nitrogen: 1 3 2 0 1 79 84  = 1 mg/kg
Phosphorous: 1 3 2 0 2 39 85  = 2 mg/kg
  Potassium: 1 3 2 0 3 F8 45  = 3 mg/kg

   Nitrogen: 1 3 2 0 1 79 84  = 1 mg/kg
Phosphorous: 1 3 2 0 2 39 85  = 2 mg/kg
  Potassium: 1 3 2 0 3 F8 45  = 3 mg/kg

   Nitrogen: 1 3 2 0 1 79 84  = 1 mg/kg
Phosphorous: 1 3 2 0 2 39 85  = 2 mg/kg
  Potassium: 1 3 2 0 3 F8 45  = 3 mg/kg

At least now the response is working correctly. I don't know why there was a problem with the original SoftwareSerial code. The original author must have got it working so maybe an update to the library broke something along the way.

EDIT: I tried a slightly different Modbus simulator called ModRSsim2 and had to tweak the crude delay to 200ms before reading in the data, otherwise it always reported back 0xFF (= -1) indicating that there was no data to read.