Writing to the register


sadyrbek

Recommended Posts

Hi,

I have a Modbus slave device. Actually, this device has its own small software and I realized that it is Modbus. I can read many registers without any problem.

But, I have a problem with writing in it. When I analyze with port monitoring software, its software is sending following:

TX: 01 10 75 7F 00 01 02 00 CF C9 0C - writing the value CF to the register.no.757F

But, when I try to write using Daqfactory same things, it sends following:

TX: 01 10 75 7F 00 02 04 00 CF 00 00 4E 60

And, giving the fault : "CRC failed".

If you realize, there are four zeros are extras.

1.How can I write to the device exactly the same thing in first TX(original)?

2. This one is also longer than the others:

01 10 75 94 00 03 06 30 30 30 30 00 00 50 DE

does it writes to the 3 registers after the 7594?

thank you very much,

Link to comment
Share on other sites

I tried followings with Daqfactory and still problems:

float 01 10 75 7F 00 02 04 43 52 00 00 5A 0C

floatRbytes01 10 75 7F 00 02 04 00 00 52 43 92 C8

floatwords 01 10 75 7F 00 02 04 00 00 43 52 5E 94

skip2 01 10 75 7F 00 02 04 43 52 00 00 5A 0C

S16 01 06 75 7F 00 D2 22 43

S32 01 10 75 7F 00 02 04 00 D2 00 00 4E 60

S32word 01 10 75 7F 00 02 04 00 00 00 D2 6E 04

U32 01 10 75 7F 00 02 04 00 D2 00 00 4E 60

U32word 01 10 75 7F 00 02 04 00 00 00 D2 6E 04

I realized that when daqfactory writes something(bytes 6,7) after the register number (757F) there are the numbers multiplied with two (02 04 or 04 08), but its own software writes 01 02 or 02 04 or 03 06 as followings:

01 10 75 7F 00 01 02 00 CF C9 0C

01 10 2A 2C 00 01 02 00 75 EB D9

01 10 75 94 00 03 06 30 30 30 30 00 00 50 DE

when I use

Device.MyDevice.SetRegisterS32(1,30079,{0,210})

it sends:

01 10 75 7F 00 04 08 00 00 00 00 00 D2 00 00 F0 1D

Could you help me to find a failure please.

Why daqfactory writes the bytes 6,7 multiplied with 2 even I write to only one register?

Thanks,

Link to comment
Share on other sites

I tried all types.

float 01 10 75 7F 00 02 04 43 52 00 00 5A 0C

floatRbytes 01 10 75 7F 00 02 04 00 00 52 43 92 C8

floatwords 01 10 75 7F 00 02 04 00 00 43 52 5E 94

skip2 01 10 75 7F 00 02 04 43 52 00 00 5A 0C

S16 01 06 75 7F 00 D2 22 43

S32 01 10 75 7F 00 02 04 00 D2 00 00 4E 60

S32word 01 10 75 7F 00 02 04 00 00 00 D2 6E 04

U32 01 10 75 7F 00 02 04 00 D2 00 00 4E 60

U32word 01 10 75 7F 00 02 04 00 00 00 D2 6E 04

But there are the still problems. What is the meaning of byte 6 and 7?

Daqfactory always writes there 02 04 even I write something to only one register.

But other program writes 01 02 as following.

01 10 2A 2C 00 01 02 00 75 EB D9

01 10 75 94 00 03 06 30 30 30 30 00 00 50 DE

01 10 75 7F 00 01 02 00 CF C9 0C

Link to comment
Share on other sites

The problem is that your port monitoring software is using the 16 command "Set Multiple Registers" even when it wants to set a single register. This is sometimes seen when the programmer is lazy, though usually its on the device side, which might only support 16 or 6. Command 6 is "Set Single Register" and therefore does not have to specify how many words are being set. So, looking at these two:

S16 01 06 75 7F 00 D2 22 43

S32 01 10 75 7F 00 02 04 00 D2 00 00 4E 60

The command for S16 is 6, set single register. Its setting the value to 00D2. Note that this comes immediately after the address. For S32, it takes two words to set a 32 bit value, so DAQFactory has to use the 16 command (or 10 hex as your data shows). In this case, the two bytes after 75 7F, the 00 02 are the number of registers to set, in this case 2. It then passes the two values, 00D2 and 0000, which make up a 32 bit value of 000000D2.

This same thing applies to all the floating point choices. You see that U16 also uses command 6.

So, the bottom line is that the software that you are referencing too is actually incorrect. If your device only supports command 16, even when setting a single register, then use the S16 (16) I/O type. This is why we have two Set Register S16 I/O types. One uses the normal 6 command, and the other allows you to force DAQFactory to use 16 for devices that don't support it. Note that the function SetRegisterS16() will use 6 if you specify one value, and 16 if you specify more than one.

In addition, in your example when you use:

Device.MyDevice.SetRegisterS32(1,30079,{0,210})

You are actually setting 4 registers. You have two values, 0 and 210, but you are specifying these as 32 bit values (S32), which take 2 registers per value, so 4 total registers.

Link to comment
Share on other sites

Thank you very much for your help.

I have another question about this device.

When you start to connect to device via its own software it gives:

TX: 01 FA 00 00 00 00 00 00 75 7B 00 09 11 09

I am thinking that it is not MODBUS. Because there is no any Modbus Functions.

When it stay online, this software always makes a request from the device like followings:

01 FA 00 00 00 00 00 00 28 74 00 49 33 56

01 FA 00 00 00 00 00 00 75 7B 00 09 11 09

etc.

is this device Modbus? if I send .dll of this software, could you help me to adjust for Daqfactory?

thank you again,

Link to comment
Share on other sites

Correct. That is not modbus. FA is not a valid modbus command. That said, some hardware manufacturers will extend modbus and create their own modbus commands, so perhaps this manufacturer is using FA for some other purpose. You'd have to ask the manufacturer about it.

I would need both the .dll and either the .h file and/or the manual for the .dll. The dll alone won't help.

Link to comment
Share on other sites

Thank you very much for your help.

OK, lets say that my device is not Modbus, but user defined serial device.

I write followings CODE:

device.Mydevice.write(chra({1,0xFA,0x00,0x00,0x00,0x00,0x00,0x75,0x30,0x00,0x3E,
x20,0xC9}))
data = device.lamtec.read(100)
Mychannel.AddValue(asca(mid(data,15,2)))

when I write to my device, Mydevice responds as following:

1 FA 00 02 00 C8 18 E3 7C 00 51 00 00 00 00 01

E9 00 00 00 00 00 10 00 00 00 00 00 77 00 D2 FA

with function:

Mychannel.AddValue(asca(mid(datain[0],15,2)))
Mychannel={1,233}

01 E9= 1,233

But actually, Mychannel should be 489. (01E9= in decimal 489)

Which function should I use to get 489 from {1,233}?

Thanks a lot.

Link to comment
Share on other sites

You want to use the To. functions. This is actually exactly what they are designed for. These are a suite of functions for converting binary streams into real values. In this case you want To.urWord():

MyChannel.AddValue(To.urWord(asca(mid(datain[0],15,2))))

Link to comment
Share on other sites

Thank you very much.

With your perfect help, I am solving many problems of my devices.

My next question is about CRC.

Is there any complete sequence to calculate CRC16 in Modbus in Daqfactory?

My device that we talked about above use reversed CRC. I mean, when I use CRC calculator, for example, the CRC for the calculator is 0x3751, but my devices CRC is 0x5137.

If I find CRC sequence of Daqfactory for normal Modbus, I would modify it to my device.

Thank you very much again.

Link to comment
Share on other sites

No, because there are many different flavors of CRC. Do you have sample C code that shows your form of CRC? If so, post it and I can translate it to DF for you. Otherwise, if you want I can show you the standard Modbus CRC calc in DF.

Link to comment
Share on other sites

Here is the code:

function CalcCRC(string buffer)

private crc = 0xffff
private raw = asca(buffer)
for (private x = 0, x < GetLength(buffer), x++)
   crc = crc # raw[x]
   for (private j = 0, j < 8, j++)
	  if (crc & 0x0001)
		 crc = crc >> 1
		 crc = crc # 0xA001
	  else
		 crc = crc >> 1
	  endif
   endfor
endfor
return(crc)

Link to comment
Share on other sites

Buffer is a string parameter to the CalcCRC function. Since the .write() function of the serial port takes a string, I made this function take one too. So, if you'd assembled a string with your call:

private string out = chra({1,0xFA,0x00,0x00,0x00,0x00,0x00,0x75,0x30,0x00,0x3E,x20,0xC9})

you could add the crc to the end by doing this:

out = out + chra(from.urWord(calccrc(out)))

Actually, it'd probably be better if the chra(from.urword()) was in the function itself, so instead of return(crc), you'd have:

return(chra(from.urWord(crc)))

so you could just do:

out = out + calccrc(out)

Yes, you could put the code into a single sequence, but why would you want to? Then you couldn't reuse it elsewhere. To use as a function, just create a function called CalcCRC and put the script in it.

Link to comment
Share on other sites

hi,

I have following message.

01 FA 00 00 00 00 00 00 75 30 00 3E

And CRC must be 20 C9.

The code gives me to that message followings:

with polynom 0xA001: crc=38014 =(0x947E)=({126,148})

I am sure that my device polynom is 0xA001 in CRC calculation.

is that code DF crc calculation code? Help me please to find out the problem.

thanks.

Link to comment
Share on other sites

Yes, that code is right out of our modbus driver. I checked it and get the right result:

? calccrc(chra({0x01, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x30, 0x00, 0x3E}))

this displays 51488 which is 0xc920

I'm assuming that your CRC is in little-endian, meaning the 20 goes before the c9. This is reverse of modbus, but doesn't affect the crc calculation. It does mean that you want the from.uWord() not from.urWord() function. urWord is for big-endian, and uWord is for little-endian. Modbus uses big-endian, Windows PC's use little-endian.

Link to comment
Share on other sites

thank you very much for your nice help.

The problem was in that code was

---C1127 Infinite loop detected. 100 steps executed in 0.014146 seconds

And, I put delay after the

for (private j = 0, j < 8, j++)

delay(0.09)

And, that code is working accurate. But very slow. below the 0.09 sec, it shows me C1127 fault.

is it possible to calculate CRC more faster?

And, my next question is how can I parse crc=({9D6A}) to crc=({9D,6A}) or

crc=({0x9D6A}) to crc=({0x9D,0x6A})

thank you again.

Link to comment
Share on other sites

hi,

i solved that slow problem with changing to this code.perfect fast.

I am sending to DF users, it works well.

private crc_table
crc_table[] = ({0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40
0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,
xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,
x81,0x40,0x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,
x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,
x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0
C0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0
81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0
40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0
1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,0x
0,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x
1,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x
1,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x
,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x81,0x40,0x0,0xC1,0x81,0x40,0x1,0xC
,0x80,0x41,0x0,0xC1,0x81,0x40,0x1,0xC0,0x80,0x41,0x1,0xC0,0x80,0x41,0x0,0xC1,0x8
,0x40,0x0,0xC0,0xC1,0x1,0xC3,0x3,0x2,0xC2,0xC6,0x6,0x7,0xC7,0x5,0xC5,0xC4,0x4,0x
C,0xC,0xD,0xCD,0xF,0xCF,0xCE,0xE,0xA,0xCA,0xCB,0xB,0xC9,0x9,0x8,0xC8,0xD8,0x18,0
19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,0x14,0xD4,0x
5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,0xF0,0x30,0x3
,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,0x3C,0xFC,0xFD
0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,0x28,0xE8,0xE9,
x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,0xE4,0x24,0x25,0
E5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,0xA0,0x60,0x61,0x
1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,0x6C,0xAC,0xAD,0x6
,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,0x78,0xB8,0xB9,0x79
0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,0xB4,0x74,0x75,0xB5,
x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,0x50,0x90,0x91,0x51,0
93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9C,0x5C,0x5D,0x9D,0x
F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,0x88,0x48,0x49,0x89,0x4
,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,0x44,0x84,0x85,0x45,0x87
0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40})

private string buffer=chra({0x01,0x10,0x2A,0x2C,0x00,0x01,0x02,0x00,0x75})
private crc_low = 0xFF
private crc_high = 0xFF
private raw = asca(buffer)
private index

for (private x = 0, x &lt; getlength(buffer), x++)

   index = crc_high # raw[x]
   crc_high=crc_low # crc_table[index]
   crc_low=crc_table[index+256]   

endfor

V.crchigh=crc_high
V.crclow=crc_low

Thank you again to Azeotech team.

Link to comment
Share on other sites

The infinite loop check can be disabled by going to File - Preferences. It normally defaults to inactive and is essentially a deprecated feature.

To parse crc=({9D6A}) to crc=({9D,6A}) or crc=({0x9D6A}) to crc=({0x9D,0x6A}) use the From.uWord() functions as I mentioned in the other posts.

As for your final code, yes, it works quite well to use a lookup as you did. I was trying to stick to basics so didn't bring this option up. You can actually precalc the values in a loop rather than hand type them if want. In C, using a lookup is not really needed since the code runs so quick and the comm is the limiting factor, but DAQFactory definitely does better if you can eliminate loops in script, so bravo for figuring out how to do the lookup on your own!

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.