AzeoTech

Administrators
  • Posts

    6,436
  • Joined

Posts posted by AzeoTech

  1. Timing doesn't affect output channels so that is not your issue. The issue is that every time you do:

    myChannel = someValue

    it has to send the Modbus query. So if you have 62 outputs, it will take 62 separate queries, which will be pretty slow.  To set multiple outputs at once, you'll have to bypass channels and use a function call instead.  To do this, create an array with the consecutive values:

    private out
    out[0] = firstRegistryValue
    out[1] = secondRegistryValue
    out[2] = thirdRegistryValue
    // etc.

    then call the function to send it:

    device.myDevice.setRegisterS16(id, firstAddress, out)

    There are other setRegister() functions depending on data type.

  2. That would do it.  It's easy to forget that connecting over Ethernet requires more than just the IP address.  The IP address just gets you to the proper office building.  You also need to know what the port number is to get to the right office in the building and there are 65535 offices in the building and 99.99% are empty.

    If your MCU is going to act as a standard ModbusTCP slave, put it on port 502, as that is the standard port and anyone doing Modbus TCP is going to try 502 first without looking at any documentation you provide.  Also, you should avoid port's below 256 as they are kind of "reserved".

  3. When you try and send something out a TCP port in DAQFactory and it gives you "Port is busy" it most likely means that the socket could not be established and the port is busy trying to establish it.  In general that usually means you got the IP address or Port # wrong.  5001 is an unusual port # for Modbus TCP.  502 is the standard.  Also, its possible that your device can only handle one connection and so while your other tool is running, DAQFactory can't connect.

     

    Note that this does not apply to serial ports.  For serial ports, if you get Port is busy when you try and send, it usually means its locked due to other comms.

  4. Use two actions on the same button.  Both should be quick sequence actions.  The first one would have the "On Mouse Down" checkbox that appears when you select Quick Sequence checked.  That one would have script like:

    myChannel = 1
    strCaption = "ON!"

    Then the second action would not have On Mouse Down checked and would have:

    myChannel = 0
    strCaption = "Off"

    Note if you want the button text to change if the channel changes outside of the button press, you either need to add it to script, or you can use a blank button, and then overlay a Descriptive Text Component on top of it.

  5. There is always a write limit on flash memory.  Usually its around 10,000 iterations, but may be better now.  SSD's use wear leveling to help with this, but I doubt a PLC is going to use anything too modern or fancy.  Its also possible that its not flash, but instead either battery or capacitance backed memory, in which case there shouldn't be a wear limit.

    As for reestablishing, you can do:

    device.myDevice.initComm()

    to reestablish the socket or reinit the serial port, though serial connections don't typically need to be reconnected.  I'd just create a watch dog to do it.  Something like:

    while(1)
       if (systime() - someInputChannel.time[0] > 10)
          device.myDevice.initComm()
          delay(60)
      endif
      delay(1)
    endwhile

    and let that run in the background.  Note that you probably don't want to initComm() more often than once a minute for ethernet comms, thus the delay(60) inside the if().

     

  6. Yeah, the Omron E5 manual for the controller is a bit confusing.  Obviously written by someone without a real grasp of what is important, and what's just filler.  They also say things like "Set in hexadecimal" but that's not right unless they are talking about ModbusASCII.  "Hexadecimal" doesn't really apply in binary protocols like RTU.  Hexadecimal is just a way of describing a particular number.  So is decimal.  The number 0F in hexidecimal is the same number as the number 15 in decimal, which is the same number as 1111 in binary.  So when you see all the "hexidecimal" in the manual, really just think "number".  The exception is when they actually show a value in hexadecimal.  Then they are using the hex notation so you need to know.  In many cases they use the rather non-standard H' in front of hex represented numbers, but they don't do this consistently.  I, for one, had to look through the two-byte mode addresses to see whether they were decimal or hex since you can't tell the difference unless its notated, or you see the letters A through F in the number.

    Anyhow, I rant.  Mostly because Modbus shouldn't be this complicated, and manufacturers seem to insist on writing bad manuals.

    OK, now to your questions.  A tag is the same as a Modbus address, though really the tag is the thing at a particular address.  So, for example, "10 Downing Street" is an address, and the UK prime minister's house at that address is the tag.

    Now on to the addressing they documented.  This controller has two sets of addresses for the exact same thing.  This is the 2 byte vs 4 byte mode.  So, address 0 and address hex 2000 are the same value, the PV or temperature, but address 0 returns the value as a 32 bit integer, while address hex 2000 returns the value as a 16 bit integer.  Which you use I think largely depends on the software you use.  DAQFactory supports 32 bit values, so you might as well use those addresses.  You'll just need to tell DAQFactory to read 32 bits, not 16, so you need Read Holding S32, or perhaps the reverse word version.  Then you'll see that the addresses increment by 2.  This is because Modbus addresses can only hold a 16 bit value, so it takes two consecutive addresses to create a single value.  You can see this in your data in your screen shot.  Its why you see "0" in the 0 section, then "248" then another "0" then 28672.  The value is 32 bit, it just isn't use the first 16 bits and those are all 0.

    So, use 4 byte mode by using Read Holding S32 (or U32, or the reverse word versions), then use the addresses listed in the 4 byte column converted to decimal.  DAQFactory does not accept hex represented addresses in the Channel #, so you'll have to use a calculator, like the one built into Windows, to convert from hex to decimal.  So for example, if you wanted to read the Set Point at address hex 0106, you'd have to put in 262 decimal into the channel # in DAQFactory.  These are the same number just represented two different ways.

     

  7. That's because the symbols in the symbol library are not bitmap images, but vector graphics.  DAQFactory doesn't support transparent in bitmaps.  You have two choices:

     

    1) use the symbol directly.  If all you want to do is incline it, why not just set the rotation parameter in the symbol component?  It will rotate it for you.

    2) export the symbol as a WMF, then edit it with a WMF editor instead of Paint.  Illustrator sometimes works as a WMF editor, though I'm not sure about support in the latest releases.  There are other WMF editors on the web for a lot cheaper or free.  WMF is a vector file format.

  8. You get the timing lag because the Timeout's slow down the Timing loops to the point where they lag far enough behind that DAQFactory resets them.  Ignore that error as its a biproduct of your main Timeout error.  This is also why you should put UE9 and PSL channels on different Timing / Offset combos.  If they are the same, the timeouts will drag down the UE9 poll rate.

     

    You can try reiniting the port if you lose data for more than, say, 3 seconds.  Its easiest to do this if you are not using channel timing, but even with channel timing you can do it.  Let's say you have a channel called PSL on a device called PQube:

     

    private lastTime = systime()

    private watchdogTimeout = 3

    while(1)

       if ((systime() - PSL > watchdogTimeout) && (systime() - lastTime > 60))

          device.PQube.initComm()

          lastTime = systime()

      endif

      delay(1)

    endwhile

     

    Something like that.  Note that you don't want to continuously reinit the port, otherwise it'll never get inited, so I only do it once a minute if the connection stays dead.

  9. Alas, DAQFactory is not Unicode, so the font you selected probably won't work.  You'll need a japanese font.   For example, when I go to paint and paste the characters you indicated, it automatically switched my font to Microsoft YaHei.   You also might try code page 932.  I can't guarantee that it will work, but those would be the things I'd try.  I'd also try setting the caption using script instead of through the properties window.  Or possibly through the docking properties window.  

     

     If you can't get it to work, you'll have to create images of the japanese words in Microsoft Paint and then paste them on top of the buttons.  Certainly not as convenient, but it will definitely work. 

     

    Also, it would help us if you could post a .ctl document with your attempts.  When I copy/paste out of the browser, it wants to paste the characters as UTF-8 which I'm sure DAQFactory won't take.  But, if you were to type the japanese characters directly into DAQFactory, it may work better.  But alas I can't type japanese!

  10. Sometimes it can be hard to tell if a failure to communicate with a device is caused by a networking issue (cut cable, no power to remote device) or something else (protocol error, etc.)  In these cases, the first thing we tend to do is ping the device.  A successful ping at least tells us that the device is powered up and the IP is accessible from this computer.  It doesn't tell us if the device will allow us to connect to it, a firewall is blocking the desired ports (say 502 for Modbus), or other issues, but it does eliminate some possible problems.  There are many times when we wish to do this automatically.  So, here is a simple script we'd like to share that you can use to ping a device from script:

     

    function checkPing(string ip, string path)
       system.ShellExecute("cmd","","/C ping " + ip + " > " + path, "", "hide")
       delay(5)
       private h = file.Open(path,1,0,0,0)
       private string data = file.Read(h, file.GetLength(h))
       file.Close(h)
       return(find(data,"TTL=",0) != -1)
    

    It does this by triggering the command line ping, just like you would type it, and then piping the result to a file.  Then it opens the file and looks for "TTL=" which really only appears if a ping is successful.  The delay(5) is to give the ping command time to execute as there is no way us to know.  ShellExecute() is a non-blocking function, meaning it will trigger the command but then immediately return.  Because we are using command line piping we have to have shellExecute() run "CMD" not "Ping" directly.  We pass the /C flag to CMD to tell it to run the Ping command then quit.

     

    The design of this function is to allow you to, in script, check the network status on many devices.  Simply call this function with the ip and a path to the file you'd like ping to create with the result.  You'll want to make sure if you are calling this function from multiple threads for multiple IPs that you pass a different path.  

    Note also that this function will take at least 5 seconds to run, so don't call it from the command line or a button press.  Make sure and call it from a sequence running in a background thread.

     

       
  11. You can't put variables in static array notation (i.e. {1,2,3} is fine, but {1, myVariable, 3} is not).  But write() just takes a string, and asca() generates a string, so you can just concatenate them:

     

    device.Sprint.Write(chra({0x04, 0x30, 0x30, 0x30, 0x30, 0x02, 0x41, 0x61}) + format("%03d", val) + chr(0x03) + bcc)

     

    where val is some number.  Format() with %03d will prefix val to 3 digits with 0's, so 5 becomes 005 and 32 becomes 032.  I'm not sure how you are calculating BCC, but lets say its just a sum of all the other characters rolled at 256.  Then I'd do:

     

    private string out = chra({0x04, 0x30, 0x30, 0x30, 0x30, 0x02, 0x41, 0x61}) + format("%03d", val) + chr(0x03)

    private bcc = sum(asca(out)) & 0xff

    device.sprint.write(out + chr(bcc)

  12. You've got basically two parts here: the PID loop and the PWM.  What you'll want to do is create a PID loop with the appropriate Process Variable (your temp probe) and set point (probably a variable?) and then have the output range from -100 to 100 and go to a global variable.  That completes the PID part.  Then create a sequence that loops at the same rate as the PID (default is once per second) and looks at the variable you created to hold the output of the PID and controls the SSR accordingly, where -100 = 0% PWM and 100 = 100% PWM.  The PWM you can either do using LabJack's built in PWM functionallity, and there are samples that show how to do that, or, if your system is on the slower side and a perfect PWM is not required, you can do it in script.  The script is pretty straightforward (assuming PIDOut is the global variable for your PID output, and SSR is the FIO4)

     

    private PIDLoopTime = 1  // the interval the PID updates (a setting in the PID)

    while(1)

       switch

          case (PIDOut < -95)

             SSR = 0

             delay(PIDLoopTime)

          case (PIDOut > 95)

              SSR = 1

              delay(PIDLoopTime)

          default

              SSR = 1

              delay((PIDOut + 100) / 200 * PIDLoopTime)

              SSR = 0

              delay(1 - (PIDOut + 100) / 200 * PIDLoopTime)

       endcase
    endwhile
     
    The switch is required to avoid a rapid toggle at the extremes.  If we didn't do that, then if the PID calls for all on or all off, then then the logic under "default" will quickly toggle the SSR, i.e. if it calls for 100% it will run the SSR for one second then turn it off for a millisecond then turn it back on again.
  13. DAQFactory doesn't do automatic pagination.  You can, however, extend your table off the screen and it will still print that area.  The problem is that if you make the table too long, the aspect is going to get weird and table is going to get really long and thin.  I personally create a separate report page when I have components off the side of the screen.

     

    If you want a multipage report you are going to have to do it manually.  This only works in 5.90.7 and newer.  Create a table that is the right aspect for one page, filled just with the data for that page.  First call page.pdfStart().  It takes just the aspect, so is usually:

     

    page.pdfStart(8.5, 11)

     

    Then, to actually "print" a page to the pdf, setup the page and call:

     

    page.pdfAddPage("myPageName")

     

    repeat this, updating the data in your table for each page and then calling addPage().  When you are done, call pdfFinish() with the path:

     

    page.pdfFinish("c:\daqfactory\myReport.pdf")

     

    It would actually be very easy to do.  For example, lets say you have a table with just one column containing the array "data".  You size the table so it prints a single page nicely.  Feel free to add other components that printPDF supports.  Then figure out how many rows of the table are visible so the scroll bar doesn't show.  Then, change the Expression in the table to:

     

    data[tableStart, tableStart + tableLength]

     

    where tableStart is a global variable, and tableLength is the # of rows visible on the table (make it a global too...).  Finally a short sequence will get you there:

     

     

    global tableLength = 50

    page.pdfStart(8.5,11)

    tableStart = 0

    while(tableStart < numrows(data))

       page.pdfAddPage("myReportPage")

       tableStart += tableLength

    endwhile

    page.pdfFinish("c:\myReport.pdf")

  14. The best way to confirm is to actually try it.  strAlert[0] will hold the last alert message until the next one comes in, at which point, the message moves to [1], etc.  I believe it will store the last 100.  Its really designed to allow you to use a table component or similar to simply display the message history.  To actually do something more specific, you should really use OnAlert.  Then you can do whatever you want.

  15. You may need to set the CodePage DAQFactory uses.  You can do this by creating a DWORD registry entry called "CodePage".  The location is:

     

    hklm/software/DAQFactory/Control

     

    Note that on x64 systems, its:

     

    hklm/software/wow6432Node/DAQFactory/Control

     

    Search the internet to determine the proper code page.

     

    Also, note that you may have to be ensure that the font you are using supports your characters.  

     

    Can you please post the characters you are trying to use?