ASCII Commands Over RS485
-
@georgedumitru Hi George,
a. To send commands in ASCII format to the device, you can use theWrite()
function. For example, the following code will send the command@00DI[CR]
to the device:a = Write(socketHandle,"@00DI[CR]");
if
a>0
, the write command was successful (see the error codes in the REXLANG doc for Write() function). The value ofa
will be the number of bytes that were written to the device.
b. To receive the response from the motor controller, you can use theRead()
function. For example, the following code will receive up to 10 bytes of data from the device:dataCnt = Read(socketHandle,data,DATA_SIZE); //receive data, max number of bytes = DATA_SIZE if (dataCnt > 0) // data received { DO_SOMETHING }
I've defined data as the string and DATA_SIZE as a constant in the code before:
#define DATA_SIZE 10 //maximum number of bytes to receive string data[DATA_SIZE+1]; //buffer for incoming data
The
main()
procedure body can be a kind of state machine. I personally use a switch-case construction, but it can also be done externally using an ATMT block. For example, the following code will send a command in one tick and then wait to a response in the next ticks:switch(status) { case 0: a = Write(socketHandle,"@00DI[CR]"); if(a == 6) { status = 1; } break; case 1: dataCnt = Read(socketHandle,data,DATA_SIZE); //receive data, max number of bytes = BUFFER_SIZE if (dataCnt > 0) // data received { DO_SOMETHING status = 0; } break; default:
Please note that this is just a simple example, and you will need to modify it to fit your specific needs. Try to go step by step. First get a simple response from the controller and then create complex code.
Is there a reason why you are using the USB<->RS485 converter and not the RS485 directly on the Monarco HAT?
Cheers,
Jan -
@jan-reitinger said in ASCII Commands Over RS485:
te command was successful (see the error codes in the REXLANG doc for Write() function). The value of a will be the number of bytes that were written to the device.
Hi Jan, this is amazingly helpful. I just couldn't figure it out from the block documentation. This was exactly the pointer in the right direction I needed. Thank you very much!
-
@jan-reitinger As for why am I using a USB <-> RS-485, it was not my decision. If that is not going to meet my requirements in terms of speed, I will change it, but this is a project I jumped in kind of in the middle, after all the wiring and setup has been completed and I had nothing to say about it.
-
@georgedumitru Let me know how you're doing. I've also found it helpful to set the
status
as an output of REXLANG block and to use tracking using the Trace() function. However, it is necessary to have the "Function block messages: Information" option checked in the System Log Configuration in REXYGEN. -
@jan-reitinger Hi Jan, the write is successful but the read doesn't return anything. This is where I always have issues. For some reason the read almost always misses the replay from the device.
-
@georgedumitru Hello George,
Would you mind sharing the part of the project related to communication with the controller? If you prefer to keep it private, please feel free to send it to support@rexcontrols.com.
Thank you!
-
@jan-reitinger Hi Jan, here is the code of the entire block:
#define COM_BAUDRATE 9600 //baudrate, e.g. 9600, 19200, 57600, 115200 #define COM_PARITY_NONE 0 //no parity #define COM_PARITY_ODD 1 //odd parity #define COM_PARITY_EVEN 2 //even parity #define BUFFER_SIZE 20 // MAXIMUM NUMBER OF BYTES TO SEND #define COMMAND_LENGTH_MAX 20 //maximum length of command //Assigning parameters to variables, these variables are read-only; string parameter(0) serialdevice;//serial device is defined by parameter p0 of the REXLANG Block (e.g. /dev/ttyS0 in Linux or COM1 in Windows) //Assigning inputs to variables bool input(0) IsGreenButtonSignalOn; bool input(1) IsRedButtonSignalOn; bool input(2) IsYellowButtonSignalOn; bool input(3) IsProcedureStandardSignal; //Assigning Variables to Outputs, these variables are WRITE-Only bool output(0) IsDeviceReady; bool output(1) IsDeviceInError; bool output(2) IsDeviceRunning; string output(3) ResponseFromDMX; long output(14) DebugMessage; long output(15) ConnectionStatus; //Variables Declaration const long cr = 13; // (cr) is the termination character, carrige return (0Dh); long hCom, s, receive; // Communication Handle long buffer[BUFFER_SIZE]; // buffer for incoming data long dataCount; // Number of bytes sent bool read = true; string data[BUFFER_SIZE+1]; int status=0; long a; void HomeMotor(void){ long readData[6]; readData[0]='L'; readData[1]='H'; readData[2]='O'; readData[3]='M'; readData[4]='E'; readData[5]='-'; s=Send(hCom,readData,6); return; } void ClearError(void){ a=Write(hCom,"@DMK01EO=1[CR]"); if(a>0){ DebugMessage=a; } else{ DebugMessage=-1; } } void MoveTo1000(void){ a=Write(hCom,"@01J+"); if(a>0){ DebugMessage=a; status=0; } else{ DebugMessage=-1; } } //the init procedure is executed once when the REXLANG function block initializes long init(void) { /* PUT YOUR CODE HERE */ hCom=-1; return 0; } //the main procedure is executed repeatedly (once in each sampling period) long main(void) { /* PUT YOUR CODE HERE */ if(hCom<0) { hCom = OpenCom(serialdevice,COM_BAUDRATE,COM_PARITY_NONE); //Opening Serial Device ConnectionStatus=hCom; } switch(status) { case 0: a=Write(hCom,"@00EO[CR]"); if(a>0){ status=1; } break; case 1: dataCount = Read(hCom, data,BUFFER_SIZE); if(dataCount>0){ if(data=="1"){ ResponseFromDMX="ON"; } else{ ResponseFromDMX="OFF"; } status = 0; } default: break; } return 0; } //the exit procedure is executed once when the task is correctly terminated // (system shutdown, downloading new control algorithm, etc.) long exit(void) { /* PUT YOUR CODE HERE */ if(hCom>=0){ Close(hCom); } return 0; }
-
@georgedumitru, I believe there's a mistake in the Write command. Instead of using the [CR], it should be the ASCII symbol "\r". My apologies for not thoroughly reading the controller manual. Furthermore, I'm considering putting the switch into an else statement:
long main(void) { /* PUT YOUR CODE HERE */ if(hCom<0) { hCom = OpenCom(serialdevice,COM_BAUDRATE,COM_PARITY_NONE); //Opening Serial Device ConnectionStatus=hCom; } else { switch(status) { case 0: a=Write(hCom,"@00EO\r"); if(a>0){ status=1; } break; case 1: dataCount = Read(hCom, data,BUFFER_SIZE); if(dataCount>0){ if(data=="1"){ ResponseFromDMX="ON"; } else{ ResponseFromDMX="OFF"; } status = 0; } default: break; } } return 0; }
-
@jan-reitinger Hi Jan, sorry if I'm being difficult here, but I am just curious, I am receiving a string in the return message. How can i process that to have the string in the output of the block? I managed to get a response from the device, and as long as the response is a single byte, that works just fine, but I am struggling to get a string out of the buffer. Do you have any suggestions?
-
@georgedumitru Hi George,
if you only need a control statement in the log, useTrace(1,data)
. If you want the string to output directly, this should work:... string output(3) outputstring; ... outputstring = data;
Cheers,
Jan -
@jan-reitinger said in ASCII Commands Over RS485:
trol statement in the log, use Trace(1,data). If you want the string to output directly, this should work:
That's what I thought, but every time I try to do that I get this as an error:
-
@georgedumitru Could you post line 111 here or ideally the whole code again?
This minimal example works for me:
#define BUFFER_SIZE 20 string output(1) outputstring; string data[BUFFER_SIZE+1]; long init(void) { data = "hello there"; return 0; } long main(void) { Trace(1,data); outputstring = data; return 0; } long exit(void) { return 0; }
-
Can you please help me with a conversion? I need to interrogate the position of the stepper motor, they have an ascii command I can send to do that, but the response is a 28-bit number. Can you tell me what I can use to get that number from the buffer?
-
@georgedumitru Hi,
When we refer to a 28-bit number, does this imply that the number is transmitted within 4 bytes? If that's the case, and the number is in floating-point format, you should usedouble buf2double(buf[,endian])
REXLANG function. -
@jan-reitinger said in ASCII Commands Over RS485:
buf2double
Hi, the number is not in floating-point format, is actually an int. But what I don't understand is how to use your function What exactly does it take in the argument. I never seen a function taking anything like yours and if I call just double myDouble = buf2double(myBuffer) I expect 100.000 and I get -7.403 669 410 330E-171 . So, how exacttly do i solve this?
-
@georgedumitru
Hello George,It's challenging to give advice remotely when I can't see what's happening. The data might be in a different format than expected. Could you use Trace() to print the contents of the buffer and share it here?
-
@jan-reitinger can you direct me to some documentation that shows how to actually use Trace() as I could definitely use that for myself too.
-
@georgedumitru I think the best documentation is this thread here on the forum. Byte array reading from communication is also discussed there.
Another helpful tool is definitely the example located at C:\Program Files\REX Controls\REXYGEN 2.50.12.14711\Examples\0203_Function_Blocks_REXLANG.