Read data from an RS-422 communicating Sensor

Hello everyone,

I have a protractor that communicates with Rs 422 and sends me data on the Roll and Pitch axes, i.e. the angular axes of x and y. How can I read this data in Automation Studio with Rs422 and assign the relevant variable where I read it, is there a sample application? I searched a bit in the help but I couldn’t find much.

image

Hello @omer.alumur ,

RS422 is just a variant of ‘serial communication’.

‘DVFrame’ is the library for this:

B&R Online Help (br-automation.com)

There are also two examples for it in online help:

B&R Online Help (br-automation.com)

3 Likes

There is already a structure set up for rs232 in an old project. However, what I was wondering was, in some B&R examples, the project is given with a simple ST or C code, but I could not see such a detailed example for this topic.

(********************************************************************
 * COPYRIGHT -- Bernecker + Rainer
 ********************************************************************
 * Program: Receiver
 * File: ReceiverCyclic.st
 * Author: Bernecker & Rainer
 * Created: January 25, 2010
 ********************************************************************
 * Implementation of program Receiver
 ********************************************************************)

(*************init program**********************)
PROGRAM _INIT
	Receiver.Commands.open_receive := TRUE;												(*enable Receiver by default*)						
END_PROGRAM

(*************cyclic program********************)
PROGRAM _CYCLIC


	CASE Receiver.step OF
		FRM_WAIT:	(*--- wait for command*)
			
			IF Receiver.Commands.open_receive = TRUE THEN								(*command for Receiver activation*)
				Receiver.step := FRM_OPEN;
			END_IF			
		
			(*close will be requested in step FRM_RBUF*)
		
		FRM_OPEN:	(*--- open serial interface*)
			
			(*Parameters for FRM_xopen()*)
			Receiver.FRM_xopen_0.enable := TRUE;
			Receiver.FRM_xopen_0.device := ADR('SL2.IF5');										(*Devicename --> see your serial interface properties*)
			Receiver.FRM_xopen_0.mode 	:= ADR('/PHY=RS232 /BD=57600 /DB=8 /PA=N /SB=1'); 		(*Modestring --> specifies the seria operation mode*)
			Receiver.FRM_xopen_0.config := ADR(Receiver.xopenConfig) ;							(*Additional Parameters, optional*)
			
			(*Additional Parameters for FRM_xopen()*)
			//			Receiver.xopenConfig.idle 		:= 10;											(*Idle time between two characters*)
			//			Receiver.xopenConfig.delimc 	:= 0;											(*activate two delimeters*)
			//			Receiver.xopenConfig.delim[0] 	:= 0; 											(*e.g. CR - carridge return -> dec 13*)
			//			Receiver.xopenConfig.delim[1] 	:= 0; 											(*e.g. LF - line feed -> dec 10*)
			//			Receiver.xopenConfig.tx_cnt 	:= 3;											(*number of transmit buffers*)
			//			Receiver.xopenConfig.rx_cnt 	:= 3; 											(*number of receive buffers*)
			//			Receiver.xopenConfig.tx_len 	:= 256; 										(*length of transmit buffers*)
			//			Receiver.xopenConfig.rx_len 	:= 256; 										(*lenght of receive buffers*)
			//			Receiver.xopenConfig.argc 		:= 0;											(*activate additional options*)
			//			Receiver.xopenConfig.argv 		:= 0;											(*parameters for additional options (check help)*)
		
			Receiver.FRM_xopen_0();														(*call the FRM_xopen() function*)
			
			IF Receiver.FRM_xopen_0.status = 0 THEN
				Receiver.step := FRM_READ;												(*Interface opend successfully --> next step*)
			ELSIF Receiver.FRM_xopen_0.status = BUSY THEN
				Receiver.step := FRM_OPEN;												(*operation not finished yet --> call again*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
			
		FRM_READ:	(*--- read data from serial interface*)
			Receiver.FRM_read_0.enable := TRUE;
			Receiver.FRM_read_0.ident := Receiver.FRM_xopen_0.ident;
			
			Receiver.FRM_read_0();														(*call the FRM_read() function*)
			
			IF Receiver.FRM_read_0.status = 0 THEN
				Receiver.step := FRM_COPY_RD_DATA;										(*system returned a valid data --> next step*)
			ELSIF Receiver.FRM_read_0.status = frmERR_NOINPUT THEN
				Receiver.step := FRM_READ;												(*no data available --> call again*)
			ELSIF Receiver.FRM_read_0.status = frmERR_INPUTERROR THEN
				Receiver.step := FRM_RBUF;												(*received Frame with defective characters, skip data*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
			
		
		FRM_COPY_RD_DATA: (*--- copy data out of the receive buffer*)
			memset(ADR(Receiver.receive_data),0,100);			(*clear read_data buffer*)
			memcpy(ADR(Receiver.receive_data),Receiver.FRM_read_0.buffer,Receiver.FRM_read_0.buflng);     (*copy and evaluate read data*)
			Receiver.step := FRM_RBUF;													(*release read buffer*)
			
			(*******************************************************************************************************************************)
			(* COPYRIGHT - Sanlab Robotic Team *)
			(* Author: Zülfikar Ali Erbudak - ali.erbudak@sanlab.net *)
			(* Description: Converting Received Data from Delta Ohm Anemometer HD52.3D17R to Readable Data Code *)
			
			text := Receiver.receive_data; 		(* text format: $$IIMDA,x.x,I,x.x,B,x.x,C,x.x,C,x.x,x.x,x.x,C,x.x,T,x.x,M,x.x,N,x.x,M*hh<CR><LF> *)
						
			IF MID(text,6,1) = '$$IIMDA' THEN	(* Check if first 6 characters are equal to $$IIMDA or not *)
				k := 0; 						(* Counter to find the location of commas *)				
				FOR i := 1 TO SIZEOF(text) DO
					character := MID(text,1,i); (* Get 1 character starting from the i'th term *)
					IF character = ',' THEN		(* Check if character is equal to comma(,) or not *)
						commaPosition[k] := i;	(* Example: commaPosition[0] := 7 means 1'st comma is located in 7'th term *)
						k := k + 1;			
					END_IF; 
				END_FOR;	
				Anemometer.P_Hg			:= STRING_TO_REAL(MID(text, commaPosition[1] -commaPosition[0] -1, commaPosition[0]+1));
				Anemometer.P_Bar		:= STRING_TO_REAL(MID(text, commaPosition[3] -commaPosition[2] -1, commaPosition[2]+1));
				Anemometer.T_CelAir		:= STRING_TO_REAL(MID(text, commaPosition[5] -commaPosition[4] -1, commaPosition[4]+1));
				Anemometer.T_CelWater	:= STRING_TO_REAL(MID(text, commaPosition[7] -commaPosition[6] -1, commaPosition[6]+1));
				Anemometer.H_RH 		:= STRING_TO_REAL(MID(text, commaPosition[9] -commaPosition[8] -1, commaPosition[8]+1));
				Anemometer.H_gm3		:= STRING_TO_REAL(MID(text, commaPosition[10]-commaPosition[9] -1, commaPosition[9]+1));
				Anemometer.D_Cel		:= STRING_TO_REAL(MID(text, commaPosition[11]-commaPosition[10]-1, commaPosition[10]+1));
				Anemometer.W_DGeo		:= STRING_TO_REAL(MID(text, commaPosition[13]-commaPosition[12]-1, commaPosition[12]+1));
				Anemometer.W_DMag		:= STRING_TO_REAL(MID(text, commaPosition[15]-commaPosition[14]-1, commaPosition[14]+1));
				Anemometer.W_SKnot		:= STRING_TO_REAL(MID(text, commaPosition[17]-commaPosition[16]-1, commaPosition[16]+1));
				Anemometer.W_Sms		:= STRING_TO_REAL(MID(text, commaPosition[19]-commaPosition[18]-1, commaPosition[18]+1));
			END_IF;
			(* Creation Date: 2021.05.15 *)
			(*******************************************************************************************************************************)

		FRM_RBUF:	(*--- release readbuffer*)
		
			(*Parameters for FRM_rbuf()*)
			Receiver.FRM_rbuf_0.enable 	:= TRUE;
			Receiver.FRM_rbuf_0.ident 	:= Receiver.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)
			Receiver.FRM_rbuf_0.buffer 	:= Receiver.FRM_read_0.buffer;					(*read buffer*)
			Receiver.FRM_rbuf_0.buflng 	:= Receiver.FRM_read_0.buflng;					(*length of sendbuffer*)
   			
			Receiver.FRM_rbuf_0();														(*call the FRM_rbuf() function*)
			
			IF Receiver.FRM_rbuf_0.status = 0 THEN
				IF Receiver.Commands.close = TRUE THEN
					Receiver.Commands.open_receive := FALSE;							(*disable command open_send*)
					Receiver.step := FRM_CLOSE;											(*request to close serial port*)
				ELSE				
					Receiver.step := FRM_READ;											(*read again*)
				END_IF
			ELSIF Receiver.FRM_rbuf_0.status = BUSY THEN
				Receiver.step := FRM_RBUF;												(*operation not finished yet --> call again*)
			ELSIF Receiver.FRM_rbuf_0.status = frmERR_INVALIDBUFFER THEN					
				Receiver.step := FRM_READ;												(*buffer is invalid --> read again*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
		
		FRM_CLOSE:	(*--- close the interface*)
			Receiver.FRM_close_0.enable := TRUE;
			Receiver.FRM_close_0.ident := Receiver.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)			
			
			Receiver.FRM_close_0();														(*call the FRM_close() function*)
			
			IF Receiver.FRM_close_0.status = 0 THEN
				Receiver.Commands.close := FALSE;										(*disable close command*)
				Receiver.step := FRM_WAIT;												(*closed interface successfully --> wait step*)
			ELSIF Receiver.FRM_close_0.status = BUSY THEN
				Receiver.step := FRM_CLOSE;												(*operation not finished yet --> call again*)
			ELSE
				Receiver.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

with RS422 only the .mode input of FRM_xopen changes.

Unfortunatly we don’t find find ‘device profiles’ as you’ll find in all fieldbuses.
The protocols are very special.

You usually talk about some ‘datagrams’ and ‘polling’. That means e.g. you send a serial datagram as request. This request is usually enclosed by control characters (e.g. STX, ETX).

After a timeout you can then expect a response from the sensor (which might also be enclosed by control characters).

Also the content of request/response could be ‘text data’ like ASCII commands or could be binary data like in Modbus/RTU.

So a better example would be very special. Every vendor can use what they want. You’ll need a detailled description of how the protocol was implemented.

1 Like

++
one further question is: is it really RS422 (>= 4 wires) or RS485 (>=2 wires).
For the latter it becomes more challenging since requests and responses must not overlap.