REXYGEN Community Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Login

    ASCII Commands Over RS485

    Communication (RS232, RS485, I2C, SPI, UDP, TCP, ...)
    2
    19
    1.6k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • G
      GeorgeDumitru
      last edited by

      Hi I am currently working on a project where I want to use a MonarcoHAT to control a DMX-K-SA-17 stepper motor controller. The two devices are communicating over RS-485 serial com (I Am using a USBtoRS485 connection). The DMX-K-SA-17 can be controlled using ASCII Commands. I have been struggling for a few weeks now to find a proper REXLANG Routine that will allow me to :
      a. Send commands in ascii format to the device
      b. Get the response of those commands once the command has been sent.

      Can anyone help me with this?

      J 1 Reply Last reply Reply Quote 1
      • J
        Jan Reitinger @GeorgeDumitru
        last edited by Jan Reitinger

        @georgedumitru Hi George,
        a. To send commands in ASCII format to the device, you can use the Write() 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 of a will be the number of bytes that were written to the device.
        b. To receive the response from the motor controller, you can use the Read() 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

        G 2 Replies Last reply Reply Quote 0
        • G
          GeorgeDumitru @Jan Reitinger
          last edited by

          @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!

          1 Reply Last reply Reply Quote 0
          • G
            GeorgeDumitru @Jan Reitinger
            last edited by

            @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.

            J 1 Reply Last reply Reply Quote 0
            • J
              Jan Reitinger @GeorgeDumitru
              last edited by

              @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.

              G 1 Reply Last reply Reply Quote 0
              • G
                GeorgeDumitru @Jan Reitinger
                last edited by

                @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.

                J 1 Reply Last reply Reply Quote 0
                • J
                  Jan Reitinger @GeorgeDumitru
                  last edited by Jan Reitinger

                  @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!

                  G 1 Reply Last reply Reply Quote 0
                  • G
                    GeorgeDumitru @Jan Reitinger
                    last edited by

                    @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;
                    }
                    
                    
                    
                    
                    
                    
                    
                    
                    J 1 Reply Last reply Reply Quote 0
                    • J
                      Jan Reitinger @GeorgeDumitru
                      last edited by Jan Reitinger

                      @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;
                      }
                      
                      G 1 Reply Last reply Reply Quote 0
                      • G
                        GeorgeDumitru @Jan Reitinger
                        last edited by

                        @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?

                        J 1 Reply Last reply Reply Quote 0
                        • J
                          Jan Reitinger @GeorgeDumitru
                          last edited by

                          @georgedumitru Hi George,
                          if you only need a control statement in the log, use Trace(1,data). If you want the string to output directly, this should work:

                          ...
                          string output(3) outputstring;
                          ...
                          outputstring = data;
                          

                          Cheers,
                          Jan

                          G 1 Reply Last reply Reply Quote 0
                          • G
                            GeorgeDumitru @Jan Reitinger
                            last edited by

                            @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:

                            a3c625d1-eb27-44d0-bad6-45a86a04262f-image.png

                            J 1 Reply Last reply Reply Quote 0
                            • J
                              Jan Reitinger @GeorgeDumitru
                              last edited by Jan Reitinger

                              @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;
                              }
                              
                              
                              1 Reply Last reply Reply Quote 0
                              • G
                                GeorgeDumitru
                                last edited by

                                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?

                                J 1 Reply Last reply Reply Quote 0
                                • J
                                  Jan Reitinger @GeorgeDumitru
                                  last edited by

                                  @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 use double buf2double(buf[,endian]) REXLANG function.

                                  G 1 Reply Last reply Reply Quote 0
                                  • G
                                    GeorgeDumitru @Jan Reitinger
                                    last edited by

                                    @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?

                                    J 1 Reply Last reply Reply Quote 0
                                    • J
                                      Jan Reitinger @GeorgeDumitru
                                      last edited by

                                      @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?

                                      G 1 Reply Last reply Reply Quote 0
                                      • G
                                        GeorgeDumitru @Jan Reitinger
                                        last edited by

                                        @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.

                                        J 1 Reply Last reply Reply Quote 0
                                        • J
                                          Jan Reitinger @GeorgeDumitru
                                          last edited by Jan Reitinger

                                          @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.

                                          1 Reply Last reply Reply Quote 0
                                          • First post
                                            Last post

                                          This is a community forum for REXYGEN users and fans. Detailed information can be found at REXYGEN homepage.

                                          There is also an outdated REXYGEN community forum.

                                          Powered by NodeBB.