Boron Sensor using RS485

Hi @rickkas7 @ScruffR @peekay123

The last post got locked before I had the chance to reply / report back.
I grabbed the boards @peekay123 recommended for talking to RS485 sensor using Boron.

Code is compiling and I am getting data from the sensor but want to run the schematic and updated code by you guys for a sanity check :slight_smile:

#include <Particle.h>
#include <SerialBufferRK.h>

// SYSTEM_MODE(MANUAL);
// SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(DISABLED);

SerialBuffer<256> rs485Buffer(Serial1); // use serial1 (D9/D10 tx/rx) for rs485 communication

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];

byte nitrogen() {
  delay(100);
  for (byte i = 0; i < sizeof(nitro); i++) {
    rs485Buffer.write(nitro[i]);
  }
  delay(100);
  if (rs485Buffer.available() >= sizeof(nitro)) {
    for (byte i = 0; i < 7; i++) {
      values[i] = rs485Buffer.read();
      //Serial.print(values[i], HEX);
    }
    //Serial.println();
  }
  return values[4];
}

byte phosphorous() {
  delay(100);
  for (byte i = 0; i < sizeof(phos); i++) {
    rs485Buffer.write(phos[i]);
  }
  delay(100);
  if (rs485Buffer.available() >= sizeof(phos)) {
    for (byte i = 0; i < 7; i++) {
      values[i] = rs485Buffer.read();
      //Serial.print(values[i], HEX);
    }
    //Serial.println();
  }
  return values[4];
}

byte potassium() {
  delay(100);
  for (byte i = 0; i < sizeof(pota); i++) {
    rs485Buffer.write(pota[i]);
  }
  delay(100);
  if (rs485Buffer.available() >= sizeof(pota)) {
    for (byte i = 0; i < 7; i++) {
      values[i] = rs485Buffer.read();
      //Serial.print(values[i], HEX);
    }
    //Serial.println();
  }
  return values[4];
}

void setup() {
  Serial.begin(9600);
  delay(2500); // allow time to open serial port

  Serial1.begin(9600);
  rs485Buffer.setup();
  delay(1000);
  Serial.println();
}

void loop() {
  // turn on power to rs485 via D11
  pinMode(D11, OUTPUT);
  digitalWrite(D11, HIGH);
  delay(1500);

  // turn on step-up-converter by setting enable to low via D8
  pinMode(D8, OUTPUT);
  digitalWrite(D8, HIGH);
  delay(1500);

  for (int counter = 0; counter <= 5; counter++){
      byte val1, val2, val3;
  val1 = nitrogen();
  delay(250);
  val2 = phosphorous();
  delay(250);
  val3 = potassium();
  delay(250);

  Serial.print("Nitrogen: ");
  Serial.print(val1);
  Serial.println(" mg/kg");

  Serial.print("Phosphorous: ");
  Serial.print(val2);
  Serial.println(" mg/kg");

  Serial.print("Potassium: ");
  Serial.print(val3);
  Serial.println(" mg/kg");
  Serial.println();

  // convert values to strings
  String nitrogenValue = String(val1);
  String phosphorousValue = String(val2);
  String potassiumValue = String(val3);
  delay(2500);

    if (counter == 5) {
      Particle.publish("NPK-Nitrogen", nitrogenValue, PRIVATE);
      Particle.publish("NPK-Phosphorous", phosphorousValue, PRIVATE);
      Particle.publish("NPK-Potassium", potassiumValue, PRIVATE);
  
      Serial.println("[ULTRA-LOW-POWER-SLEEP]");
      Serial.println("Going to Sleep.....");
      Particle.disconnect();
      delay(5000);
      SystemSleepConfiguration config;
      config.mode(SystemSleepMode::ULTRA_LOW_POWER).duration(1440min);
      System.sleep(config);
      Serial.println("Awake from Sleep, Restarting Device.....");
      System.reset(); // code execution starts back in void setup()
    }
  }
}

I am using a step-up-converter since the sensor requires 12V.

@babsndeep, some thoughts:

Regarding the schematic:

  • Does the Boost w/EN (3.3-12v) have a built-in pull-up resistor on the EN pin. If not, you should add one.
  • How is the unit powered? Only via the CR123A? If so, at 3V it will not be enough to power the Boron. You show 3.3v-4.2v so not sure what battery you intend to use and if it is being charged via USB or other method.
  • I assume the NPK RS485 box is your sensor powered via 12Vdc, correct? How far is the sensor from the Boron?
  • Why is D11 powering Vcc of the TTL-RS485 module? The GPIO output current on the Boron is likely not high enough to power the module.

Regarding the code:

  • You have pinMode() in loop() which is not necessary since ULTRA_LOW_POWER sleep mode maintains GPIO settings and states. However, since you so a System.reset() after sleeping, it is "good form" to put single run code, such as the pinMode() commands in setup().
  • You should consider a single function for sending/receiving to the sensor. The function should have two arguments: a pointer to the command bytes array and a pointer to a values array. The function would use the command pointer to output the command and then use the values pointer to receive the data. However, I notice you only return values[4] indicating that the other received bytes may be response bytes such as address or ack/nack. You don't validate any of that before "accepting" the last byte.
  • To reduce cloud operations, you may want to have a single publish and combine the values into a single c-string using snprintf() for example.
  • You may want to wait for 'Particle.disconnected()` before sleeping. Alternatively, you could use Particle.setDisconnectOptions() to disconnect gracefully before sleeping.
3 Likes

@peekay123 @ScruffR @rickkas7

Schematic

  • No datasheet for the Boost unfortunately but I can see EN connected to an SMD resistor which I assume is the pull-up resistor.
  • Boron is powered by a 4.2V battery with its own charging circuit that's separate from the additional 4.2V that powers the Boost and NPK sensor with Boron I/O pins (D8) controlling the EN of the Boost.
  • Correct, NPK RS485 is sensor powered via 12VDC, less than 1FT from Boron.
  • (D11) is powering the TTL-RS485 chip for controlling ON/OFF. Should I switch the power for TTL-RS485 from Boron OI (can't find the current draw of the TTL-RS485) to Battery and control it using Boron IO using Transistor like for the Boost?

Code

  • Thanks for the single run code pointer, moving to setup().
  • Will do on single function with command and values array as well as validating.
  • The final code will combine publish.
  • Will do on disconnect before sleeping.

Thanks again for taking the time to help.
Looking forward to the response to above updates.