RS485 communication x20 series

Hello,

i’m trying to connect my x20cp0484 to a third party device for RGB lights ;
the controller for RGB only accepts RS485 commandos

has anybody some startcode to share ? i’ve tried the dvframe library but the external controller doesn’t reacts.

i have the x20bb53 socket in my project.

thanks you all

Hello Sven,

welcome to the Community!

First, DVFrame is the right choice to develop a communcation via a serial interface to a 3rd party device.
To get a serial communication up and running does not only depend on the right settings of the interfaces itself, but depending on the communication partners also in some cases on the protocol implementation itself: some devices may not react even if settings and base code setup are right, as long as the protocol is not as expected by the 3rd party device.

But let’s start at the beginning:
RS485 connection has to be terminated at the first and the last device - X20BB53 has a little switch at the bottom to activate the built-in termination resistor - if it’s activated you can see that the “T” led on the X20BB53 is on.
If the 3rd party device is the last device at the RS485 bus, it has to be terminated, too.

With Automation Studio installation, some samples for libraries are available. For DVFrame, the sample code can be imported directly from the following folder:


Of course this samples have to be adapted to the device and the protocol needs, but it’s a good starting point to dig deeper into DVFrame functions.
What’s implemented in and how the demo code works is described here in Automation Help.

For using the RS485 on BB53 you have to change in the demo code at least the FRM_xopen.mode string to the 3rd party device settings for baudrate (/BD), data bits (/DB), parity (/PA), stopp bits (/SB), and tell the function block that we’re using a RS485 interface (/PHY).

The following screenshot shows a example for X20BB53’s interface (the interface name is IF1 like shown in the hardware tree), and a setup for “RS485 interface using a baudrate of 115.2kBit, 8 data bits and 1 stopp bits, parity none”:

The usage of the parameter string is described here in the Automation Help

After setting the right parameters for the 3rd party device, then you can go on with sending and receiving data.
Of course, this now depends highly on the device / protocol itself, so I can’t provide more tipps/ideas about that without having much deeper knowledge about the device itself.

But I hope the information above helps a little, have a nice weekend!

Hello Alexander,

thank you for the clear explanation!
i will look into it and try to solve my problem

the tip of the end resitor is also nice, it is like CAN bus communication.

regarding the third party device, i only know 9600/8/1/n parameters and the parameter to send

PL1 string for activate
PL0 string for deactivate

with regards and thanks a lot

Hi Sven,

sometimes such devices also expect carriage return and / or line feed at the end of a command, like as they are sent by a terminal program.

When using a IEC language like structured text, such special characters are escaped by ‘$’ character. So maybe you have to send for example ‘PL1$r$n’ to “emulate” that the command was sent from a terminal.

Best regards, Alex

Hello @SvenG

It looks like you got some good answers from Alexander and it has been a couple of weeks since the last activity on this post. If the answers helped you with your question, can you help the next person with the same question by marking the solution on the information which helped you the most. If you still have open questions on this topic, can you provide an update? Thanks!

Hello,

I’m still struggeling with this issue, i’m trying to figure out what could be the problem, but Alexander has given me a good explanation

sven

1 Like

Hello Alexander,

not any white smoke for the moment,
but i’ve received some more details from the supplier

• Baud rate: 9600 baud, 8 data bits, 1 stop bit, no parity

image

do you see something that i could try
i’m using the standard testprogram from the samples site, where i did modify
. FRM_PREPARE_SENDDATA: (— prepare senddata, copy data to sendbuffer)
(simulate counter up)
Sender.send_data := ‘PL1’;
strcpy(Sender.FRM_gbuf_0.buffer,ADR(Sender.send_data)); (copy senddata to sendbuffer)

		Sender.step := FRM_WRITE;

with regards
sven

Hi Sven,

Is the settings screenshot from a terminal program that communicates with the device?
If yes, are you typing in the command “PL1”, and if yes do you have to press Enter before the device reacts?

I’m asking because I see that there’s no end-of-line attached by the settings, but if you’re pressing Enter in a terminal program, normally anyway the CR + LF will be send.
And, very unusual, but maybe the device needs to receive the command byte by byte with some pause time in between? To be honest I don’t think so, but that’s the only thing coming in my mind, rest of it looks normal so far.

I’ll try to have a deeper look into at the weekend, can you please share information about the device (name, manufacturer, and so on), thanks!

Best regards!

Hey Alexander;

I ordered a USB-Serial cable to test the terminal program Termite myselve and to be sure that the plc from the Lights did work :slight_smile:

When i use the program the lights go on/off with the commando PL1 and PL0 but i need to press enter. The commandos are case sensitive. in the output window you also see the HEX convertion

image

With the PLC nothing happens ;-(
this is the watch result

And this is the source code i use, almost copy / paste from the demo program
i tried to add $R - $R$L - $L but all stays the same

if you see something that i do wrong i would be happy !

(********************************************************************

  • COPYRIGHT – Bernecker + Rainer

  • Program: Sender
  • File: SenderCyclic.st
  • Author: Bernecker & Rainer
  • Created: January 25, 2010

  • Implementation of program Sender
    ********************************************************************)

(init program*********)
PROGRAM _INIT
// Sender.Commands.open_send := TRUE; (enable sender by default)
END_PROGRAM

(cyclic program*******)
PROGRAM _CYCLIC
commando := ‘PL1’;

CASE Sender.step OF
	FRM_WAIT:	(*--- wait for command*)
			Sender.Commands.close := 0;	
		IF Sender.Commands.open_send = TRUE THEN								(*command for sender activation*)
			Sender.step := FRM_OPEN;
		END_IF			
	
		(*close will be requested in step FRM_WRITE*)
	
	FRM_OPEN:	(*--- open serial interface*)
		
		(*Parameters for FRM_xopen()*)
		Sender.FRM_xopen_0.enable := TRUE;
		Sender.FRM_xopen_0.device := ADR('IF1');										(*Devicename --> see your serial interface properties*)
		Sender.FRM_xopen_0.mode := ADR('/PHY=RS485 /BD=9600 /DB=8 /PA=N /SB=1'); 		(*Modestring --> specifies the seria operation mode*)
		Sender.FRM_xopen_0.config := ADR(Sender.xopenConfig) ;					(*Additional Parameters, optional*)
		
	
		
		Sender.xopenConfig.idle := 4;											(*Idle time between two characters*)
		Sender.xopenConfig.delimc := 0;											(*activate two delimeters*)
		Sender.xopenConfig.delim[0] := 13; 										(*CR - carridge return -> dec 13*)
		Sender.xopenConfig.delim[1] := 10; 										(*LF - line feed -> dec 10*)
		Sender.xopenConfig.tx_cnt := 2;											(*number of transmit buffers*)
		Sender.xopenConfig.rx_cnt := 2; 										(*number of receive buffers*)
		Sender.xopenConfig.tx_len := 256; 										(*length of transmit buffers*)
		Sender.xopenConfig.rx_len := 256; 										(*lenght of receive buffers*)
		Sender.xopenConfig.argc := 0;											(*activate additional options*)
		Sender.xopenConfig.argv := 0;											(*parameters for additional options (check help)*)

			Sender.send_data := commando;
		(*parameters for additional options (check help)*)

		Sender.FRM_xopen_0();													(*call the FRM_xopen() function*)
		
		IF Sender.FRM_xopen_0.status = 0 THEN
			Sender.step := FRM_GBUF;											(*Interface opend successfully --> next step*)
		ELSIF Sender.FRM_xopen_0.status = BUSY THEN
			Sender.step := FRM_OPEN;											(*operation not finished yet --> call again*)
		ELSE
			Sender.step := FRM_ERROR;											(*function returned errorcode --> check help*)
		END_IF			
		
	FRM_GBUF:	(*--- aquire sendbuffer for FRM_WRITE*)
		Sender.FRM_gbuf_0.enable := TRUE;
		Sender.FRM_gbuf_0.ident := Sender.FRM_xopen_0.ident;
		
		Sender.FRM_gbuf_0();													(*call the FRM_gbuf() function*)
		
		IF Sender.FRM_gbuf_0.status = 0 THEN
			memset(Sender.FRM_gbuf_0.buffer,0,Sender.FRM_gbuf_0.buflng);		(*clear sendbuffer*)
			Sender.step := FRM_PREPARE_SENDDATA;								(*system returned a valid buffer --> next step*)
		ELSIF Sender.FRM_gbuf_0.status = BUSY THEN
			Sender.step := FRM_GBUF;											(*operation not finished yet --> call again*)
		ELSE
			Sender.step := FRM_ERROR;											(*function returned errorcode --> check help*)
		END_IF			
		
	
	FRM_PREPARE_SENDDATA: (*--- prepare senddata, copy data to sendbuffer*)
													(*simulate counter up*)
	
	strcpy(	ADR(Sender.send_data) , ADR(commando));
				(*attach value*)
		strcpy(Sender.FRM_gbuf_0.buffer,ADR(Sender.send_data));		
		
		Sender.step := FRM_WRITE;												(*--> next step*)
	
	FRM_WRITE:	(*--- write data to interface*)
		
		(*Parameters for FRM_write()*)
		Sender.FRM_write_0.enable := TRUE;
		Sender.FRM_write_0.ident := Sender.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)
		Sender.FRM_write_0.buffer := Sender.FRM_gbuf_0.buffer;					(*sendbuffer*)
		Sender.FRM_write_0.buflng := strlen(ADR(Sender.send_data));				(*net length of senddata*)
		
		Sender.FRM_write_0();													(*call the FRM_write() function*)
		
		IF Sender.FRM_write_0.status = 0 THEN
			IF Sender.Commands.close = FALSE THEN								(*requst to close the serial port*)
				Sender.Commands.open_send := FALSE;								(*disable command open_send*)
				Sender.step := FRM_CLOSE;
			ELSE
				Sender.step := FRM_GBUF;										(*writing successful --> get next sendbuffer*)
			END_IF
		ELSIF Sender.FRM_write_0.status = BUSY THEN
			Sender.step := FRM_WRITE;											(*operation not finished yet --> call again*)
		ELSE
			Sender.step := FRM_ROBUF;											(*function returned errorcode --> check help*)
		END_IF			
		
	FRM_ROBUF:	(*--- release sendbuffer in case of no successful write operation*)
		counterUp := counterUp +1;
		Sender.FRM_robuf_0.enable := TRUE;
		Sender.FRM_robuf_0.buffer := Sender.FRM_gbuf_0.buffer;					(*sendbuffer*)
		Sender.FRM_robuf_0.buflng := Sender.FRM_gbuf_0.buflng;					(*buffer length*)
		Sender.FRM_robuf_0.ident := Sender.FRM_xopen_0.ident;					(*ident open*)
	
		Sender.FRM_robuf_0();													(*call the FRM_robuf() function*)
	
		IF Sender.FRM_robuf_0.status = 0 THEN
			Sender.step := FRM_GBUF;											(*released buffer successful --> get next sendbuffer*)
		ELSIF Sender.FRM_robuf_0.status = BUSY THEN
			Sender.step := FRM_ROBUF;											(*operation not finished yet --> call again*)
		ELSE
			Sender.step := FRM_ERROR;											(*function returned errorcode --> check help*)
		END_IF			
	
	FRM_CLOSE:	(*--- close the interface*)
		Sender.FRM_close_0.enable := TRUE;
		Sender.FRM_close_0.ident := Sender.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)			
		
		Sender.FRM_close_0();													(*call the FRM_close() function*)
		
		IF Sender.FRM_close_0.status = 0 THEN
			Sender.Commands.close := 1;										(*disable close command*)
			Sender.step := FRM_WAIT;											(*closed interface successfully --> wait step*)
		ELSIF Sender.FRM_close_0.status = BUSY THEN
			Sender.step := FRM_CLOSE;											(*operation not finished yet --> call again*)
		ELSE
			Sender.step := FRM_ERROR;											(*function returned errorcode --> check help*)
		END_IF
		
	FRM_ERROR:	(*--- error handling*)
	; (*not implementet yet, check help for error codes*)
END_CASE	

END_PROGRAM

these are the termite program settings

image

with regards
sven

Hi Sven,

I can’t see any obvious error, I’m sorry.

The configuration seems to be ok.
From watch window, it seems that the data was sent (FRM_write_0.status = 0).
The hex sequence in Termite has a CR at the end, so I assume the data to send is “PL1$r”, but you also tried that…
… I’m running out of ideas, and unfortunately I don’t have a X20BB53 available so I can’t do a real test.

When you start sending from the PLC, can you please have a look on the yellow “S” LED of the X20PS module?
This LED indicates sending data, and it should at least flash once when your command is sent. Does it? (for test you could try to send the command more then once by changing the step sequence in the code, then the LED should flicker)

Also I’m sure you double-checked wiring
image

Sorry, no more ideas right now, but I promise I’ll keep thinking about!

Best regards, Alex

I don’t see anywhere that the $R$L characters are added to the command before sending.
The delim[0] and delim[1] are only used for receiving data, not sending.

brsstrcat(ADR(commando),ADR(‘$R$L’));
brstrccpy(ADR(Sender.send_data),ADR(commando));

or something like that.

You should not use the asstring library but the AsBrStr library instead. (This is on old sample)
The asstring library gives problems when in the project also c-tasks are used.

Hey Alexander

I see the S flashing once when sending !
i don’t know how to see what is actually send,
maybe there goes something wrong in the copy to the buffers

regarding cabling
i use 2 wires connected to RS485 DATA and RS485 DATA\ and allready swapped both wired and did al the tests again, to be sure i did not miss in + and -

we will try some more things :slight_smile:

with regards

Sven

Hello Corne,

i will try your suggetion for the STRCpy , maybe that will be the correct hint,
i allready added the $R and $L or a combination to the command, Alexander give me that tip.

i have a feeling that it will be something stupid at the end

keep you posted and thanks

sven

To activate RS485, it could be needed to send a dummy character before the PL0 or PL1 command.
Could you try perhaps the following command ‘$r$nPL0$r$n’ ?

It is also recommended nowadays to use FRM_writeAcknowledged instead of FRM_write.

Hi,

as I know because the LED flashes, at least “something” is sent from the interface… of course this is not the solution, but good to know!

If you have the possibility to build a adapter between your USB RS interface you’re using with your PC and the PLC, it would be interesting to see if data is received in the terminal program (and what data).

Best regards!

Hello Corne

i did modify the code like your suggestion

1/
commando := ‘PL1’;
returncommando := ‘$R$N’;

2/
brsstrcat(ADR(commando),ADR(returncommando));
brsstrcpy(ADR(Sender.send_data),ADR(commando));
brsstrcpy(Sender.FRM_gbuf_0.buffer,ADR(Sender.send_data));

3/
Sender.FRM_writeAcknowledged_0.enable := TRUE;
Sender.FRM_writeAcknowledged_0.ident := Sender.FRM_xopen_0.ident; (ident from FRM_xopen())
Sender.FRM_writeAcknowledged_0.buffer := Sender.FRM_gbuf_0.buffer; (sendbuffer)
Sender.FRM_writeAcknowledged_0.buflng := strlen(ADR(Sender.send_data)); (net length of senddata)

		Sender.FRM_writeAcknowledged_0();									

the result is the same :frowning:

but when i check the status on sending

is see that is display 65353 as status and
‘$01’ on internal

sven
image

Hi,

WriteAcknowledged stays in state 65535 = busy until sending the frame is confimed by the driver.
You have to keep calling the function block in every cycle until state changes away from 65535 and switches to 0 = success or <> 0 (means then error).

If the function block stays “longer” in state 65535, I think that’s an indicator that something is going wrong with the transmission of data to the wire… so in that case less the data string is the problem, but more the physical interface / wiring / electrial interference or other stuff like that.

Best regards!

Hello

it stays in that state and the “S” is flickering
back to the drawing boards :slight_smile:
sven

Oh wow, the interface definitely tries to send.
Is the RS485 line terminated at both sides?
Any possibility to ground both systems to the same potential? (from the PLC side, there’s the RS485 GND Pin for that)

Best regards!

Hello,
i did a recheck on wiring and nothing was wrong,
Both lines are terminated;
I staring to thing this project will not work with B&R equiment ;-(

i cannot find any more code examples

thank for all the help

Sven