The issue has been resolved thanks to @nmcc. I have uploaded the code with comments and a wiring diagram to GitHub, see here.
Hello,
I am using an oxygen sensor which uses RS485 ModBus protocol (link to sensor) with a Heltec WiFi LoRa 32V3 MCU. For compatibility, I am using an active isolated RS485 to UART signal adapter module (link to converter).
My problem is, that with my current code, I receive a “??Time out” message (see Fig. 1 below).
Fig. 1: Serial monitor output showing “??Time out” for the setup with the Heltec MCU.
This is the code I'm using with the Heltec board:
HardwareSerial RS485(2); // define serial entity
float sal, ap; // define variables for Salinity and Atmospheric Pressure
// Define Com so that the error from it missing does not get thrown anymore.
uint8_t Com[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0xC5, 0xC8 };
uint8_t Com1[8] = { 0x01, 0x03, 0x10, 0x22, 0x00, 0x01, 0x20, 0xC0 };
uint8_t Com2[8] = { 0x01, 0x03, 0x10, 0x20, 0x00, 0x01, 0x81, 0x00 };
void setup() {
// put your setup code here, to run once:
// Power supply
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
Serial.begin(115200);
RS485.begin(9600, SERIAL_8N1, 47, 48); // baud rate, bits, RX, TX
Serial.println("[setup] WiFi LoRa 32 V3 RS485 Test");
}
void loop() {
// put your main code here, to run repeatedly:
// unchanged code from DFRobot
readDO_DOS_TEM();
Atmospheric_pressure();
Serial.print("AP = ");
Serial.print(ap, 2);
Serial.print("Kpa ");
Salinity();
Serial.print("Salinity = ");
Serial.print(sal,0);
Serial.println("% ");
Serial.println(" ");
delay(1000);
}
void readDO_DOS_TEM(void) {
uint32_t val = 0, val1 = 0, val2 = 0;
uint8_t Data[18] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (Serial.available() > 0) { // was mySerial
Serial.read(); // was mySerial
}
Serial.write(Com, 8); // was mySerial // error due to Com being undefined, define before void setup()
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x0C) {
Data[2] = ch;
if (readN(&Data[3], 14) == 14) {
if (CRC16_2(Data, 15) == (Data[15] * 256 + Data[16])) {
val = Data[3];
val = (val << 8) | Data[4];
val = (val << 8) | Data[5];
val = (val << 8) | Data[6];
float *dos = (float *)&val;
float Dos = *dos * 100.00;
Serial.print("DO Sat = ");
Serial.print(Dos, 1);
Serial.print("% ");
val1 = Data[7];
val1 = (val1 << 8) | Data[8];
val1 = (val1 << 8) | Data[9];
val1 = (val1 << 8) | Data[10];
float *Do = (float *)&val1;
Serial.print("DO = ");
Serial.print(*Do, 2);
Serial.print(" mg/L ");
val2 = Data[11];
val2 = (val2 << 8) | Data[12];
val2 = (val2 << 8) | Data[13];
val2 = (val2 << 8) | Data[14];
float *tem = (float *)&val2;
Serial.print("TEM = ");
Serial.print(*tem, 1);
Serial.println("°C");
flag = 0;
}
}
}
}
}
}
}
}
}
}
void Atmospheric_pressure(void) {
uint8_t Data[12] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (Serial.available() > 0) { // was mySerial
Serial.read(); // was mySerial
}
Serial.write(Com1, 8); // error due to Com1 being undefined, define before void setup() // was mySerial
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out2");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x02) {
Data[2] = ch;
if (readN(&Data[3], 4) == 4) {
if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
ap = (Data[3] * 256 + Data[4]) / 100.0;
flag = 0;
}
}
}
}
}
}
}
}
}
}
void Salinity(void) {
uint8_t Data[12] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (Serial.available() > 0) { // was mySerial
Serial.read(); // was mySerial
}
Serial.write(Com2, 8); // error due to Com2 being undefined, define before void setup() // was mySerial
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out3");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x02) {
Data[2] = ch;
if (readN(&Data[3], 4) == 4) {
if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
sal = Data[3] * 256 + Data[4];
flag = 0;
}
}
}
}
}
}
}
}
}
}
uint8_t readN(uint8_t *buf, size_t len) {
size_t offset = 0, left = len;
int16_t Tineout = 500;
uint8_t *buffer = buf;
long curr = millis();
while (left) {
if (Serial.available()) { // was mySerial
buffer[offset] = Serial.read(); // was mySerial
offset++;
left--;
}
if (millis() - curr > Tineout) {
break;
}
}
return offset;
}
unsigned int CRC16_2(unsigned char *buf, int len) {
unsigned int crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (unsigned int)buf[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
return crc;
}
}
From the converter, I’m connecting to the board as follows: (-) -> GND, (+) -> Ve, R -> 47, T -> 48. Measuring voltages at the Heltec’s pins, I get Ve = 3.24 V, 47 = 3.23 V, 48 -> 3.23 V. Measuring voltages at the pins connecting converter to sensor, I get 12V = 12.75 V, A = 5.02 V, B = 0.05V.
In comparison, when I connect the same sensor and converter to an Arduino Minima R4, I receive plausible values (see Fig. 2 below) in the serial monitor.
Fig. 2: Serial monitor output showing desired output/values for the setup with the Arduino Minima R4.
With the Arduino Minima R4, I'm using the following code:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); //TX,RX
uint8_t Com[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0xC5, 0xC8 };
uint8_t Com1[8] = { 0x01, 0x03, 0x10, 0x22, 0x00, 0x01, 0x20, 0xC0 };
uint8_t Com2[8] = { 0x01, 0x03, 0x10, 0x20, 0x00, 0x01, 0x81, 0x00 };
float sal, ap;
void setup() {
Serial.begin(9600);
mySerial.begin(4800);
}
void loop() {
readDO_DOS_TEM();
Atmospheric_pressure();
Serial.print("AP = ");
Serial.print(ap, 2);
Serial.print("Kpa ");
Salinity();
Serial.print("Salinityt = ");
Serial.print(sal,0);
Serial.println("% ");
Serial.println(" ");
delay(1000);
}
void readDO_DOS_TEM(void) {
uint32_t val = 0, val1 = 0, val2 = 0;
uint8_t Data[18] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (mySerial.available() > 0) {
mySerial.read();
}
mySerial.write(Com, 8);
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x0C) {
Data[2] = ch;
if (readN(&Data[3], 14) == 14) {
if (CRC16_2(Data, 15) == (Data[15] * 256 + Data[16])) {
val = Data[3];
val = (val << 8) | Data[4];
val = (val << 8) | Data[5];
val = (val << 8) | Data[6];
float *dos = (float *)&val;
float Dos = *dos * 100.00;
Serial.print("DO Sat = ");
Serial.print(Dos, 1);
Serial.print("% ");
val1 = Data[7];
val1 = (val1 << 8) | Data[8];
val1 = (val1 << 8) | Data[9];
val1 = (val1 << 8) | Data[10];
float *Do = (float *)&val1;
Serial.print("DO = ");
Serial.print(*Do, 2);
Serial.print(" mg/L ");
val2 = Data[11];
val2 = (val2 << 8) | Data[12];
val2 = (val2 << 8) | Data[13];
val2 = (val2 << 8) | Data[14];
float *tem = (float *)&val2;
Serial.print("TEM = ");
Serial.print(*tem, 1);
Serial.println("°C");
flag = 0;
}
}
}
}
}
}
}
}
}
}
void Atmospheric_pressure(void) {
uint8_t Data[12] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (mySerial.available() > 0) {
mySerial.read();
}
mySerial.write(Com1, 8);
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out2");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x02) {
Data[2] = ch;
if (readN(&Data[3], 4) == 4) {
if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
ap = (Data[3] * 256 + Data[4]) / 100.0;
flag = 0;
}
}
}
}
}
}
}
}
}
}
void Salinity(void) {
uint8_t Data[12] = { 0 };
uint8_t ch = 0;
bool flag = 1;
long timeStart = millis();
long timeStart1 = 0;
while (flag) {
if ((millis() - timeStart1) > 100) {
while (mySerial.available() > 0) {
mySerial.read();
}
mySerial.write(Com2, 8);
timeStart1 = millis();
}
if ((millis() - timeStart) > 1000) {
Serial.println("Time out3");
//return -1;
}
if (readN(&ch, 1) == 1) {
if (ch == 0x01) {
Data[0] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x03) {
Data[1] = ch;
if (readN(&ch, 1) == 1) {
if (ch == 0x02) {
Data[2] = ch;
if (readN(&Data[3], 4) == 4) {
if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
sal = Data[3] * 256 + Data[4];
flag = 0;
}
}
}
}
}
}
}
}
}
}
uint8_t readN(uint8_t *buf, size_t len) {
size_t offset = 0, left = len;
int16_t Tineout = 500;
uint8_t *buffer = buf;
long curr = millis();
while (left) {
if (mySerial.available()) {
buffer[offset] = mySerial.read();
offset++;
left--;
}
if (millis() - curr > Tineout) {
break;
}
}
return offset;
}
unsigned int CRC16_2(unsigned char *buf, int len) {
unsigned int crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (unsigned int)buf[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
return crc;
}
I assume that the time-out-error is being thrown due to sensor response not coming within the defined timeframe. Further, I assume that (1) the COM definitions at the top of the code made for the Heltec board are incorrect, which (2) blocks the B cable from getting enough voltage to produce a reply (hence having a voltage of 0.05 V). That’s where I then end up being stuck.
Any help, links, resources, ideas, suggestions etc. are very welcome and appreciated!




