Average rainfall 2001-2016, global tropics

Map: Average rainfall 2001-2016, global tropics

sketch: rs485/MODBUS NPK

Thomas Gumbricht bio photo By Thomas Gumbricht
/*
 * Initial test program for
 * Adafruit Feather nRF52840 with XSPECLUM01 board.
 *
 * Test:
 * - rs485 communication with NPK+pH+SM-EC sensor, ModbusMaster
 *
 * Note: the feather needs to be removed from the board when updated,
 * since the bootloader does not set nKILL high (which will turn off the device after a few hundreds of ms).
 *
 *
 * Arduino IDE installation:
 * ========================
 *     Download and install the Arduino IDE (At least v1.8)
 *     Start the Arduino IDE
 *     Go into Preferences
 *     Add https://adafruit.github.io/arduino-board-index/package_adafruit_index.json as an 'Additional Board Manager URL'
 *     Restart the Arduino IDE
 *     
 *     Open the Boards Manager option from the Tools -> Board menu and install 'Adafruit nRF52 by Adafruit'
 *     Once the BSP is installed (takes long time with a long delay in the middle), select
 *     Adafruit Bluefruit nRF52840 Feather Express (for the nRF52840) from the Tools -> Board menu
 *     
 *
 *
 * To update the bootloader:
 * =========================
 * Step 1:
 * Tools -> Board: Adafruit Feather nRF52840 Express
 * select "Bootloader DFU for Bluefruit nRF52" for Tools->Programmer
 * Select the right com port
 * Tools->Burn Bootloader
 *
 * Step 2:
 * Double-click the Reset button. NeoPixel turns green.
 * Drag the downloaded .uf2 file to FTHR840BOOT. The LED will flash.
 *
 */

#define DAC6571_ADDR 0x4C

#define BNC               A0
#define SPECTRO_AN        A1 // The analog video signal for the spectrometer
#define GX16_AN           A2 // The GX16 analog sensor signal
#define nKILL             17
#define nPBINT            18
#define ONEWIRE           19

#define GPIOSCK           26  // NC
#define nRE               25
#define GPIOMISO          24
#define GPIORX            1
#define GPIOTX            0
#define GPIOD2            2

#define SPECTRO_CLK       13
#define SPECTRO_ST        12
#define SPECTRO_TRG       11
#define SPECTRO_EOS       10
#define SPECTRO_BOOST_EN  9

#define LED_BUCK_EN       6
#define LED_PULSE         5

#define GPIOSCL           23
#define GPIOSDA           22

#define USERSWITCH        7
#define BATTERYV2         A6
#define NEOPIXEL          8

#define SPECTRO_CHANNELS          256 // Nr of spectral channels in sensor
#define SPECTRO_START_CHANNEL     64 // First channel with valid data
#define SPECTRO_END_CHANNEL       256 // Last channel with valid data
#define SPECTRO_integration_time  300 // Integration time for spectral sensor sampling ("expsoture rime")

uint16_t data[SPECTRO_CHANNELS];

#include <Adafruit_NeoPixel.h>    //  Library that provides NeoPixel functions

// -- Create a NeoPixel object called onePixel that addresses 1 pixel in pin 8
Adafruit_NeoPixel rgbPixel = Adafruit_NeoPixel(1, 8, NEO_GRB + NEO_KHZ800);

#include <Wire.h>                 // Library
#include "SHT2x.h"                // Library for in-box temperature and relaive humidity

// -- Create a SHT2x object called sht for accessing the in-box Temperature and Relative Humidity
SHT2x sht;

/* ModbusMaster For communication with RS485+MODBUS sensors */
#include <ModbusMaster.h>  

/* tinyusb is for the serical connection with Adafruit nRF52 boards */
#if defined(USE_TINYUSB)
#include <Adafruit_TinyUSB.h> // for Serial
#endif

/* Setup the Modbus transmission basics */

void PreTransmission(){
  // Set transmit mode
  digitalWrite(nRE, HIGH);
}

void PostTransmission(){
  // Set receive mode
  digitalWrite(nRE, LOW);
}

// instantiate ModbusMaster object
ModbusMaster node;

/* END - Setup the Modbus transmission basics */

void setup() {

  pinMode(BNC,      INPUT);  // BNc connection - usually an Ion Selecteve Electrode (ISE)
  pinMode(SPECTRO_AN,   INPUT);  // Spectro video analog signal
  pinMode(GX16_AN,      INPUT);  // Aalog signal from GX16 expansion socket)
  pinMode(nKILL,    OUTPUT); // #KILL
  pinMode(nPBINT,   INPUT);  // #PBINT (pushbutton)
  pinMode(ONEWIRE,   INPUT);  // 1W interface (pulled up to 3v3 by 2k2)
  pinMode(SCK,      OUTPUT); // - (not connected)
  pinMode(nRE,      OUTPUT); // #RE (Receive enabled, RS485)
  pinMode(GPIOMISO, OUTPUT); // - (not connected)
  pinMode(GPIORX,   INPUT);  // Rx (Uart)
  pinMode(GPIOTX,   OUTPUT); // Tx (Uart)
  pinMode(GPIOD2,   OUTPUT); // - (not connected)

  pinMode(SPECTRO_CLK,   OUTPUT); // Spectrometer clock pulse
  pinMode(SPECTRO_ST,    OUTPUT); // Spectrometer start pulse
  pinMode(SPECTRO_TRG,   INPUT);  // Spectrometer trigger pulse
  pinMode(SPECTRO_EOS,   INPUT);  // SPECTRO_EOS
  pinMode(SPECTRO_BOOST_EN, OUTPUT); // Spectrometer end of scan

  pinMode(LED_BUCK_EN,  OUTPUT); // LED_BUCK_EN
  pinMode(LED_PULSE,    OUTPUT); // LED_PULSE

  pinMode(GPIOSCL,  INPUT);  // SCL
  pinMode(GPIOSDA,  INPUT);  // SDA

  pinMode(USERSWITCH,   INPUT);  // User switch

  pinMode(A6,           INPUT);  // Battery voltage/2
  pinMode(LED_BUILTIN,  OUTPUT); // Red LED

  pinMode(NEOPIXEL,     OUTPUT); // RGB

  // Disable LED driver
  digitalWrite(LED_BUCK_EN, LOW);
  digitalWrite(LED_PULSE, HIGH);

  // Start Spectrometer and RS485
  digitalWrite(SPECTRO_BOOST_EN, HIGH); // +5V for rs485
  digitalWrite(nRE, HIGH);          // Set transmit mode

  // Set the baud rate for the sensor connection
  // The soil-NPK sensor is set to a baudrate of 4800
  Serial1.begin(4800);
  node.begin(1, Serial1);
  node.preTransmission(PreTransmission);
  node.postTransmission(PostTransmission);
}

void print_rs485_modbus_npk(float temperature, float sm, int ec, float ph, int nitrogen, int phosphorus, int potassium, int salinity, int tds){

  //temp 34.0, sm 80.2, ph 8.4, N:2, P:51, K: 44107, salinity98, tds: 1539.0
  Serial.print(temperature,1);
  Serial.print(',');
  Serial.print(sm,1);
  Serial.print(',');
  Serial.print(ph,1);
  Serial.print(',');
  Serial.print(nitrogen);
  Serial.print(',');
  Serial.print(phosphorus);
  Serial.print(',');
  Serial.print(potassium);
  Serial.print(',');
  Serial.print(salinity);
  Serial.print(',');
  Serial.print(tds);

  Serial.print("\n");

}

void full_print_rs485_modbus_npkphcth(float temperature, float sm, int ec, float ph, int nitrogen, int phosphorus, int potassium, int salinity, int tds){

  Serial.print("Temperature: ");
  Serial.print(temperature,1);
  Serial.print(", SM: ");
  Serial.print(sm,1);
  Serial.print(", pH: ");
  Serial.print(ph,1);
  Serial.print(", N: ");
  Serial.print(nitrogen);
  Serial.print(", P: ");
  Serial.print(phosphorus);
  Serial.print(", K: ");
  Serial.print(potassium);
  Serial.print(", salinity: ");
  Serial.print(salinity);
  Serial.print(", TDS: ");
  Serial.print(tds);

  Serial.print("\n");

}

void rs485_modbus_npkphcth(){

  uint8_t resultMain;
  float sm = -999.0;
  float temperature = -999.0;
  int ec = -999;
  float ph = -999;
  int nitrogen = -999;
  int phosphorus = -999;
  int potassium = -999;
  int salinity = -999;
  int tds = -999;

  // 0x0000 = Moisture (%)
  delay (500);
  resultMain = node.readInputRegisters(0x000, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    sm = float( node.getResponseBuffer(0x00) )/10;
  }

  // 0x0001 = Temperature (C)
  delay (500);
  resultMain = node.readInputRegisters(0x0001, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    temperature = float( node.getResponseBuffer(0x00) )/10;
  }

  // 0x0002 = ec (uS/cm)
  delay (500);
  resultMain = node.readInputRegisters(0x0002, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    ec =  float( node.getResponseBuffer(0x00) )/10;
  }

  // 0x0003 = ph
  delay (500);
  resultMain = node.readInputRegisters(0x0003, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    ph =  float( node.getResponseBuffer(0x00) )/10;
  }



  // 0x0004 = phosphorus (mg/kg)
  delay (500);
  resultMain = node.readInputRegisters(0x0004, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    phosphorus =  node.getResponseBuffer(0x00);
  }

  // 0x0005 = potassium (mg/kg)
  delay (500);
  resultMain = node.readInputRegisters(0x0005, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    potassium =  node.getResponseBuffer(0x00);
  }

  // 0x0006 = nitrogen
  delay (500);
  resultMain = node.readInputRegisters(0x0006, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    nitrogen =  node.getResponseBuffer(0x00);
  }

  // 0x0007 = salinity (ppm)
  delay (500);
  resultMain = node.readInputRegisters(0x0007, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    salinity =  node.getResponseBuffer(0x00);
  }

  // 0x0008 = tds (ppm)
  delay (500);
  resultMain = node.readInputRegisters(0x0008, 1);
  if (resultMain == node.ku8MBSuccess)
  {
    tds =  node.getResponseBuffer(0x00);
  }

  full_print_rs485_modbus_npkphcth(temperature, sm, ec, ph, nitrogen, phosphorus, potassium, salinity, tds);

}

#define RA 68.0
#define RB 16.9
#define RD 75.0
#define DAC_VREF_mV 3300.0
#define DAC_MAX 4095.0
#define VSET_MIN_mV 566
#define VSET_MAX_mV 3558

#define pH_OFFSET_mV 1650
#define pH_GAIN 3
#define pH_mV_PER_pH 59.194
#define pH_OFFSET_pH 7

void loop()
{
  int adcvalue = 0;
  float ph,vbat,vid_in,an2;
  float mv_per_lsb = 3600.0F/1024.0F; // 10-bit ADC with 3.6V input range

  delay (100);
  digitalWrite(LED_RED, HIGH);

  rs485_modbus_npkphcth();

  delay (100);
  digitalWrite(LED_RED, LOW);

}