NPK soil sensor to much variations in the output

I am using Arduino UNO with a MAX485 module to interface the NPK sensor which supports 12 v to 24v.
Below is the Arduino script I am applying to get the output value of NPK

#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(3000);
}
 
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(3000);
}
 
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();
  
  // switching RS485 to receive mode
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
 
  // 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 to allow response bytes to be received!
  //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 to allow response bytes to be received!
  //delay(100);
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

Please suggest what is the correct way to get the correct NPK values.

Please suggest what is wrong with the code you have already written?

As I am getting continuous NPK output as 255, 255, 255 from the above code.

Per AltSoftSerial Library, for an extra serial port

mySerial.read();

Reads the next byte from the port. If nothing has been received, -1 is returned.

A -1 is cast to 255 when you store it in a byte variable. Maybe you need to check mod.available() before you attempt to read,

Ok sure. Thank you. But if I am receiving 0, 0, 0, 0 values then? This value is the Hexa value.

Thanks in advance

What does that mean?

The point is you should not read data that is not present... wait for .available > 0 before starting to read.

What data are you expecting from the sensor?

This is the current value that I am receiving from the NPK sensor.

I have put the sensor into the soil which is powered with a 12v DC supply.

I need a soil NPK value correctly. which not to be many variations. such as If the current NPK value is 60, 75, or 80 then it should not change with many variations. Hope I clearly define the problem

Yes we understand the problem... and you have been told how to fix it. READ post #5 and #7.

Study this...

#include <SoftwareSerial.h>

SoftwareSerial mySerial (2,3);

void setup()
{
  Serial.begin(115200);
  mySerial.begin(9600);

  byte x = mySerial.read();

  Serial.print("x = ");  
  Serial.println(x);  
}

void loop()
{} 

This is the output... does the result look similiar to yours? Do you see why?

20:07:57.500 -> x = 255

Firstly, how have you wired up your NPK sensor, your RS485 board and your UNO?

Secondly, and it's not your fault, but the NPK code circulating the web and also repeated on this forum is garbage.

Thirdly, and my apologies here for what looks like my code that you are using. I modified the original NPK code before I really understood what was going on.

You have commented out the delay(100) in all 3 parameter reading routines. This was a hack to allow the sensor to respond before reading in the response.

As others have pointed out, you are assuming that the sensor response is instantly available once you ask for it.

Have a look at post #14 in this discussion:

Yes, now I am using the same code which you have posted #14. But I am receiving the value


Please help

Thanks in advance

It can be a hardware problem also. ?

My code from post #14 prints out the received bytes. I don't see any in your output.

Please detail how you have wired up you setup. Not photos.

I am using the RS485 module in which the RE pin is connected to Arduino UNO D7, the same as the DE pin is connected to D6, the R0 pin is connected to D8, and the DI pin is connected to D9. And NPK sensor yellow A pin is connected with RS485 A pin, and B blue is connected with B pin

Do you have a common GND between your UNO, RS485 module and your NPK sensor?

No, NPK sensor GND and 12v power wire are connected with a 12V DC power supply, and RS485 GND is connected with Arduino UNO GND

The photos you posted are next to useless. People are trying to understand how things are connected...

What do you think this shows?

Sorry for my mistake I am new in hardware and electronics, I just show I am using the RS485 module to connect the NPK sensor with Arduino UNO. If its confusing I will remove this picture

People are trying to help you but you are not listening to what they are saying.

Do you understand why you were receiving 255 previously?

Do you have new code now? Can you post it so we have some idea what issues you are now facing.

If you want help... you need to read peoples replies.

This is my new code now as suggested by @markd833.

`#include <SoftwareSerial.h>

#define RE 7
#define DE 6

const uint32_t TIMEOUT = 500UL;

//const byte code[]= {0x01, 0x03, 0x00, 0x1e, 0x00, 0x03, 0x65, 0xCD};
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];
SoftwareSerial mod(8, 9); // Rx pin, Tx pin

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

  delay(500);
}

void loop() {
  byte val1, val2, val3;

  Serial.print("Nitrogen: ");
  val1 = nitrogen();
  Serial.print(val1);
  Serial.print(" mg/kg\n\n");
  delay(1000);

  Serial.print("Phosphorous: ");
  val2 = phosphorous();
  Serial.print(val2);
  Serial.print(" mg/kg\n\n");
  delay(1000);

  Serial.print("Potassium: ");
  val3 = potassium();
  delay(1000);
  Serial.print(val3);
  Serial.print(" mg/kg\n\n");

  delay(5000);
}

byte nitrogen() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  mod.write(nitro, sizeof(nitro));
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  startTime = millis();
  while ( millis() - startTime <= TIMEOUT ) {
    if (mod.available() && byteCount<sizeof(values) ) {
      values[byteCount++] = mod.read();
      printHexByte(values[byteCount-1]);
    }
  }
  Serial.println();
  return values[4];
}

byte phosphorous() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  mod.write(phos, sizeof(phos));
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  startTime = millis();
  while ( millis() - startTime <= TIMEOUT ) {
    if (mod.available() && byteCount<sizeof(values) ) {
      values[byteCount++] = mod.read();
      printHexByte(values[byteCount-1]);
    }
  }
  Serial.println();
  return values[4];
}

byte potassium() {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  mod.write(pota, sizeof(pota));
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  startTime = millis();
  while ( millis() - startTime <= TIMEOUT ) {
    if (mod.available() && byteCount<sizeof(values) ) {
      values[byteCount++] = mod.read();
      printHexByte(values[byteCount-1]);
    }
  }
  Serial.println();
  return values[4];
}

void printHexByte(byte b)
{
  Serial.print((b >> 4) & 0xF, HEX);
  Serial.print(b & 0xF, HEX);
  Serial.print(' ');
}`

I have read all replies and tried with respect to that. please read the post #16, #15, #14

Thank you for the correction. @red_car

@thinktocodeit the code that you have is a poor mans hack compared to a proper modbus library. It doesn't perform any sanity check on the received data. You need to be aware of that.

It will also help you understand where the problem(s) may be if you know what the code is trying to do.