hello i am trying to get an ultra sonic sensor to work with an arduino nano every. But i get no signal out of it. may be the sensor is broken or i am doing something wrong.
may be this sensor does not work as i excpect since it is not the same as in the tutorial? Also i could not find any technical documentation on this exact model. Does anybody have any experience with this sensor?
/*
JSN-SR04T-V3.0 Ultrasonic Sensor - Mode 1 Demo
srt04-mode1.ino
Uses JSN-SR04T-V3.0 Ultrasonic Sensor
Displays on Serial Monitor
Mode 1 is set by bridging "M1" pads on board
Also works with A02YYUW Ultrasonic Sensor
DroneBot Workshop 2021
https://dronebotworkshop.com
*/
// Include the Software Serial library
#include <SoftwareSerial.h>
// Define connections to sensor
int pinRX = 10;
int pinTX = 11;
// Array to store incoming serial data
unsigned char data_buffer[4] = {0};
// Integer to store distance
int distance = 0;
// Variable to hold checksum
unsigned char CS;
// Object to represent software serial port
SoftwareSerial mySerial(pinRX, pinTX);
void setup() {
// Set up serial monitor
Serial.begin(115200);
// Set up software serial port
mySerial.begin(9600);
}
void loop() {
// Run if data available
if (mySerial.available() > 0) {
delay(4);
// Check for packet header character 0xff
if (mySerial.read() == 0xff) {
// Insert header into array
data_buffer[0] = 0xff;
// Read remaining 3 characters of data and insert into array
for (int i = 1; i < 4; i++) {
data_buffer[i] = mySerial.read();
}
//Compute checksum
CS = data_buffer[0] + data_buffer[1] + data_buffer[2];
// If checksum is valid compose distance from data
if (data_buffer[3] == CS) {
distance = (data_buffer[1] << 8) + data_buffer[2];
// Print to serial monitor
Serial.print("distance: ");
Serial.print(distance);
Serial.println(" mm");
}
}
}
}
make sure pin 10 is connected to the Tx pin of your sensor (pin 4 on the sensor wire) and pin 11 is connected to the Rx of the sensor (pin 3 on the sensor wire). 5V and GND connected to the red and black wires
upload this code
#include <SoftwareSerial.h>
int pinRX = 10; // connected to Tx pin of Sensor
int pinTX = 11; // connected to Rx pin of Sensor
SoftwareSerial mySerial(pinRX, pinTX);
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
}
void loop() {
if (mySerial.available() > 0) {
byte r = mySerial.read();
if (r == 0xFF) Serial.println("\nHeader - ");
else {
if (r < 0x10) Serial.write('0');
Serial.print(r, HEX);
Serial.write(' ');
}
}
}
You are right. Actually I do not know. I guessed that red goes to 5V and black to ground. Then a tried around with Tx and Rx but I did not get any signal.
so we got the header (0xFF) that's when I print Header - (I should have been print and not println)
and then you got the 2 bytes for the disance High byte first and then low byte, so 0x059D is your distance and to know if it's correct the last byte is the check sum and should match
so if we calculate the CheckSum8 (Sum of Bytes modulo 256) 0xFF + 0x05 + 0x9D = 0x1A1 modulo 256 (ie take the low byte) = 0xA1 ➜ success, this matches the last byte you got, so the distance 0x059D is correct which is 1437mm so when you took the measurement the first obstacle was 1 m 43cm and 7mm away (I would not trust the mm)
so now you can write a small piece of code getting the payload and extracting the data, something like this will probably work
#include <SoftwareSerial.h>
int pinRX = 10; // connected to Tx pin of Sensor
int pinTX = 11; // connected to Rx pin of Sensor
SoftwareSerial sensorSerial(pinRX, pinTX);
uint16_t distance;
bool readDistance(uint16_t & newDistance) {
const uint8_t headMarker = 0xFF;
static bool waitingForMarker = true;
static uint8_t data[3];
static uint8_t dataIndex = 0;
if (sensorSerial.available() != 0) {
uint8_t r = sensorSerial.read();
if (waitingForMarker) {
if (r == headMarker) {
dataIndex = 0;
waitingForMarker = false;
}
} else {
data[dataIndex++] = r;
if (dataIndex >= sizeof data) { // we have received the full payload => check content
waitingForMarker = true; // get ready for next frame
newDistance = (((uint16_t)data[0]) << 8) + data[1]; // concatenate MSB and LSB into distance in mm
uint8_t ck = (((uint16_t)data[0]) + ((uint16_t)data[1]) - 1u) & 0x00FFu; // calculate checksum
return (data[2] == ck); // returns true if the check sum was OK
}
}
}
return false;
}
void setup() {
Serial.begin(115200);
sensorSerial.begin(9600);
}
void loop() {
if (readDistance(distance)) Serial.println(distance);
}
(typed here, so not tested)
The readDistance function is a small state machine waiting for the 0xFF start marker and then accumulating the 3 next bytes. taking the first two for the distance and verifying that the last byte matches the checksum as I manually did above. if the checksum is correct the call returns true otherwise false. when you get true, you know the value in the parameter has been correctly updated and so you can use it for the distance.
Might this be the reason why i get only one measurement? I also tried using the pins labelled with with TX1 and RX0. and instead of software serial is used Serial1. But that does not work at all. Here is the code which does not work.
void setup() {
Serial.begin(115200);
Serial1.begin(9600);
}
void loop() {
if (Serial1.available() > 0) {
byte r = Serial1.read();
if (r == 0xFF) Serial.println("\nHeader - ");
else {
if (r < 0x10) Serial.write('0');
Serial.print(r, HEX);
Serial.write(' ');
}
}
}
then i connected TX1 and RX0 directly and tried this script from the examples, which work fine:
/*
SerialPassthrough sketch
Some boards, like the Arduino 101, the MKR1000, Zero, or the Micro, have one
hardware serial port attached to Digital pins 0-1, and a separate USB serial
port attached to the IDE Serial Monitor. This means that the "serial
passthrough" which is possible with the Arduino UNO (commonly used to interact
with devices/shields that require configuration via serial AT commands) will
not work by default.
This sketch allows you to emulate the serial passthrough behaviour. Any text
you type in the IDE Serial monitor will be written out to the serial port on
Digital pins 0 and 1, and vice-versa.
On the 101, MKR1000, Zero, and Micro, "Serial" refers to the USB Serial port
attached to the Serial Monitor, and "Serial1" refers to the hardware serial
port attached to pins 0 and 1. This sketch will emulate Serial passthrough
using those two Serial ports on the boards mentioned above, but you can change
these names to connect any two serial ports on a board that has multiple ports.
created 23 May 2016
by Erik Nyquist
https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialPassthrough
*/
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}
void loop() {
if (Serial.available()) { // If anything comes in Serial (USB),
Serial1.write(Serial.read()); // read it and send it out Serial1 (pins 0 & 1)
}
if (Serial1.available()) { // If anything comes in Serial1 (pins 0 & 1)
Serial.write(Serial1.read()); // read it and send it out Serial (USB)
}
}
When "RX" floats or input High level, the module outputs processed value, the data is more steady, response time: 100-300ms; when input Low level, the module outputs real-time value, response time: 100ms.
May be that's an issue for Software Serial and it can't keep up...
In many UART implementations, when there is no incoming data, the Rx pin is typically in a "mark" state, the voltage level on the Rx pin is at a logical HIGH (idle state). this can vary but if it's the case with your Arduino then you should see data coming every 100-300ms
may be you can try connecting only the module's Tx to the arduino D0 and connect the Rx of the module to 5V or GND to ensure the mode is set. don't connect the Arduino D1 to anything and try
// Serial -> USB interface
// Serial1 -> D0 (RX) / D1 (TX)
uint16_t distance;
bool readDistance(uint16_t & newDistance) {
const uint8_t headMarker = 0xFF;
static bool waitingForMarker = true;
static uint8_t data[3];
static uint8_t dataIndex = 0;
if (Serial1.available() != 0) {
uint8_t r = Serial1.read();
if (waitingForMarker) {
if (r == headMarker) {
dataIndex = 0;
waitingForMarker = false;
}
} else {
data[dataIndex++] = r;
if (dataIndex >= sizeof data) { // we have received the full payload => check content
waitingForMarker = true; // get ready for next frame
newDistance = (((uint16_t)data[0]) << 8) + data[1]; // concatenate MSB and LSB into distance in mm
uint8_t ck = (((uint16_t)data[0]) + ((uint16_t)data[1]) - 1u) & 0x00FFu; // calculate checksum
return (data[2] == ck); // returns true if the check sum was OK
}
}
}
return false;
}
void setup() {
Serial.begin(115200);
Serial1.begin(9600);
}
void loop() {
if (readDistance(distance)) Serial.println(distance);
}
Ok, so when i do this i get again one reading only /Rx to ground). but whenever i disconnect the Rx from Ground while the program ist running i get another reading and then when i reconnect too.
May be you don’t have a real module… you could connect the Rx of the module then to an ouput pin which you would pulse when you want to trigger a reading?
So your suggested somehow works for some seconds but somehow weirdly. And then stops. I think I would like another sensor. Can you recommend one? It must be waterproof, because I want to use it outside.
I have that one and at the top of a rain collecting water tank to measure how much water is left and it’s working fine for me. May be you got a bad one or a knock off.
Could you try it with another arduino, just to remove doubts about the Nano every
I tested with another arduino nano every and i get the same results. Then i contacted the company that sold me the sensor and they will send me a replacement