problems interfacing with RS485

hello

i am new here and i don’s have much knowledge in the area of programming (arduino’s or anything else) but hopefully that will change :slight_smile:

i have come across a Thies Clima ultrasonic wind sensor, and i would very much like to get that turned into part of a weather station. it uses RS485 MODBUS or thies interpretation to display wind speed, direction and temperature.

if i use the Thies software i can get the data in a serial monitor, by using an RS485 to USB converter. so i know i have the wirering ad the connection data correct.

the problem with that is that it is too limited, and i would like to get the data by using an Arduino so that in the long run i can add more sensors (pressure or rainfall) and possibly add it to a web server using a raspberry pi.

but my main problem is that i cannot seem to get any sketch that works, and every application of this RS485 seems to be a completely different code.

so i was hoping that one or more of you could help me out with the basics for a sketch. basically just setting the Arduino to master, reading the data and then displaying it in the serial monitor.

i have added a picture of the MODBUS settings for the unit and the manual for it.
i know how to work with the hardware, i just dont know how to make the code, once i have a code i can usualy see how it works. i just dont have the experience to write it from scratch :frowning:

the unit is programmed up to start sending data as soon as it boots up, in MODBUS mode it sends a long string of HEX code, and in Thies mode it just sends 3 numbers on 1 line (speed, direction and temp)

i hope one of you can help me out with the basic code for getting data.

4.387x.xx.xxx_US-Anemometer-2D_compact-eng.pdf (589 KB)

RS-485 is hardware. Modbus is Software. You can use Modbus with different hardware, you can use RS-485 with different softare (protocols). You need to be sure to combine, but not mix the two. You have Modbus over RS-485. Good.

Which Modbus? Modbus ASCII or Modbus RTU?

Which RS-485 hardware card do you have to put between the sensor and the Arduino? (ie., which break out board?)

ohh sorry forgot to mention the hardware :)

i have Arduino nano and UNO here at the moment, along with MAX485 RS-485 Module For the testing with a laptop i used an USB to RS485 converter'

the sensor is running MODBUS-RTU half duplex bus mode

I used the smarmengol library with much success. Have you tried this one?

With this library the program can function as master or slave (nice two-in-one feature so I don't have to have two libraries). The library and example do need to be reworked to fix the improper use of millis(), there is enough information around to search the fix. The examples are pretty good and overall I find it flexible enough.

tried out the smarmengol library, but no luck

i tried a good selection of the sketches listed as excamples, but noone of them worked :frowning:

this is the code i used that gave me the most response

but i just get squares and ?'s in the serial monitor

#include <ModbusRtu.h>

uint16_t au16data[16];
uint8_t u8state;

Modbus master(0,0,3); // this is master and RS-232 or USB-FTDI

modbus_t telegram;

unsigned long u32wait;

void setup() {
  master.begin( 9600 ); 
  master.setTimeOut( 2000 );
  u32wait = millis() + 1000;
  u8state = 0; 
}

void loop() {
  switch( u8state ) {
  case 0: 
    if (millis() > u32wait) u8state++; 
    break;
  case 1: 
    telegram.u8id = 10; // slave address
    telegram.u8fct = 3; // function code (this one is registers read)
    telegram.u16RegAdd = 1; // start address in slave
    telegram.u16CoilsNo = 4; // number of elements (coils or registers) to read
    telegram.au16reg = au16data; // pointer to a memory array in the Arduino

    master.query( telegram ); 
    u8state++;
    break;
  case 2:
    master.poll(); 
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 100; 
    }
    break;
  }
}

The serial monitor can only display alphanumeric ascii values. What you you think it will display when the value byte value '16' is sent? Since it is not ascii, it will display a square,?, or other garbage character.

Furthermore, the arduino is a master (per the program posted) and you are trying to read registers from the serial monitor. The serial monitor has no 'registers' for the master to read.

I think you need to (re)think your test setup and contemplate what each piece is doing and/or can do.

adwsystems: The serial monitor can only display alphanumeric ascii values. What you you think it will display when the value byte value '16' is sent? Since it is not ascii, it will display a square,?, or other garbage character.

Furthermore, the arduino is a master (per the program posted) and you are trying to read registers from the serial monitor. The serial monitor has no 'registers' for the master to read.

I think you need to (re)think your test setup and contemplate what each piece is doing and/or can do.

hmmm okay

when i use the software from the manufacturer of the sensor i get a whole list of HEX "blocks" (like a mac adresse) and i was actualy assuming (apparently i was wrong) that i would receive the same in the serial monitor of the arduino. again i am no where close to being able to program much more than an on off switch on the arduino.

i assumed that there had to be a master somewhere ? is that wrong ?

from looking into the terminal monitor on the manufacturer software i get the following info

in what they call "thies interpreter"

20:19:02: 10TR2

20:19:02: 00.1 271 +24.0 5E*48

20:19:03: 10TR2

20:19:03: 00.1 282 +24.0 5E*44

in MODBUS RTU mode

20:19:40: 0A 04 88 B9 00 1C 0A FD  (MODBUS-REQUEST: SlaveAddr=0A FctCode=04 RegAddr=88B9 RegCnt=001C)

20:19:41: 0A 04 38 00 00 00 01 FF FF FF FF 00 00 09 F4 FF FF FF FF 00 00 00 F6 00 00 00 F2 FF FF FF FF FF FF FF FF 01 32 69 E5 00 00 01 63 00 00 00 5E 00 00 00 F1 00 03 99 47 00 00 00 00 DA FF  (MODBUS-RESPONSE: SlaveAddr=0A FctCode=04 ByteCnt=38 DecodedData=1, 4294967295, 2548, 4294967295, 246, 242, 4294967295, 4294967295, 20081125, 355, 94, 241, 235847, 0)
20:19:41: 0A 04 88 B9 00 1C 0A FD  (MODBUS-REQUEST: SlaveAddr=0A FctCode=04 RegAddr=88B9 RegCnt=001C)

20:19:42: 0A 04 38 00 00 00 01 FF FF FF FF 00 00 09 9F FF FF FF FF 00 00 00 F5 00 00 00 F2 FF FF FF FF FF FF FF FF 01 32 69 E5 00 00 01 64 00 00 00 5E 00 00 00 F1 00 03 9D 2F 00 00 00 00 5A B0  (MODBUS-RESPONSE: SlaveAddr=0A FctCode=04 ByteCnt=38 DecodedData=1, 4294967295, 2463, 4294967295, 245, 242, 4294967295, 4294967295, 20081125, 356, 94, 241, 236847, 0)

and at connect i get this info

Interpreter: THIES
baudrate    : 9600
Framing     : parity=N data=8 stop=1 rts=off dtr=off 
ID             : 10

SW-VER     : 003.10
Art.-Nr.      : 4.3875.00.390

)
--------- COM4,9600,0,0,8,0,1,4294967295,0,100,0,100, ------------

but looking at it am i right in assuming that the first line is a request for data and then the second is the response (then repeated) ?

it would be easiest for me if i could read the Thies Interpreter directly, but i doubt i would be able to find anything that can read that since it seems fairly company specific.

so the MODBUS RTU have to do, but my main goal at the moment is just to get the arduino to send the request , read the data and write it in the serial monitor. that should be possible correct ?

any help is very much appreciated.

Should be. The data from the Thies Interpreter tells you exactly how to set up the request telegram and read the response telegram.

Serial port 0 on the UNO is also the port that communicates with the USB to the PC. You are asking it to do double duty. For projects like this, I highly suggest using an Arduino with at least two hardware serial ports. The MEGA has the advantage that the UNO shields will fit it. Then you can leave serial 0 available for sending ascii debug code to the serial monitor and use serial 1 or 2 for the RS-485.

okay

so i will need to get a hold of a mega, is there any of the other boards that has multiple serial ports ?
i am mainly thinking space, since the MEGA is kinda big, and i would prefer it to be a small combined package.

since i have to go shopping again, i figured i might aswell get the optimal solution right off the bat.

A few

Arduino Product List

As I mentioned, the advantage to the MEGA is shields from the UNO will fit it. Not the same with the Micro and a few others.

might be able to get a hold of a MEGA on sunday, then i can try to get on with this project :) anything else you could recommend while i am in the shop ? :)

i have been searching around for more info on this line, i did notice something similar in some of the examples i have tried.

COM4,9600,0,0,8,0,1,4294967295,0,100,0,100,

but there seems to be a couple of things i cant find (or doesnt understand) but the first is the port obviosly, and the next would be baud rate and polarity.

but what about that long number 4294967295 ?

4294967295 is the max size for a long (0xFF FF FF FF). See the run of 4 FF?

Looks like all the data is of long data type.

Windows 10 has a nice calculator with a programmer mode to easily convert dec to hex.

FF FF FF FF 00 00 09 F4 FF FF FF FF 00 00 00 F6 00 00 00 F2 FF FF FF FF FF FF FF FF 01 32 69 E5 00 00 01 63 00 00 00 5E 00 00 00 F1 00 03 99 47 00 00 00 00

is the data

4294967295, 2548, 4294967295, 246, 242, 4294967295, 4294967295, 20081125, 355, 94, 241, 235847, 0

okay managed to get a hold of an arduino MEGA, and after alot of reading i think i am getting a better understanding of serial communication (thou still a long way to go i fear)

but i have borrowed a sketch from microcontroller-project.com for sending data to another Arduino and getting a reply. i was hoping to use it to tap into the Thies interpreter, since that is open with no password needed, just needed to send a “telegram”

if it is in this mode i should be able to send “10TR00002” and get a reply (at least that is how i read it in the manual) i have attached that part of the manual if anyone is interestet.

using the following code at the moment.

void setup() {
  
  Serial1.begin(9600);//Using Serial1 Port
  Serial.begin(9600);
  pinMode(8, OUTPUT);//DE/RE Controling pin of RS-485
}

void loop() {
  char getdata='m';

  digitalWrite(8,HIGH);//DE/RE=HIGH Transmit Enabled M1
  Serial1.print("10TR00002");

   
  digitalWrite(8,LOW);//DE/RE=LOW Receive Enabled M1
  delay(1000);
  
  if(Serial1.available()){ //If Serial Data is available
    
    while(Serial1.available() && getdata!='d')
    { 
    getdata=Serial1.read();
    Serial.print(getdata);
    }
    
    Serial.println("1");
    }
  Serial.println("2");
  delay(1000);
}

MAX485 data pins connected to serial 1 ont he MEGA, with the send/recieve pins is connected to pin8

when running i get 1 and 2 in my serial monitor, but no data from the sensor.
if i disconnect the sensor i only get the 2, so in my mind it looks like the connection is there, i am just not sending the right codes, or not reading it right.

am i completely on the wrong track here ? i figured i would try to simplest for now, and see if i could avoid the modbus rtu, if it isnt needed.

the sensor is normaly working with this thies interpreter, connected to a PLC. and if i connect to it via Putty and type in 10TR2 i get a response with the data.

so what am i missing in the code ?

  digitalWrite(8,HIGH);//DE/RE=HIGH Transmit Enabled M1
  Serial1.print("10TR00002");

   
  digitalWrite(8,LOW);//DE/RE=LOW Receive Enabled M1

This assumes the Serial1.print() statement completes before it moves on to the digitalWrite statement. This is not true, therefore the DE/RE line switches mid-transmission.

You can't avoid Modbus RTU, completely, This is the language begin used over RS-485. You may find a way to work around having to use a modbus libary, but you can't avoid the fact it speaks using modbus RTU.

How many MAX485 boards do you have? If you purchased multiple, being the boards are half-duplex you can use two and not worry about the DE/RE pin. Connect one to each of the Rx and TX pins and hardwire the RE/DE pin to fix the polarity (Rx/Tx). then you don't have to worry about switching or timing. Once you have this working, then you can work to reduce to a single board.

i have plenty of the MAX485 so that isnt a problem.

but the sensor is only half duplex, so i dont realy see how i could hook it up to 2, unless i could just loop the RX and TX wires to both modules, similar to a setup with 3 RS485 units on one line.

but maybe i should hook up another arduino instead of the sensor so i can see if the entire command is sent and received.

but a delay inbetween the serial1.print and switching to recieve makes sense, 100ms could maybe work.

i will try to look into it again tonight.

The sensor works on RS485, you have proved that. So the issue is with the arduino. Use two RS485 modules connect the A/B wires to both. On one module, connect RO to Arduino RX and DE/RE to 5V, on the other connect DI to Arduino TX and ground DE/RE. This forces each module on the arduino to a single purpose and rules out any problem with controlling DE/RE (which you have per the last sketch posted). Let's bypass the problem areas for now and get to something that works. Then we can go back and fix the bandaids later.

You don't need another arduino, you have a RS485-USB converter that you can use to see what is on the A/B lines using the PC.

progress :) yay

okay i tried hooking up 2 MAX485's and running one for transmit and one receive, and after ALOT of fidling around, i finaly changed the sketch to only receive serial data and display it on the serial monitor. then i used the RS485 to USB and used the PC to send the 10TR2 command.

that worked, but initially when i switched on the transmit from the arduino, i could only see an echo of the command i sent. it turned out i had to send an ENTER command after the 10TR2, so i switched to Serial1.println and it worked.

but i still cant get it to send and receive from the same module. for some reason even thou i take the wires completely off DE and RE on the transmit module, it still transmits, and i have to connect DE and RE to ground on the receive module in order to get that working.

maybe i just have a bad set of modules, but it seems to me i have to get a small transistor in there to switch the pins to ground when receiving (or remember a fluke tomorrow so i can see if it actualy goes low), in order to get it running on 1 module.

the current code (wire from pin 8 not mounted)

void setup() {
  Serial1.begin(9600);
  Serial.begin(9600);
  pinMode(8, OUTPUT);
}
void loop() {
  char getdata='m';
  digitalWrite(8,HIGH);
  Serial1.println("10TR2");
  delay(100); 
  digitalWrite(8,LOW);

  if(Serial1.available()){
  
    while(Serial1.available() && getdata!='d')
    { 
    getdata=Serial1.read();
    Serial.print(getdata);
    }
    Serial.println(" ");
    }
  delay(1000);
}

output in serial monitor (VV.V DDD TT.T) (V=windspeed D=wind direction T=temperature)

*44
10TR2
22:00:57.754 -> 00.1 067 +24.8 5 
E*45
10TR2
22:00:58.850 -> 00.0 000 +24.9 5E 
*44
10TR2
22:00:59.958 -> 00.0 000 +25.0 5E 
*4C
10TR2
22:01:01.023 -> 00.0 000 +25.0 5E 
*4C
10TR2
22:01:02.125 -> 00.0 000 +25.1 5 
E*4D
10TR2
22:01:03.253 -> 00.0 000 +25.2 5E 
*4E
10TR2
22:01:04.348 -> 00.0 000 +25.1 5E

so now at least i am getting some usefull data, just need to see if i can refine it a bit and get rid of that extra module.

then then next big step is going to be to get in transfered to a web server on a raspberry, but thats another headache :)

thanks alot for your help up to now adwsystems, it has realy helped me get on the right track everytime i was straying off the path :)

frichsness: but i still cant get it to send and receive from the same module. for some reason even thou i take the wires completely off DE and RE on the transmit module, it still transmits, and i have to connect DE and RE to ground on the receive module in order to get that working.

What you should have is: TX Module: -DE/RE on Tx module are connected to +5V -DI connected to Arduino Serial1 Tx -RO not connected

RX Module: -DE/RE on the Rx module are connected to ground -RO connected to Arduino Serial1 Rx -DI not connected

This will work, I have done this very thing to get my modbus RS-485 network and software working.

Once you connect DE/RE to the Arduino, you now must synchronize the transmit of data while the DE/RE line is high and not go low until everything is transmitted (not as easy as one would hope).

just an update :)

managed to get the whole thing simplified to the point of having only 1 RS485 module and the code cleaned up a bit.

but as you said getting the timing right was quite a bit of trail and error, i finally got it working at 7ms transmit time. with 6ms the 2 of the command string was missing every 3-4 loops, and at 9 it didn't switch to receive before the sensor sent it's data, so i would only get the last bit of the string.

it helped a lot to have the RS485 to USB in the circuit and monitoring that with putty.

but if anyone wants it later here is the final code i am using.

void setup() {
  Serial1.begin(9600);
  Serial.begin(9600);
  pinMode(2, OUTPUT);
}
void loop() {
  char getdata='m';
  digitalWrite(2,HIGH);
  Serial1.println("10TR2");
  delay(7); 
  digitalWrite(2, LOW);

  if(Serial1.available()){
  
    while(Serial1.available() && getdata!='d')
    { 
    getdata=Serial1.read();
    Serial.print(getdata);
    }
    Serial.println(" ");
    }
  delay(980);
}

I hate timers. You need to find out if there is a way to detect when the transmit is done. From a library I did not write, I think this is the command you need when using Serial1.

while (!(UCSR1A & (1 << TXC1)));

I would leave the line is receive by default, and change to transmit using the above code to determine when to change back to receive.