Placing Variables Into Character Array


Fairford

Recommended Posts

Hi

I am a DaqFactory novice so please excuse my ignorance if the following is trivial

I’m connected with a Sprint DC Variable Speed Drive through the RS232 port. Communication is established and I can perform basic parameter functions.

Using the line below, I can set the speed to 100%

device.Sprint.Write(chra({0x04,0x30,0x30,0x30,0x30,0x02,0x41,0x61,0x31,0x30,0x30,0x03,0x12}))
                                       (EOX) (GroupID)(   Unit ID  )(STX)( Mnemon)(      Value         )(ETX)(BCC)
Where:
EOX = End of transmission. Clears the line at start of new message
STX = Start of Text
ETX = End of text
BCC = Block Check Character – verification check digit which is exclusive OR of Mnemon to ETX
Mnemon = Two hex character ASCII mnemonic for parameter. Aa in this case = Speed
Value = ASCII hex representation of parameter value. In this case 100

Whilst EOX, GroupID, Unit ID, STX and mnemonic can remain fixed in each transmission, I’d like to be able to dynamically change the value and check block (BCC) so that I can change the speed of the drive by reading a slider value (or similar).

I’ve tried for many hours to place variables into the chra array to dynamically change the values and BCC, but I’ve failed miserably!

Please can anyone help.

With thanks

Link to comment
Share on other sites

You can't put variables in static array notation (i.e. {1,2,3} is fine, but {1, myVariable, 3} is not).  But write() just takes a string, and asca() generates a string, so you can just concatenate them:

 

device.Sprint.Write(chra({0x04, 0x30, 0x30, 0x30, 0x30, 0x02, 0x41, 0x61}) + format("%03d", val) + chr(0x03) + bcc)

 

where val is some number.  Format() with %03d will prefix val to 3 digits with 0's, so 5 becomes 005 and 32 becomes 032.  I'm not sure how you are calculating BCC, but lets say its just a sum of all the other characters rolled at 256.  Then I'd do:

 

private string out = chra({0x04, 0x30, 0x30, 0x30, 0x30, 0x02, 0x41, 0x61}) + format("%03d", val) + chr(0x03)

private bcc = sum(asca(out)) & 0xff

device.sprint.write(out + chr(bcc)

Link to comment
Share on other sites

  • 4 years later...

Hi, I'm trying to make a sequence function to formulate commands to be sent to a TMC stepper motor driver. Each command is in binary in 9 bytes, with some info about addresses, motors etc in each of first 4 bytes, then the value in the next 4 bytes (MSB), then the last being a checksum of the first 8 bytes. A typical command which works is this:

device.TMC.Poll(ChrA({1, 2, 0, 0, 0, 0, 0, 100, 103})) 

My function based on the topic above is this:

function Cmd(address, instruction, type, motor, valuein)
   private string out = format("%03d", address) + format("%03d", instruction) + format("%03d", type) + format("%03d", motor) + from.urbLong(to.uLong(from.urwLong(valuein)))
   private cks = sum(asca(out)) & 0xff
return(out + cks)

But isnt quite working - the Long conversion isnt concatenating with the rest of the string properly - could you tell me what I'm doing wrong please? Many thanks!

Link to comment
Share on other sites

There is a common misunderstanding concerning the difference between binary bytes, and ASCII values.  A serial stream is made up of bytes.  A byte is a number from 0 to 255.  A string is a bunch of bytes linked together one after another.  A string is typically represented by the ASCII coded representation of each byte.  ASCII is basically a coding scheme, where a byte value, say, 65, corresponds to a character used in the English language, in the case of 65, the upper case A.  I say English because ASCII is largely limited to A-Z and doesn't include characters with accents, or any non-english characters.  For that there are other mappings, the most common being UTF.  But let's stick to ASCII since that is what DAQFactory uses.  

As I said, a serial stream is just bytes.  Because the bytes are sent one after another (serially), it is convenient to use a string to store what bytes you are sending or receiving because a string is the same thing, a bunch of bytes one after another.  So, when you do chra({1,2,0,0,0,0,0,100,103}) you are taking an array of numbers, {1,2,0,0,0,...} and using the chra() function to convert it into a string where each character in the string corresponds to one of those numbers, in order.

In your case, that is it.  Everything is in binary.  In many serial streams, the device expects the ASCII representation of those numbers, not the numbers themselves.  So while 100 binary is just 100, "100" ascii is actually 49, 48 and 48, where 49 corresponds to 1, and 48 corresponds to 0.  The asca() function in DAQFactory takes a string and converts it into an array of bytes, so ? asca("100") returns {49,48,48}.   Doing ? chra({1,2,0,0,0,0,0,100,103}) is going to print next to nothing because the string starts with numbers below 32, and any number below 32 is, in ASCII, called a control character and is not printable.

Now, on to your code: when you do format("%03d", address) you are actually taking the number stored in address and converting it to the ASCII representation of that number.  So, if address was 100, the format command would return the string "100", which is actually the three bytes 49,48,48 which is definitely NOT what you are after.  You really just want the numbers going direct to the serial port.  So, you want something like this:

private out
out[0] = address
out[1] = instruction
out[2] = type
out[3] = motor
out[4] = from.urbLong(to.uLong(from.urwLong(valuein)))
private cks = sum(out) & 0xff
return(chra(concat(out, cks)))

 

 

Link to comment
Share on other sites

Hi again, the following line works perfectly:

device.QBCrig.Poll(ChrA({1, 1, 0, 0, 0, 0, 0, 100, 102}))

Even though the output, as you said, is just control characters:

? ChrA({1, 1, 0, 0, 0, 0, 0, 100, 102})

But using the function as you suggested (I changed 'out' to 'tosend' as I thought that might be conflicting somehow with the 'out' in the poll function but it isnt...):

function Cmdcopy(address, instruction, type, motor, valuein)
   private tosend
   tosend[0] = address
   tosend[1] = instruction
   tosend[2] = type
   tosend[3] = motor
   tosend[4] = from.urbLong(to.uLong(from.urwLong(valuein)))
   private cks = sum(tosend) & 0xff
return(chra(concat(tosend, cks)))

I get this:

device.QBCrig.Poll(Cmdcopy(1, 1, 0, 0, 100))
C1136 Timeout: Cmdcopy Line 20: Cmdcopy Line 28:  Line 1

and the actual output its trying to send is this:

? concat(tosend, cks)
{{1, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 100}, {2, 0, 0, 100}}

...which isnt correct, as there should always be 9 bytes sent and received. I'm confused as C1136 isnt in the user guide, and there are only 9 lines in the function above, so I assume lines 20 (Write(out)) and 28 (throw())refer to the poll function (basically the same as the given one), and there's a problem with the format from the function above. 

A little more help please?

Link to comment
Share on other sites

Brilliant, thanks, works great making control so much better than the trinamic IDE that came with the driver. The final code below for others if helpful:

function Cmd(address, instruction, type, motor, valuein)
   private tosend
   tosend[0] = address
   tosend[1] = instruction
   tosend[2] = type
   tosend[3] = motor
   tosend[4] = transpose(from.urbLong(to.uLong(from.urwLong(valuein))),0)
   private cks = sum(tosend) & 0xff
return(chra(concat(tosend, cks)))

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.