I2C communications from Uno to Particle Electron

I am a complete Arduino neophyte so I need help from you pros!

I want to embellish my residential community’s shared water well system with the ability to remotely monitor the water level in its 1500-gallon storage tank.

I began with a waterproof ultrasonic sensor (JSN-SR04T) and an Arduino Uno (affectionately named ‘Tony’). The code I’m currently running on Tony perfectly reports the depth via the Arduino serial monitor.

But my desire is to interface Tony to an existing Particle Electron (embedded on an NCD-MCP23008 PCB/shield) via the I2C bus. This would allow the depth data to be remotely accessible via IoT using the Particle Cloud.

Specifically, I want to pass the contents of a float variable ‘gallons’ to the Electron (I need to report fractional gallons). I embellished Tony’s code with what on-line tutorials suggest are the proper commands and functions to enable I2C communications, but I have so far been unsuccessful in passing any data of any type from Tony to the Electron.

The Wire.write function will not accept a float variable or a String variable (the lack of String support begs the question: how can you ever pass anything but a number via I2C?), so for testing purposes I declared ‘gallons’ as a byte, as a long and then as an integer. In all cases the code compiled, but only zeros showed up on the other end (on the Electron).

I tried sending an actual string (not to be confused with a String variable); Wire.write accepted it, i.e. it compiled, but again nothing showed up in the Particle console.

Below is the latest iteration of my Arduino code. Note that I have been unable to figure out the difference between the Wire.onReceive(requestEvent) and Wire.onRequest(requestEvent) functions, so I've tried them both separately and together; no change.

Can any of you experts out there help me figure out what I’m doing wrong?

#include <Wire.h>
#include <stdlib.h>

/* Arduino example sketch to control a JSN-SR04T ultrasonic distance sensor with Arduino. No library needed. More info: https://www.makerguides.com */
// Define Trig and Echo pin:
#define trigPin 2
#define echoPin 3

// Define variables:
long duration;
float distance;
byte gallons;
byte requestEvent;
String depth;

void setup() {
// Define inputs and outputs
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);

// Begin Serial communication at a baudrate of 9600:
Serial.begin(9600);

Wire.begin(8);
Wire.onReceive(requestEvent);
Wire.onRequest(requestEvent);

}

void loop() {

// Clear the trigPin by setting it LOW:
digitalWrite(trigPin, LOW);

delayMicroseconds(5);
// Trigger the sensor by setting the trigPin high for 10 microseconds:
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Read the echoPin. pulseIn() returns the duration (length of the pulse) in microseconds:
duration = pulseIn(echoPin, HIGH);

// Calculate the distance in cm:
distance = duration * 0.034 / 2;

// Convert to inches:
distance = distance * 0.393701;

// Adjust for error:
distance = distance * 1.037;

int i;
char buff[10];
String depth = "";
dtostrf(distance, 5, 2, buff); //5 is mininum width, 2 is precision
depth += buff;

// This formula is for testing only:
gallons = distance * 30;

// Print the distance to the water surface on the Serial Monitor:
Serial.print("Distance = ");
Serial.print(distance);
Serial.println(" in");

// Print the amount of water remaining on the Serial Monitor:
Serial.print("Depth = ");
Serial.print(gallons);
Serial.println(" gallons");
//The above code works flawlessly

void requestEvent(); //This Function is called when Master wants value from slave

{
// Wire.beginTransmission();

Wire.write(gallons);

// Wire.write(depth.c_str()); //Attempt to send a string
// Wire.endTransmission();
}
// Introduce a 5-second delay:
delay(5000);
}

For what it's worth, here's the code running on the Electron:

#include <Wire.h>

String data = String(10);
byte distance;

void setup() {
//Set the speed of the I2C port on the Photon and start it.
Serial.begin(9600);
Wire.begin();
}

void loop() {
Wire.beginTransmission(8);
Wire.requestFrom(8,1);
distance = Wire.read();
Wire.endTransmission();
Particle.publish ("Distance = ",String(distance),60, PRIVATE);

delay(10000);
}

Crap! I figured it out, so I wanted to delete this post entirely but can't figure out how to do so. So instead, here's what I discovered: I had my 'requestEvent()' function inside of my 'loop()' function. Can't nest functions. Moved it after the 'loop()' closing brace and voila! It works!

Sorry, folks, for my stupidity....

Just curious whether you could eliminate the Arduino completely and just use an Particle Electron alone.

.

Hi ieee488!

I probably could have, but here's why I didn't:

As I mentioned, the Particle Electron was already in place. Specifically, the Electron is plugged into the NCD relay board which, in turn, is connected to an in-tank float switch. When the float switch closes (at a pre-defined low water level), the relay board passes that contact closure event to the Electron which passes it to the Particle Cloud which passes it to a companion Electron at the well site 1000 feet away. The latter is also plugged into an identical NCD relay board which closes a relay to start the pump. All that works like a charm.

The reason I chose the Electron is that there is no WiFi at either the tank site or the well site, so I had to use cellular. Had WiFi been available, I would have used a Photon instead and avoided the monthly fee for cellular service.

When it recently became important to check the actual water level in the tank remotely, it made sense to just add appropriate code to the existing firmware running on the Electron at the tank location. Note that, for clarity, the code that I originally posted here excluded the code associated with turning the pump on and off.

Hope that helps. If you want more information, let me know.

FWIW, here's the final version of my Arduino code that actually works:

#include <Wire.h>
#include <stdlib.h>

/* Arduino example sketch to control a JSN-SR04T ultrasonic distance sensor with Arduino. No library needed. More info: https://www.makerguides.com */

// Define Trig and Echo pin:
#define trigPin 2
#define echoPin 3

// Define variables:
long duration;
float distance;
int gallons;
byte val;

void setup() {
// Define inputs and outputs
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);

Serial.begin(9600); // Begin serial communication at a baud rate of 9600:

Wire.begin(8);
Wire.onRequest(requestEvent);
}

void loop() {

digitalWrite(trigPin, LOW); // Clear the trigPin by setting it LOW:
delayMicroseconds(5);

// Trigger the sensor by setting the trigPin high for 10 microseconds:
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH); // Read the echoPin. pulseIn() returns the duration (length of the pulse) in microseconds:

distance = duration * 0.034 / 2; // Calculate the distance in cm:
distance = distance * 0.393701; // Convert to inches:
distance = distance * 1.037; // Adjust for error:

val = round(distance);

// Print the distance to the water surface on the Serial Monitor (Ctrl+Shift+M):
// Serial.print("Distance = ");
// Serial.print(distance);
// Serial.println(" in");

delay(5000); // Introduce a 5-second delay:
}

void requestEvent() //This Function is called when Master wants value from slave
{
Wire.write(val);
}

Why can't the Electron monitor the SN-SR04T ultrasonic distance sensor ?

.

Unless I am wrong - I easily could be; I'm not any kind of engineer, just a tinkerer - the easiest way to get any kind of signal to the Electron once inserted onto the NCD relay board is via the i2C bus. The PCB that comes with the sensor does not have an I2C interface, so that's what the Arduino is doing for me. Maybe I could have accessed the appropriate pins on the Electron via the NCD's socket, but I don't know. Since the Arduino was so cheap and there was readily-available code for connecting the SN-SR04T to it, I took the easy way (yet still mucket it up for a while due simply to my ignorance of C++).

If you could suggest what pins on the Electron are equivalent to digital pins 2 & -3 on the Arduino, I'd love to give it a try.

The NCD relay board is just a relay board isn't it?

The datasheet for the Particle Electron https://docs.particle.io/datasheets/cellular/electron-datasheet/ says that there are 8 digital only pins GPIO D0-D7.

.

You have been 100% correct ieee488! Based upon your comments and another post elsewhere on the web, I connected the sensor's trig and echo pins to the Electron's pins 2 and 3 and with a tweak to the code running on the latter, I got it working almost immediately. Bottom line: MUCH simpler code and an entire PCB - the Arduino - can be omitted from my very tight electronics enclosure. Another benefit: I now have an Arduino to play with any time I want. MANY THANKS!

(Note that the long chain of 'else if' statements will be converted to an array at some point; won't affect performance, just more compact. To impress my friends.)

#include <New_Ping.h>

// Define variables:
int gallons;
int distance;

#define trigPin 2
#define echoPin 3
#define MAX_DISTANCE 200

NewPing sonar = NewPing(trigPin, echoPin, MAX_DISTANCE);

void setup() {

Serial.begin(9600); // Set the speed of the I2C port on the Photon and start it.
}

void loop() {

distance = sonar.ping_in();

if (distance == 10) {
gallons = 1480;
}
else if (distance == 11) {
gallons = 1438;
}
else if (distance == 12) {
gallons = 1396;
}
else if (distance == 13) {
gallons = 1356;
}
else if (distance == 14) {
gallons = 1316;
}
else if (distance == 15) {
gallons = 1271;
}
else if (distance == 16) {
gallons = 1226;
}
else if (distance == 17) {
gallons = 1186;
}
else if (distance == 18) {
gallons = 1146;
}
else if (distance == 19) {
gallons = 1096;
}
else if (distance == 20) {
gallons = 1046;
}
else if (distance == 21) {
gallons = 1003;
}
else if (distance == 22) {
gallons = 961;
}
else if (distance == 23) {
gallons = 919;
}
else if (distance == 24) {
gallons = 876;
}
else if (distance == 25) {
gallons = 831;
}
else if (distance == 26) {
gallons = 786;
}
else if (distance == 27) {
gallons = 741;
}
else if (distance == 28) {
gallons = 696;
}
else if (distance == 29) {
gallons = 656;
}
else if (distance == 30) {
gallons = 616;
}
else if (distance == 31) {
gallons = 571;
}
else if (distance == 32) {
gallons = 526;
}
else if (distance == 33) {
gallons = 482;
}
else if (distance == 34) {
gallons = 438;
}
else if (distance == 35) {
gallons = 396;
}
else if (distance == 36) {
gallons = 354;
}
else if (distance == 37) {
gallons = 309;
}
else if (distance == 38) {
gallons = 264;
}

Particle.publish ("Gallons",String(gallons),60, PRIVATE);
Particle.publish ("Distance",String(distance),60, PRIVATE);

delay(300000); // Take a measurement every 5 minutes

}

excellent !