Sign in to follow this  
p.piwowar

Modbus - time management for beginners

Recommended Posts

Dear Sirs, I downloaded your DAQF software only few days ago and I consider to buy it as I am really excited with my new toy. I installed Circuit power meter with Modbus/RS485 connected through an ethernet to RS/485 adapter. My very simple application reads some 12 out of over 50 available float32 registers measuring voltage, current, frequency, power, etc of my house electricity.

It works fine, but .....

... as my PC (Win/XP) does also few other things (camers, weather station, alarm monitoring...) communication with Modbus stops after some 15-20 mins and I have to restart the device in DAQF again (Device Configuration/Configure/Save - I assume it "restarts a device). I tried to increase Timing (up to 3s) and device Timeout (up to 5s) and then it works a bit longer .... If I try to run DAQF on a different PC that is not that much overloaded it could work for hours....

I am not desperate to read the device every 1-2 seconds but please help to make DAQF not stopping the device after a peak processor load of my PC.

Thanks in advance,

Pawel

Share this post


Link to post
Share on other sites

Are you getting Timeout alerts? What about timing lag errors? In general you do not want your Timeout value greater than your Timing. Also, try opening the monitor and selecting Display Time of Tx/Rx and look at what the difference is between tx and rx to see what the round trip query time is.

Share this post


Link to post
Share on other sites

Thank you for the prompt response. I must say it is working now for few hours after I have set very long timing=5s and timeout=3.5s ... Yes I had some timeouts and quite a few lag errors before. It might be my PC is really overloaded and the only way is is to read data every 5s or even with less frequently which I can live with.

Share this post


Link to post
Share on other sites

It also may be that the device is slow and you are reading too many values in a second. This is why its good to see what the round trip time is by looking at the monitor. On some devices, I've seen it as large as 0.2 seconds, even with a direct connect serial connection. If you then try and query 30 non-consecutive inputs, that means 6 seconds!

Share this post


Link to post
Share on other sites

You are really right with your Tx/Rx round trip check hint! While I was able to get some improvement through increasing timing=10s and timeout=5s, but I discovered also something. Your software reads data in 5 runs every time as the device registers I need are not straight one after the other:

7000 U1

7002 I1

7004 P1

....

7012 U2

7014 I2

7016 P2

...

7028 U3

7030 I3

7032 P3

...

7044 FRQ

...

7052 P3Phase high

7054 P3Phase low

I guess there is a way to read all the data in one go to an array. Extract only those needed ones to display them ?

regards, Pawel

Share this post


Link to post
Share on other sites

Yes, the data needs to be consecutive. If there is any gaps, it will take two queries. Your data has only small gaps, so if you wanted to read the entire thing in one array, just create some dummy channels for the gaps, i.e 7006, 7008, etc. Make sure its the same I/O type and same timing/offset. Make the history = 1 so you don't use up any memory. Then you won't have any gaps and DF will read the entire thing in one read. Well, actually it might take 2. I can never remember what the exact max number of tags that can be read in a single query per Modbus specifications.

Share this post


Link to post
Share on other sites

What if I use one of your examples presented in the manual and read (every 2 seconds, as the device really replies within this period surely) entire 54 float registers of the device and make Channels of the ones I really want? Can I save the number of used Channels ?

______________________________________________

private data 
while (1) 
  data = Device.MyDevice.ReadHoldingFloat32(1,0,54) 
  U1.AddValue(Private.data[0][0]) 
  I1.AddValue(Private.data[0][1]) 
  P1.AddValue(Private.data[0][2]) 
  U2.AddValue(Private.data[0][8]) 
  I2.AddValue(Private.data[0][9]) 
  P2.AddValue(Private.data[0][10])
  ...... 
  FRQ.AddValue(Private.data[0][40])` 
  ...... 
  delay(2) 
endwhile

___________________________________________

Do I understand it right ?

Regards, Pawel

Share this post


Link to post
Share on other sites

Using Channels the way I described is easier, but if you are using a channel limited version of DAQFactory (i.e. base or below), then yes, you can use the script method and it will work just as well. The only thing is that you probably should add some error handling for timeouts. Probably something like this:

private data
while (1)
  try
	 data = Device.MyDevice.ReadHoldingFloat32(1,0,54)
	 U1.AddValue(Private.data[0][0])
	 I1.AddValue(Private.data[0][1])
	 P1.AddValue(Private.data[0][2])
	 U2.AddValue(Private.data[0][8])
	 I2.AddValue(Private.data[0][9])
	 P2.AddValue(Private.data[0][10])
	 ......
	 FRQ.AddValue(Private.data[0][40])`
	 ......
   catch()
	 ? strLastError
   endcatch
  delay(2)
endwhile

If you don't, the sequence will stop if the query ever times out.

Share this post


Link to post
Share on other sites

Thanks for your help a great deal (and I have bought the license). I have a more serious issue now.

The sequence now reads the data every 2 seconds. It sometimes reports an error (mainly CRC or timeout) and then after 1-2 hours stacks. An easy way to restart it is to init the device through Device Configuration and click Save manually, as I had discovered before I, therefore adjusted my sequence to discover an event when error happens in three consecutive reads, wait 10 seconds and init the device (see the code). It is good but it stacks after 12-20 hours. I guess I have to know much more about error handling ?

private data
private errcount=0
while (1)
  try
	data = Device.n14.ReadHoldingFloat(1,47001,58)
  // reads into data 58 cells from meter and puts some of them to channels
	Vol_L1.AddValue(Private.data[0][0])
	Amp_L1.AddValue(Private.data[0][1])
	Wat_L1.AddValue(Private.data[0][2])
	Vol_L2.AddValue(Private.data[0][7])
	Amp_L2.AddValue(Private.data[0][8])
	Wat_L2.AddValue(Private.data[0][9])
	Vol_L3.AddValue(Private.data[0][14])
	Amp_L3.AddValue(Private.data[0][15])
	Wat_L3.AddValue(Private.data[0][16])
	Wat_3.AddValue(Private.data[0][23])
	FRQ.AddValue(Private.data[0][28])
	KWh_3H.AddValue(Private.data[0][56])
	KWh_3L.AddValue(Private.data[0][57])
	errcount=0
  // resets error_count after reaching here
  catch()
	? strLastError+"  "+errcount
	errcount=errcount+1
  // increase error_count after catching an error
	if (errcount > 3) 
		delay(10)
		Device.n14.InitComm()
 // Init the device n14 after 3 consecutive errors 
		? "Init"
		errcount=0
	endif
  endcatch
  delay(2)
endwhile

Share this post


Link to post
Share on other sites

Code looks ok. I'm assuming by "stacks" you mean "stops"? What exactly does it do? Is the sequence still running? Does it stop querying? Are you using a USB serial converter?

Share this post


Link to post
Share on other sites

Yes - stacks means stops but the sequence appears as running in the Sequence window. Interestingly, when it "stacks" you can not see it "jumping" from line #4 to line #34. It's like stopped at line #4 all the times. (I repeat) it always helps to init the device manually by saving device configuration.

No - I do not use USB. This runs over Ethernet connected through Ethernet/RS485 converter.

In addition:

1.I never tried to stop the sequence and start it again after it stacks. I will try to do that next time.

2.Is that possible that the device generates 2 errors at one time and then .... the "try" and "catch" can not handle that ?

Regards, Pawel

Share this post


Link to post
Share on other sites

Line 4? Is that the while(1) or do you have some blank lines at the top?

It is possible that the device generates 2 errors, one at read and another when you do init(), but the second one should throw you out of the while loop and end the sequence. Perhaps the status is not updating and the sequence is actually stopped. Try putting a try/catch() around the initcomm().

Share this post


Link to post
Share on other sites

Right! I can count, really :)

I'm not quite sure how DAQFactory reports line numbers when an error occurs, so it may actually be in the catch() but reporting it as the try line.

Try adding a try/catch() around the init

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this