Forum Home › Forums › Understanding the Software › Using Formulas › V6 Formula to extract 2 int8_t values from a Modbus ushort register
Tagged: V6 Formula
- This topic has 8 replies, 3 voices, and was last updated 11 months, 2 weeks ago by Mikhail.
-
AuthorPosts
-
May 14, 2023 at 2:01 am #12582MerdockParticipant
Hello, I have this formula that extracts 2 int8 values from a holding register.
in the channel I apply it as follows:
the value is read in channel 118
“GetI8ByteDirect(Val(118),0)” here I get the first byte.
“GetI8ByteDirect(Val(118),1)” here I get the value of the second byte.
2 queries.
1 – note that when using bitmask the formula that is loaded is: “GetBit(DataRel(-1), 0)” for bit 0 and so on for the other bits.
What function does DataRel() fulfill?
Also note that in the webstation in the table if the device is not connected it shows “–” and my formula shows “0”
How do I make my formula also show “–” when the device is disconnected?
2- How do I write or modify the 2 Bytes of my formula with a command?
Something like putting in the output channel SetI8ByteDirec(Value, 0 or 1)//This function takes the same arguments as the original function: //a value of type double called val and a value of type int called n. //The function returns a value of type byte. public sbyte GetI8ByteDirect(double val, int n) { int lVal = (int)val; return (sbyte)((lVal >> (n * 8)) & 0xFF); } //Inside the function, the val value is converted to a value of type ulong and stored in the variable ulVal. //Then shift the bits of ulVal (n * 8) positions to the right and apply an AND operation with the value 0xFF. //The result of this operation is returned as a value of type byte. //This function returns the value of the byte at position n of the value val. //For example, if you want to get the first byte of the value val, //you can call the function with the argument n equal to 0. //If you want to get the second byte of the val value, //you can call the function with the argument n equal to 1, and so on.
May 14, 2023 at 7:18 pm #12583manjey73ParticipantGet I 8 Byte Direct(Vol(118),0); Stat(118)
May 14, 2023 at 7:26 pm #12584manjey73Participant2 One of the ways. You need to turn the CmdVal into a byte, Then, depending on whether it is older or younger, add it with the calculated byte of the second half and only then send the command. For example, if you change the highest byte. (Convert.Toint16(Cmd) >> 8) || Convert Uint16(Val(119)) where 119 is the value that you do not change and it is the lowest byte. Something like that
I haven’t checked. Perhaps you can solve it differently or turn it into bytes beforehand, or apply a mask, and so on
May 14, 2023 at 7:28 pm #12585manjey73ParticipantWell, bind the control command to the required channel that you are changing. To change the major and minor bytes, the write formulas will be different, just as you have made the formulas for obtaining the minor and major bytes different.
May 14, 2023 at 7:34 pm #12586manjey73ParticipantOr for example like this
For Low Byte
Mask Input channel 118 – X = (ushort)Val(118) && 0xFF00
Further – X || (ushort)CmdFor Older Byte
Mask Input channel 118 – X = ((ushort)Val(118)>>8) && 0xFF
Further – X || ((ushort)Cmd>>8)- This reply was modified 11 months, 2 weeks ago by manjey73.
May 15, 2023 at 12:29 am #12588MerdockParticipantMay 15, 2023 at 2:52 am #12590MerdockParticipantFixed, full explanation:
Formula to read 2 int8_t data stored in 1 holding register.public byte GetUi8Byte(double val, int n) { int lVal = (int)val; return (byte)((lVal >> ((1 - n) * 8)) & 0xFF); }
Script to write uint8_t values to the output
public double InsertByte(double valueToInsert, double destinationValue, bool insertInMostSignificantByte) { // Convert the input values to the corresponding types ushort val = Convert.ToUInt16(valueToInsert); ushort destVal = Convert.ToUInt16(destinationValue); ushort result; if (insertInMostSignificantByte) { result = (ushort)((destVal & 0x00FF) | (val << 8)); } else { result = (ushort)((destVal & 0xFF00) | val); } // Convert the result to double before returning it return Convert.ToDouble(result); }
We create 3 input channels in the table:
Channel 101 = data of 16 uint16_t
Channel 102 = uint8_t data 1
Input formula for channel 102GetUi8Byte(Val(101),0); Stat(101)
Channel 103 = data 2 uint8_t
Input formula for channel 103GetUi8Byte(Val(101),1); Stat(101)
Formula to write to the output channel:
Channel 102InsertByte(Cmd, Val(101), true)
channel 103InsertByte(Cmd, Val(101), false)
- This reply was modified 11 months, 2 weeks ago by Merdock.
May 15, 2023 at 3:20 am #12592MerdockParticipantAdd an overflow protection for the uint8_t value, so if it exceeds the value of 255 it will set the command to 255.
You could also make it not modify the output value if the limit of 255 is exceeded.public double InsertByte(double valueToInsert, double destinationValue, bool insertInMostSignificantByte) { // Protect against overflow of valueToInsert if (valueToInsert > 255) { valueToInsert = 255; } // Convert the input values to the corresponding types ushort val = Convert.ToUInt16(valueToInsert); ushort destVal = Convert.ToUInt16(destinationValue); ushort result; if (insertInMostSignificantByte) { result = (ushort)((destVal & 0x00FF) | (val << 8)); } else { result = (ushort)((destVal & 0xFF00) | val); } // Convert the result to double before returning it return Convert.ToDouble(result); }
Here the protection of the input value is that nothing is modified if the value exceeds 255
public double InsertByte(double valueToInsert, double destinationValue, bool insertInMostSignificantByte) { // We check if the value to insert is greater than 255 and we return the destination variable unchanged if (valueToInsert > 255) { return destinationValue; } // Convert the input values to the corresponding types ushort val = Convert.ToUInt16(valueToInsert); ushort destVal = Convert.ToUInt16(destinationValue); ushort result; if (insertInMostSignificantByte) { result = (ushort)((destVal & 0x00FF) | (val << 8)); } else { result = (ushort)((destVal & 0xFF00) | val); } // Convert the result to double before returning it return Convert.ToDouble(result); }
- This reply was modified 11 months, 2 weeks ago by Merdock.
May 15, 2023 at 11:50 am #12610MikhailModeratorHello,
1 – note that when using bitmask the formula that is loaded is: “GetBit(DataRel(-1), 0)” for bit 0 and so on for the other bits.
What function does DataRel() fulfill?The DataRel function provides data (value and status) of the channel having the specified offset from the current channel. You can find this function in the Scripts table.
How do I make my formula also show “–” when the device is disconnected?
In Rapid SCADA 6 a formula can return value of the
CnlData
type that contains value and status. In some cases, it allows to make formulas shorter. Using;
as before is also supported. SeeGetBit
implementation.How do I write or modify the 2 Bytes of my formula with a command?
Command value is provided by
Cmd
variable of the double type. -
AuthorPosts
- You must be logged in to reply to this topic.