Packed BCD to decimal in Crimson 3.1?

ELake20

Lifetime Supporting Member
Join Date
Aug 2003
Location
N. Michigan
Posts
271
Hello,

I am stumped on how to tackle this issue.

I am working on an Energy project on a solar / wind farm and I am trying to read in some data from a couple of smart meters. I have attached the data breakdown. They are using this archaic data type I haven't encountered before.

My thought was to read each byte as binary individually and then reassemble as a decimal, but I don't see how to create a single byte tag they are all word, long or real type.

Even still I cannot read raw binary from the register, it is always in decimal format.

Is there something simple I'm missing?

F19Data.png ModScan1.png
 
I think you can use the Manipulation setting of "BCD to binary" to handle this. You'll probably have to do this for two tags set up as Long integers (32 bits each) and then do some math to combine them, or leave them as separate tags, since combining them into a 32 bit float would cost some precision.
 
Using the built-in BCD unpacking functions in Crimson would probably be the best method as Paul mentioned. But you could also do it the hard way with some code.

Determine the value of each digit by ANDing the corresponding register with a mask to clear all other bits, then shift right by the necessary number of places. (For sake of example, assuming the data is mapped to tags named with address numbers from your screenshot.)

Code:
dig0 := (addr02853 & 0x000F);
dig1 := (addr02853 & 0x00F0) >> 4;
dig2 := (addr02853 & 0x0F00) >> 8;
dig3 := (addr02853 & 0xF000) >> 12;

dig4 := (addr02852 & 0x000F);
dig5 := (addr02852 & 0x00F0) >> 4;
dig6 := (addr02852 & 0x0F00) >> 8;
dig7 := (addr02852 & 0xF000) >> 12;

dig8 := (addr02851 & 0x000F);
dig9 := (addr02851 & 0x00F0) >> 4;
dig10 := (addr02851 & 0x0F00) >> 8;
dig11 := (addr02851 & 0xF000) >> 12;

dig12 := (addr02850 & 0x000F);
dig13 := (addr02850 & 0x00F0) >> 4;
dig14 := (addr02850 & 0x0F00) >> 8;
dig15 := (addr02850 & 0xF000) >> 12;
Then it's just a matter of adjusting the digits by the proper factor of 10 to determine the final value.

Code:
value := dig0 + dig1*10 + dig2*100 + dig3*1000 + dig4*10000 + dig5*100000 + dig6*1000000 + dig7*10000000 + dig8*100000000 + dig9*1000000000;
Crimson works in signed 32-bit integers which can only hold a value of +/-2,147,483,648. With 16 digits, the transmitted value could potentially exceed that so you'd either have to drop the extra digits or work out some 64-bit math.
 
Thanks for the replies!

I created (4) tags and read the modbus addresses individually, with BCD to Binary as noted above.

So my total expression I used is:
S_Total := addr2852 + addr2851*10000 + addr2850*100000000;

I did lose some precision by punting addr2853 but it does increment pretty quick on the solar side since it was sunny today.

What would the interpretation look like as 64 bit in Crimson? There doesn't appear to be any easy tool for much on this job. I get spoiled with all of the functions for data conversions in all of the usual PLC packages I usually use!
 
Do you need to perform any math on the resulting integer? If not, I would keep it as two 32 bit words, set the LSW format with leading zeros, and place them side by side on your displays.


If you need to use the 64 bit integer in any expressions or math, then you might want to do some trials with the 64-bit floating point functions built into Crimson 3.1. I have no 1st hand experience with those, but the Crimson help file has a decent explanation.
 
Do you need to perform any math on the resulting integer? If not, I would keep it as two 32 bit words, set the LSW format with leading zeros, and place them side by side on your displays.


If you need to use the 64 bit integer in any expressions or math, then you might want to do some trials with the 64-bit floating point functions built into Crimson 3.1. I have no 1st hand experience with those, but the Crimson help file has a decent explanation.

Unfortunately I have to do some math, I calculate monthly output from these numbers
 
In that case, I would recommend putting some of the value after the decimal point and try your luck with 32 bit floats. If the precision is not good enough, dig into the reference manual on the 64 bit floating point functions. It probably will not be too much extra work to get it to do what you need.
 
In that case, I would recommend putting some of the value after the decimal point and try your luck with 32 bit floats. If the precision is not good enough, dig into the reference manual on the 64 bit floating point functions. It probably will not be too much extra work to get it to do what you need.


Assuming IEEE-754, 64-bit floats (double precision) have enough mantissa bits (53 = 64 - 1(sign) -11(exponent) + 1(hidden)) to represent numbers with up to 16 decimal digits (53 x .3 ~ 16).
 

Similar Topics

hi... i have an issue in s7 300 plc, while we run the machine(in idle there is no fault) , plc cpu goes in SF mode, after restart the power cycle...
Replies
2
Views
117
Hi. I’m doing a PV 1400e to PVP 7 migration and I don’t know how to convert the old 8digit BCD type from PB1400e into something that will work on...
Replies
2
Views
589
I'm working on converting an old PanelBuilder 1200 HMI application into FactoryTalk View ME. The PLC was an old SLC 5/02 with a scanner card for...
Replies
2
Views
1,104
I have a Cmore screen which is communicating to the DL06 in BCD and need to create a timer that works in real numbers for a test, I simply need to...
Replies
3
Views
2,133
Studio 5000 v24.11 on a 1769-L33ERM Pretty simple question today! I have a piece of testing hardware with four outputs wired to four inputs on my...
Replies
5
Views
1,637
Back
Top Bottom