I discovered the Arduino for which I have only a very small experience and I will soon receive measurement equipment whose data is transmitted according to the RS485 protocol. The project is to acquire this data with Arduino and then exploit it.
The sensor manufacturer gives me the following information:
Wired connection: RS485 (A +): RS485 communication interface A + / RS485 (B -): RS485 communication interface B-
As you might expect, my question is how to interrogate the sensor and how to receive its response with an Arduino and an RS485 module.
For some of you it should be easy but I would have trouble without some explanation (how to connect the module to the sensor and the Arduino, which libraries, examples of sketch for the interrogation of the sensor and to receive the reply...).
TEDDOL:
Ok but should I send to the sensor a full string like this in my sketch: RS485Serial.write(00030000000185DB); ?
You would need to read the sensor's datasheet for the answer to that. It would surely explain what the sensor expects to receive and will deem a valid request.
Have a look here, where there's a library with an example of how to compose a string containing the recipient address, request code, paramater values and so on.
Hi, come back with this subject about RS485 modbus and my controller. I did not find the good way yet.
You can fin in attached file data sheet communication and wiring scheama used.
Here the sketch used:
#include SoftwareSerial.h
#define SSerialRX 10 //Serial Receive pin
#define SSerialTX 11 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#define RS485Transmit HIGH
#define RS485Receive LOW
#define Pin13LED 13
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
byte byteSend;
void setup()
{
// Start the built-in serial port, probably to Serial Monitor
Serial.begin(9600);
Serial.println("SerialRemote"); // Can be ignored
pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive); // Init Transceiver
RS485Serial.begin(9600);
delay(2000);
digitalWrite(SSerialTxControl, RS485Transmit);
RS485Serial.write((byte)0x00);
RS485Serial.write((byte)0x03);
RS485Serial.write((byte)0x00);
RS485Serial.write((byte)0x00);
RS485Serial.write((byte)0x00);
RS485Serial.write((byte)0x01);
RS485Serial.write((byte)0x85);
RS485Serial.write((byte)0xDB);
Serial.println(" ");
digitalWrite(Pin13LED, LOW);
delay(10);
digitalWrite(SSerialTxControl, RS485Receive);
}
void loop()
{
if (RS485Serial.available())
{
byteSend = RS485Serial.read(); // Read the byte
Serial.print(byteSend, HEX);
Serial.print(" ");
}
else
{
Serial.println(" ");
delay (1000);
digitalWrite(SSerialTxControl, RS485Transmit); // Enable RS485 Transmit
RS485Serial.write((byte)0x00); // Send byte to Remote Arduino
RS485Serial.write((byte)0x03); // Send byte to Remote Arduino
RS485Serial.write((byte)0x00); // Send byte to Remote Arduino
RS485Serial.write((byte)0x00); // Send byte to Remote Arduino
RS485Serial.write((byte)0x00); // Send byte to Remote Arduino
RS485Serial.write((byte)0x01); // Send byte to Remote Arduino
RS485Serial.write((byte)0x85); // Send byte to Remote Arduino
RS485Serial.write((byte)0xDB); // Send byte to Remote Arduino
digitalWrite(Pin13LED, LOW); // Show activity
delay(10);
digitalWrite(SSerialTxControl, RS485Receive); // Disable RS485 Transmit
}
}
My serial monitor displays strange datas as:
SerialRemote
E
C4 B6 E
C4 B6 E
C4 B6 E
C4 B6 1D
C4 B6 7 C4 B6
7 C4 B6 E
C4 B6 E
C4 B6 1D
C4 B6 E
C4 B6 1D
C4 B6 1D
C4 B6 E
C4 B6 1D
C4 B6 1D
C4 B6 E
Does this make any difference, from the Modbus RTU documentation:
The difference between MODBUS RTU and MODBUS/ASCII
There are two basic transmission modes found in serial MODBUS connections, ASCII and RTU. These transmission modes determine the way in which the MODBUS messages are coded. In ASCII format, the messages are readable, whereas in RTU the messages are in binary coding and cannot be read while monitoring. The trade-off is that the RTU messages are a smaller size, which allows for more data exchange in the same time span. One should be aware that all nodes within one MODBUS network must be of the same transmission mode, meaning MODBUS ASCII cannot communicate with MODBUS RTU and vice versa.
You are not using the ASCII version, so, as stated, they are not directly readable.
Paul
Not directly readable? What do you mean ?
Is it impossible to get response from the controller with an arduino? I think we can.
How can I write my sketch to send a request and get controller return ?
TEDDOL:
Not directly readable? What do you mean ?
Is it impossible to get response from the controller with an arduino? I think we can.
How can I write my sketch to send a request and get controller return ?
It means the data is binary, not ASCII characters. You must convert them to something readable on your monitor before they will make sense. Or write the binary equivalent out by hand for each character you display.
OK Paul, but before, i would like to know if my sketch is right ?!
Is it the good way to send request to controller according the manufacturer datasheet ?:
TEDDOL:
OK Paul, but before, i would like to know if my sketch is right ?!
Is it the good way to send request to controller according the manufacturer datasheet ?:
Yes, that seems correct and the message it right out of the document. And notice, you are sending the hex equivalent of binary, not ASCII characters. And you will be getting the same back from the device.
Paul_KD7HB:
RS485 is an electrical protocol, so has nothing to do with software. Look at the serial data examples and tutorials. They will get you going.
Paul
Other than software has to control the direction of the bus explicitly, and know the possible baud rate(s),
so it is not fully transparent to code.
Here we have a serial packet to send, then a response to listen for, and somewhere the sensor baud
rate and timing (for packet response) will be documented - and hopefully the structure of both
sent and returned packet is also documented.
#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX 10 //Serial Receive pin
#define SSerialTX 11 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#define RS485Transmit HIGH
#define RS485Receive LOW
#define Pin13LED 13
/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
/*-----( Declare Variables )-----*/
int byteReceived;
String ph_hexa, ph_hexa_hight_byte, ph_hexa_low_byte, ph_hexa_value;
byte request [] = {
0x00,
0x03,
0x00,
0x00,
0x00,
0x01,
0x85,
0xDB
};
void setup() /****** SETUP: RUNS ONCE ******/
{
// Start the built-in serial port, probably to Serial Monitor
Serial.begin(9600);
Serial.println("YourDuino.com SoftwareSerial remote loop example");
Serial.println("Use Serial Monitor, type in upper window, ENTER");
pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive); // Init Transceiver
// Start the software serial port, to another device
RS485Serial.begin(19200); // set the data rate
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
if (RS485Serial.available()) //Look for data from other Arduino
{
Serial.print("Response: ");
for (int i = 0; i <= 6; i++) {
byteReceived = RS485Serial.read(); // Read received byte
ph_hexa = String(byteReceived, HEX);
// index 3 = high byte
if(i == 3)
{
ph_hexa_hight_byte = ph_hexa;
}
// index 4 = low byte
if(i == 4)
{
ph_hexa_low_byte = ph_hexa;
ph_hexa_value = ph_hexa_hight_byte + ph_hexa_low_byte;
Serial.print(ph_hexa_value);// Show on Serial Monitor
}
Serial.print(" ");
}
/*
Serial.println(ph_hexa);
ph_hexa = "";
*/
Serial.println();
}
else
{
Serial.println();
Serial.print("Request: ");
digitalWrite(SSerialTxControl, RS485Transmit); // Init Transceiver
for (int i = 0; i < 8; i++) {
Serial.print(request[i], HEX);
RS485Serial.write((byte)request[i]);
}
Serial.println();
digitalWrite(SSerialTxControl, RS485Receive); // Init Transmit
}
delay(1000);
}
My serial monitor shows:
YourDuino.com SoftwareSerial remote loop example
Use Serial Monitor, type in upper window, ENTER
Request: 03000185DB
Response: 179
Request: 03000185DB
Response: 179
Request: 03000185DB
Response: 179
Request: 03000185DB
Response: 179
Request: 03000185DB
Response: 179
179 (HEX) = 377(DEC) => 3.77pH Yes!!!! My controller displays 3.77pH. I tested it with different pH value of the water and it matches with the hexa value.
But i'm not satisfied of my code. I want to transform the 179(HEX) value in 3.77 float value for others math calculations.
How can do that ?
179 value is a String in my code corresponding to 0x0179. First i want to convert it in int and after, divide it by 100.
What do you think ? Maybe the code is not appropriated for this...