Append an Int to an Int

asterof

Member
Join Date
May 2007
Location
Califonia
Posts
554
four modbus registers make up a single DINT

Int A
Int B
Int C
Int D

Lets day A = 1
Lets say B = 34
Lets say C = 56
Lets say D = 98

this would represent
1,34,56,98
using controllogix how can I combine them
to create 1,345.698

Register 41700-41703.
Read by placing the digits in order.
Eg. {41703 = 0000}, {41702 = 0002}, {41701 = 1578}, {41700 = 4571}
Total = 215,784.571
thanks
 
that would not be correct

Eg. {41703 = 0000}, {41702 = 0002}, {41701 = 1578}, {41700 = 4571}
Total = 215,784.571


you take D = 4571 needs to change to 4.571
so D / 1000 = 4.571
But then you take C = 1578 + 4.571 and you get 1582.571
then take B * 10 and you get 20 added to 1582.571 and
you get 1602.571, so as you can see that is not correct

Eg. A = {41703 = 0000}, B = {41702 = 0002}, C = {41701 = 1578}, D = {41700 = 4571}
Total = 215,784.571

looks like what needs to be done is
D / 1000 = 4.571
C * 10 = 1578
B * 100,000 = 200,000
A * ? = 0
Add D + C = 4.571 + 15780 = 15784.571
B = 2* 100,000 = 200,000 + 215784.571
however I am not sure this would work under all conditions
 
Last edited:
Damian's way would work, only if the number of digits was always constant.

I would say to use INT to ASCII, then Concatenate, then ASCII to INT.

Just because the Concatenate instruction will do all the work for you, and you don't have to worry about trying to use complicated code to count digits and adjust for zeros.

Edit:
I hope your decimal point is always a set number of digits. Seems odd, it sits right between the 5 and 6 in 56 in your example. If it is always a set number of digits, then in your example, just divide the resulting INT by 1000, and store it in a floating point.
 
Last edited:
Damian's way would work, only if the number of digits was always constant.

I would say to use INT to ASCII, then Concatenate, then ASCII to INT.

Just because the Concatenate instruction will do all the work for you, and you don't have to worry about trying to use complicated code to count digits and adjust for zeros.

Edit:
I hope your decimal point is always a set number of digits. Seems odd, it sits right between the 5 and 6 in 56 in your example. If it is always a set number of digits, then in your example, just divide the resulting INT by 1000, and store it in a floating point.

this is what I think I will need to do

Register 41700-41703.
41700 reads 4147
41701 reads 4115
41702 reads 1
41703 reads 0

This should read 141,154.147

but for the life of me I can not figure out how to combine then correctly
unless I convert 1 to a string, 4115 to a string, divide 4147 by 1000 and convert to a string
then append the strings
41702 is appended to 41703 = 41703 append 41702 = 01
41700 is appended to 41701 = 4115 append 4.147 = 41154.147
append 41154.147 to 01 = 0141154.147 convert back to a number you get 141,154.147
 
INT to ASCII, Concatenate, and ASCII to INT should work.

41703 -> INT to ASCII would result in 0
41702 -> INT to ASCII would result in 1
41701 -> INT to ASCII would result in 4115
41700 -> INT to ASCII would result in 4147

Concatenate 41703 and 41702 would result in 01
Concatenate that with 41701 would result in 014115
Concatenate that with 41700 would result in 0141154147

ASCII to INT that would result in an INT with value 141154147
Divide that by 1000 and put the result in a REAL, and you get 141154.147

Edit:
Again, if your decimal point is always in the same place. If it is, just divide by 1000 at the end to put the point there. If not, you need to do something based on where it should be.
 
Last edited:
MUL by .001, DIV by 1000, same thing. Glad it worked.

I imagine that this data is coming in from some serial device? A scale or meter?

Edit:
Wait, did you MUL by .0001 or .001?
 
There is a good chance that the values in 41700 to 41703 are BCD. In that case you need to convert to a binary integer first before you do the math.
 
"that would not be correct "

The concept is there, I just read it as 2 decimal places instead of 3.

Please re-read your example.
You said FOUR registers make up a single DINT.
A DINT is 32 bits.
32 bits divided by 4 equals 8bits.
Therefore your registers would be bytes.
You then define
A,B,C,D all as 2 digit integers, all within the range of a byte (2^8 = 256)
You then show all of those representing a continguous number.

In your second post, you then define all the registers as 4 digit integers.

Therefore A,B,C,D are now integers instead of bytes.
In this sense the original post was ambiguous.

---------------------------------------------------------------------------------
Now, getting back to the actual problem.

Lets assume that your registers are copied into an array of 4 16bit integers.

Lets name it ModWord, so you have ModWord[0], ModWord[1], ModWord[2], ModWord[3]

You can copy them in in any fashion you wish with the MSG block.

Let's make one "REAL" and call it "Answer"

All you need is one single CPT Function Block.

Set Destination as {Answer}

Set Expression as {0.001*ModWord[0]+10.0*ModWord[1]+100000.0*ModWord[2]+1000000000.0*ModWord[3]}

It will work in all cases.
One network.
One Function Block.

If instead you are working with Two DINTs instead, you would then have ModDint[0], and ModDint[1]

Set Expression as {0.001*ModDint[0]+100000.0*ModDint[1]}

Even simpler than before.

------------------------------------------------------------------------------
Now think about the ASCII solution.

Basically the controller has to convert your numerical characters to ASCII.

To do this it has to take each one of the digits, add 30hex to it, and make an array of contiguous bytes to store the characters.

Now it has to Move all those smaller groups of bytes into one large group of contiguous bytes.

Now it has to Convert it back into a number.
So your using an ASCII to INT instruction.

What does the ASCII to INT instruction do?

It has to subtract 30hex from each and every character to convert them back to numbers.

Then what does it have to do?

1*n0+10*n1+100*n2+1,000*n3+10,000*n4+100,000*n5+1,000,000*n6+10,000,000*n7+100,000,000*n8+1,000,000,000+10,000,000,000*n9+ ............ for all 16 digits. (I ran out of gas trying to type them all)

This should look familiar, because in large part it right back where we started from.

The only difference is the controller has to do a lot more work to get the same answer.

But now your still not even done, because you still have to divde that last number by 1000 to get your decimal places.

I can't image you would be able to find a simpler solution than below.

Compute Block.jpg
 
But what if the numbers go from:
1,1,1,1

which should result in:
1111 or 1.111

To:
199,200,201,202.

which should result in:
199200201.202 or 199200201.202

Your example, you are multiplying the larger number by 1 million, places 9 zeros ahead of it. The number of zeros that need to be added depends solely on the total number of digits in words 2, 1, and 0. In my first example, you need to add three zeros to word 3, because 2, 1, and 0 take up three digits of the result (pre division). In the second example, you need to add nine zeros to word 3, because 2, 1, and 0 make up nine digits of the result.

Your math would say that example 1 is:

1000100010.001

Which is not the same.
 
But what if the numbers go from:
1,1,1,1

which should result in:
1111 or 1.111

To:
199,200,201,202.

which should result in:
199200201.202 or 199200201.202

Your example, you are multiplying the larger number by 1 million, places 9 zeros ahead of it. The number of zeros that need to be added depends solely on the total number of digits in words 2, 1, and 0. In my first example, you need to add three zeros to word 3, because 2, 1, and 0 take up three digits of the result (pre division). In the second example, you need to add nine zeros to word 3, because 2, 1, and 0 make up nine digits of the result.

Your math would say that example 1 is:



Which is not the same.


Tharon,
I hear what you are saying, but my reasoning is that the device is clearly formatted to represent the value of the numbers as a full 16 digit number and that they are using each 16bit register to represent four digits. Therefore it would only make sense to build them all normally from right to left.

The difference between what we are talking about is you are treating leading zeros as null characters and I am saying that the leading zeros need to be treated as zeros.

Otherwise, the formatting is arbitray right? Put yourself in the place of the guy who designed the device. You want to send out a number larger than what you can represent with one registers, so your going to represent the number as the conjunction of several integers

By not "forcing" each integer to be four digits you create a situation where you could be interpretting many different values being sent to you as the same number.


A clear example of the problem with what your are saying is this. For simplicity lets ignore the decimal place. What if the device needs to send you the number


1,000,001,000,010,001

Based on your interpretation, you would end up calling this number

1000,0010,0001,0001 ^^^ 1000,10,1,1

so you would end up with 1001011

So, If I am the device, how do I send you the above number?

Gotta keep them zeros!
 

Similar Topics

I am a beginner with RS Logix and this is kind of a noob question. Every time someone uses my machine, my PLC program will have new data in 3...
Replies
1
Views
908
Hello i want to append a record to a text format device of Citect, but seems that it overwrite the record every time when open the device, i...
Replies
0
Views
1,274
Hi, is there any way to know in the PLC when turns power off and back on again. Because I need to reset a N7 register back to zero when that...
Replies
3
Views
1,744
OK this problem is taking too much time... I have a 1782-JDC RS-232/Devicenet converter which is feeding ASCII strings to a Keyence Micrometer...
Replies
2
Views
2,084
Will someone please convert this logic to pdf?
Replies
2
Views
144
Back
Top Bottom