Hiii! Can somebody help me out. I am trying to get the value from NPK sensor but it is returning 255 for all these N, P and K

I'm using this code
#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];
}```

Have a search of these forums for NPK Sensor and you will find several discussions, some quite lengthy, where there are comms issues such as you describe.

The code you posted looks like an early piece of code I posted some time ago.

You will get more assistance if you tell us:

  • which Arduino you are using
  • which RS485 module you are using
  • how you are powering your project
  • how you've connected the various parts together

You should also provide a link to the datasheet / user manual for your specific sensor. You need to make sure that this is for your sensor as there are several NPK sensors that use different registers.

1 Like

Arduino -- I'm using Arduino UNO board.
RS485 module -- MAX485 TTL to RS485 Converter Module
for powering I'm using SMPS which is able to control power supply 5 to 30V

Connections..
I have common ground for Arduino, RS485 and my powering device
VCC of RS485 connected to 5V Arduino pin
DE to 7
RE to 6
DI to 9
Ro to 8
NPK sensor connection
Yellow wire to A
Green wire to B
Red and black wire to my power supplier

Can you make a schematic of that please??

Thankyou for introducing me about schematic.. here is the connection schematic

I see you are using my diagram.

Do you have the user manual for your specific NPK sensor? Can you upload or provide a link to it?

Do read those previous threads.

I'm willing to bet you're yet another victim of those cheap and quite obviously fake NPK sensors that seem to be all over the place these days.

1 Like

Ya...
May be

Here is the manual of NPK sensor
LNPK -101 MANUAL.pdf (3.6 MB)

Yes, those are fake. Impossible for them to do what they claim to do.

Just in case you want to continue with that type of sensor, you should note from the manual that the Nitrogen, Phosphorous & Potassium are held in registers 0, 1 & 2. You need to change this bit of the code you are using to insert the correct register addresses into the canned modbus messages and then recalculate the CRC16 checksums for each one:

Of course you could always send out the message in section 7.2 of the user manual that asks for all 3 values in one go.

I suggest to replace the code with calls to random(), as the resulting data will be just as meaningful.

But less fun than sticking impressive looking probes into your plant pot, of course.

2 Likes

ok, Thankyou for your help I will try it and then update you about this.

Ok, thanks I will try

I change it like this can you please tell, Is it right or not.
Screenshot 2024-01-24 110700

if it is not right, can you please provide me a modified code according to my sensor

That's the correct message, but you only heed 1 of them. That message will ask for all 3 readings to be provided in one response.

You might want to change the name of the array to something like npk[] to avoid future confusion.

As all 3 parameters will be returned in one response, you will need to modify the code that extracts the values.

Note also that my original code has a flaw in that it only returns a byte, but should return a 16-bit value instead.

Thankyou, dude for your help I tried everything but it is not working.

The problem you have is that there are a lot of unknowns in your setup. I would suggest you invest in an RS485-USB adapter dongle for your PC/laptop. They are cheap and invaluable when in situations such as yours where nothing seems to work.

This allows you to use one of the free Windows programs to communicate with your sensor using the modbus protocol. The only wires you would need are from the RS485-USB dongle to your sensor and the power supply to your sensor.

Give this a try..
Think I've adjusted to your setup, should use broadcast address to query sensor..
Could just be your sensor is not on address 1..

#include <AltSoftSerial.h>

// RO to pin 8 & DI to pin 9 when using AltSoftSerial
#define RE 6
#define DE 7
#define BUF_SIZE 20
#define TIMEOUT  100
#define USE_CAST true

#define NITRO 0
#define PHOS  1
#define POTA  2

AltSoftSerial mod;


//all together.. 3 in 1, first 3 registers from device address 1..
const byte dataMod[3][8] = {
  {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A},//nitro
  {0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0xD5, 0xCA},//phos
  {0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x25, 0xCA} //pot
};

//same but address 255 (broadcast) any connected sensor
//should respond, the sensor will replace the 255 with their
//currently configured address, change USE_CAST to true to use
const byte dataMod_B[3][8] = {
  {0xFF, 0x03, 0x00, 0x00, 0x00, 0x01, 0x91, 0xD4},//nitro
  {0xFF, 0x03, 0x00, 0x01, 0x00, 0x01, 0xC0, 0x14},//phos
  {0xFF, 0x03, 0x00, 0x02, 0x00, 0x01, 0x30, 0x14}//pot
};

//incoming buffer
byte buf[BUF_SIZE];

void setup() {
  Serial.begin(9600);
  //check different bauds if no reply, seen them at 4800..
  mod.begin(9600);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  Serial.println("Ready..");
}

void loop() {
  uint16_t val;
  Serial.println("Nitrogen (N): ");
  val = GetModVal(NITRO);
  Serial.print(val);
  Serial.println(" mg/kg\n");
  Serial.println("-----");
  delay(1000);

  Serial.println("Phosphorous (P): ");
  val = GetModVal(PHOS);
  Serial.print(val);
  Serial.println(" mg/kg\n");
  Serial.println("-----");
  delay(1000);

  Serial.println("Potassium (K): ");
  val = GetModVal(POTA);
  Serial.print(val);
  Serial.println(" mg/kg\n");
  Serial.println("-----");

  delay(5000);

}

uint16_t GetModVal(byte val) {
  uint32_t startTime = 0;
  uint8_t  byteCount = 0;
  memset(buf, 0, sizeof(buf)); //empty incoming..
  //send request..
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (USE_CAST)
    mod.write(dataMod_B[val], sizeof(dataMod_B[val]));
  else
    mod.write(dataMod[val], sizeof(dataMod[val]));
  mod.flush();//wait for outgoing to be sent..
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  //recv response until timeout expires..
  Serial.print("Response in HEX: ");
  startTime = millis();
  while (millis() - startTime <= TIMEOUT) {
    if (mod.available() && byteCount < sizeof(buf)) {
      buf[byteCount++] = mod.read();
      printHexByte(buf[byteCount - 1]);
    }
  }
  Serial.println();
  //combine 2 bytes into the returned word..
  return (uint16_t)(buf[3] << 8 | buf[4]);
}

void printHexByte(byte b)
{
  Serial.print(b, HEX);
  Serial.print(':');
}

good luck.. ~q

Please do not advice OP to invest more money in this.

Much better: return the thing to sender, and try to get a refund. These sensors are FAKE. There is NO way they can do what they claim they do. Just ask anyone with a basic background in (soil) chemistry and they can easily enough give you several reasons it CAN NOT WORK.