Nightfly

MrPLC Member
  • Content count

    99
  • Joined

  • Last visited

Posts posted by Nightfly


  1. 1. Open the project you have. 2. Convert it to 1.2 (as you have done) 3. Save it as something else (HMI - Original program or something like that) 4. Press Transfer and then Receive. The program in the HMI will then be transferred to your computer (it will ask you if you want to overwrite the current project - press yes) I would personally keep this project un-modified - so you can mess around as much as you want and you would always be able to put it back into the HMI and know it would work. So I would save a new copy and work with that one - basically switch on "Remote Access" and transfer it back in. Regards

  2. Inntele, I think you may have misunderstood what is required from @Elizabeth86 "I did a latching circuit with a SET and RES which was if X1 or X2 is turned on the alarm goes off, X7 resets. Now the question asks do the same but with N/C." To me this means she wants a circuit that will simple switch the alarm on when X1 OR X2 is turned OFF (not X1 AND X2) She also said that in the attached program example she put both programs together simply to show us all her work She said... "I didn't run them together, I just put one above the other for the picture. I built the latching circuit with N/O switches, which works great. Then deleted them and built the code with N/C switches" so IMHO she wants... X1 Y1 |----| \ |----------------------( S )| || X2 | |----| \ |---|| X7 Y1|----| |------( R ) Best Regards

  3. Propeller Head is right, If you are putting into the PLC only the ladder runs 5 & 6 then your code is fine. It should work like this... 1. Turn both inputs X1 & X2 ON - so both LED's are red 2. Press the Reset Button ON and then OFF and the output will go off (if it was on) 3. Switch either X1 OR X2 OFF and the output will come ON and stay on regardless of X1 and X2 switch positions 4. Turn both inputs X1 & X2 back ON and press then Rest Button ON and then OFF and the output will go off again

  4. You don't need another version of E-Designer (there isn't a version 1.2 anyway) what you have is fine. The 1.2 we are talking about is the Firmware on the HMI. As your current E-Designer supports Firmware 1.5 it also supports all the previous versions. Simply downgrading the project to 1.2 (as you have done will allow the project to go into the HMI). I don't know where you got the E-Designer project from - did you suck it out of the HMI or did somebody send you it. If somebody sent you it I would suck the current project out of the HMI and save it as a matter of course (just in case the project is not the correct one - this has happened to me more than once)

  5. Your project is looking for an operator terminal with version 1.5 on it. However, the terminal you are connecting to has version 1.20. You need to update the firmware on the HMI to 1.5 - or downgrade the project in E-Designer to use operator terminals with version 1.2. (Look at project manger on the left of the E-Designer screen and double click on the top node in the listview box). you can get the latest firmware version (1.53) from here... http://www.beijer.lv/web/web_lv_be_lv.nsf/alldocuments/CB389E02C3FAA5C4C12579BF004522E2 (it is a standalone program that will update the HMI) Leave all the port settings in the "Remote Access" dialog box alone (Viewer 5900 and browser 5800) these the standard settings for VNC. The port numbers in the transfer dialog box have nothing to do with this at all.

  6. If you're running the simulator (which I image you are doing) - then yes the output will come on straight away. This may not be because you program is faulty (well we haven't seen your code) - but because when the simulator starts it will default with inputs off (and the alarm is suppose to come on when the inputs are off - because they are now programmed NC). Basically your codes probably OK - its just the simulator to work as you want it to work would have to start with both inputs in the "ON" state. Hope this makes sense. You could always post your work

  7. Hi sachincool786, Are you referring to me? (My name is Nightfly) The Sparky on each post corresponds to the amount of posts you have done on the forum. It’s not your name. You are a “Newbie” because you have only posted a few times. I and dunc (in the thread) are “Sparky” because we have posted a few more.

  8. Note sure if this is your problem but I have had similar problems myself and the issue was that old Beijer Terminals only used 8 chars for the file-name but the new E1000 range use 32 chars that overwrite data in the PLC. Use "SCRR" in the command line forces the terminal to only use 8 chars as the file name. Look in the E-Designer help file ("Creating a Recipe With The Operator Panel") as it describes this.

  9. I agree with Theo V Best way... FX3G (or 3U) + E-net module. Both HMI's connect directly into the PLC via Ethernet. Nice 'n' quick. You would program the unit using FX Configuratior. You can then use any HMI - even a GOT (how I dislike GT Designer). If you really want to use the E1000 then use the Beijer Exeter range instead. It is Identical (but you use Information designer instead of E-Designer - which is also identical Lol). Mitsubishi will stop selling these panels (in the UK) at the end of the year but Beijer will be selling them for many years to come (OK they really want to sell you the IX panels - but we have the Beijer Rep in often (we buy lots of panels) and he assures us the Exeter range will be sold for years to come (even if it is mainly to replace all the old Mitsubishi E-series out in the field now the Mitsubishi and Beijer have fallen out). Btw If you want to convent a E-Designer project to a Information designer project just rename the project mpa file to cpa then open up the file in a text editor (notepad) and change the top line from ; MAC Programmer import/export file, format 2 to ; CIMREX PROG import/export file and it will open up fine If you do want to connect to the PLC via serial you can still connect the panels together via Ethernet (you could even just make the second panel a BTDP station).

  10. It was for communicating to an Fx3U PLC for transferring recipes directly into the PLC and also 24/7 dataloging. We have our own PC based recipe system and data-capture program written in VB & C# that stores the data in an SQL Express database and makes pretty graphs for the end user lol. We stopped using MX component when we found out that it had problems re-connecting to PLC's when the Ethernet connection was broken. We ended going back to Mitsubishi Germany (we are UK based) to find a solution but although they knew about the problem they were not forthcoming with a solution so we started using OPC servers instead. Cost more - but built proof. MX component has been updates since (well we are on a different revision number) so this Issue may have been fixed. The code above was used on at least a dozen sites both in the USA and UK.

  11. We used to use MX Component but quickly found OPC to be much more reliable. Below is code we use to use. May or may not be of use. Regards // --------------------------------------------------------------------------- // Date/Time: 28/06/2005 11:54 // Solution Name: MXWrapper // Project Name: MXWrapper // Project Item Name: MXWrapper.cs // Project Item Kind: Code // Purpose: C# Wrapper for the MX COM Component // --------------------------------------------------------------------------- using System; using System.Collections; using System.Windows.Forms; using System.Data; using System.Diagnostics; using System.Timers; namespace DCN.MXWrapper { /// <summary>The PLC Device Types.</summary> public enum DType { X,Y,M,S,TN,CN,D,R,V,Z,Missing } /// <summary>Available PLC Status Settings.</summary> public enum PLCStatus { Run = 0, Stop = 1, Pause = 2 } public delegate void DeviceTriggerHandler(string sDevice, int lData); public delegate void DataPollingHandler(int machine); /// <summary> /// C# Wrapper for the MX COM Component. /// </summary> public class MXWrapperClass { /// <summary> /// Device events /// </summary> public event DeviceTriggerHandler DeviceTrigger; public event DataPollingHandler PollDevice; /// <summary> /// Timer to generate the polling interval /// </summary> private System.Timers.Timer PollTimer = new System.Timers.Timer(); /// <summary> /// The PLC COM component object /// </summary> ACTMULTILib.ActEasyIFClass PLC; private bool m_Connected = false; string[] statusDevice; int[] statusData; public int machine; /// <summary> /// MXWrapper Constructor /// </summary> public MXWrapperClass() { // Create the MX Component Object PLC = new ACTMULTILib.ActEasyIFClass(); // Assign the delegates to the events PLC.OnDeviceStatus +=new ACTMULTILib._IActEasyIFEvents_OnDeviceStatusEventHandler(PLC_OnDeviceStatus); PollTimer.Elapsed += new ElapsedEventHandler(PollTimer_Tick); } /// <summary> /// The Logical station Number used in /// the MX Component Communication Setup Utility. /// </summary> public int LogicalStationNumber { set { PLC.ActLogicalStationNumber = value; } } /// <summary> /// Convert a numeric value to a hex string. /// </summary> /// <param name="numericValue"> /// the numeric value to convert</param> /// <returns> /// the hex string</returns> public static string Hex(int numericValue) { return "0x" + numericValue.ToString("x"); } /// <summary> /// Starts the polling event only if there is already an interval set /// </summary> public void StartDataPoll() { if (PollTimer.Interval > 0) { PollTimer.Start(); } } /// <summary> /// Starts the polling event. /// </summary> /// <param name="tickInterval"> /// The number of milli-seconds interval</param> public void StartDataPoll(int tickInterval) { PollTimer.Interval = tickInterval; PollTimer.Start(); } /// <summary> /// Starts the polling event. /// </summary> /// <param name="tickInterval"> /// The number of seconds interval</param> /// <param name="IntervalUnits">Number of milliseconds in the interval</param> public void StartDataPoll(int tickInterval, int IntervalUnits) { PollTimer.Interval = tickInterval * IntervalUnits; PollTimer.Start(); } /// <summary> /// Stops the polling event. /// </summary> public void StopDataPoll() { PollTimer.Stop(); } /// <summary> /// The polling event handler. /// </summary> private void PollTimer_Tick(object sender, ElapsedEventArgs e) { //Critical section - although we want to (roughly) poll every second //we shouldn't start a new poll before the existing one is complete. lock(this) { PollTimer.Enabled = false; // Generate the PollDevice event PollDevice(machine); PollTimer.Enabled = true; } } /// <summary> /// Sets the device names that will be monitored for the trigger. /// </summary> /// <param name="deviceList"> /// The devices to monitor</param> public void SetDeviceStatusNames(params string[] deviceList) { statusDevice = deviceList; } /// <summary> /// Sets the devices trigger values, /// any one will trigger the status event. /// </summary> /// <param name="valueList"> /// The trigger values</param> public void SetDeviceStatusValues(params int[] valueList) { statusData = valueList; } /// <summary> /// Start the trigger monitor. /// </summary> /// <param name="monitorCycle"> /// Number of seconds between trigger cycles</param> public void StartTrigger(int monitorCycle) { string deviceString = String.Join("\n", statusDevice); PLC.EntryDeviceStatus(deviceString, statusDevice.Length, monitorCycle, ref statusData[0]); } /// <summary> /// Stop the trigger monitor /// </summary> public void StopTrigger() { PLC.FreeDeviceStatus(); } /// <summary> /// The device status event. /// </summary> /// <param name="sDevice"> /// The triggering device</param> /// <param name="lData"> /// The value that caused the trigger</param> /// <param name="lReturnCode"> /// The returncode</param> public void PLC_OnDeviceStatus(string sDevice, int lData, int lReturnCode) { Debug.WriteLine("On Device Event: " + sDevice + ", " + lData.ToString() + ", "); DeviceTrigger(sDevice, lData); } /// <summary> /// Opens the connection to the PLC. /// </summary> /// <returns>the status of the operation, 0 if successful</returns> public int Connect() { // Try to establish connection int connectStatus = PLC.Open(); // If there is a problem opening the connection, // then make sure it is closed if (connectStatus == 0) { m_Connected = true; } else { PLC.Close(); m_Connected = false; } return connectStatus; } /// <summary> /// Closes the connection to the PLC. /// </summary> /// <returns>the status of the operation, 0 if successful</returns> public int Disconnect() { StopTrigger(); // Try to close connection int closeStatus = PLC.Close(); // The connection will always be closed even if there is no PLC m_Connected = false; return closeStatus; } /// <summary> /// Returns the device names as an array /// </summary> /// <param name="devices"> /// The PLCdevice array from which to get the names</param> /// <returns> /// The array of device names</returns> public string[] GetDeviceNames(PLCDevice[] devices) { string deviceString = string.Empty; // Create a string of devices names, delimited by newlines foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.DeviceName + "\n"; } // Remove the last newline deviceString = deviceString.TrimEnd('\n'); // Return the string converted into a string array return deviceString.Split('\n'); } /// <summary> /// Convert a string to a Int16 arraylist. /// </summary> /// <param name="Reversed"> /// true if the bytes should be reversed</param> /// <param name="ASCIIString"> /// the original string</param> /// <returns>the array of integers</returns> public static int[] StringTo16BitRegisters(bool Reversed, string ASCIIString) { string stringToConvert = ASCIIString; int Stringlength = stringToConvert.Length; //Even up the String length with a space if (Stringlength % 2 == 1) { stringToConvert += " "; Stringlength = stringToConvert.Length; } int ArrayLength = Stringlength / 2; int[] Int16Array = new int[ArrayLength]; for (int charIndex = 0; charIndex < ArrayLength ; charIndex = charIndex + 1) { int lByte = Convert.ToInt32(stringToConvert[(charIndex * 2) + 1]); int hByte = Convert.ToInt32(stringToConvert[charIndex * 2]); if (Reversed) { Int16Array[charIndex] = hByte + lByte * 0x100; } else { Int16Array[charIndex] = lByte + hByte * 0x100; } } return Int16Array; } public string Int16RegistersToString(bool Reversed, int[] dreg_array,int MaxLength) { string ASCIIString = string.Empty; int Count = 0; try { foreach (int dreg in dreg_array) { if(Count >= MaxLength) break; Count++; int lByte = dreg & 0xff; int hByte = dreg / 0x100; // If the input numbers need to be reversed if (Reversed) { // Low Byte ASCIIString += Convert.ToChar(lByte); // High Byte ASCIIString += Convert.ToChar(hByte); } else { // High Byte ASCIIString += Convert.ToChar(hByte); // Low Byte ASCIIString += Convert.ToChar(lByte); } } } catch (Exception err) { MessageBox.Show("IntToASCIIConversion Error: " + err.Message); } return ASCIIString.TrimEnd(); } public string Int16RegistersToStringWithOffset(bool Reversed, int[] dreg_array,int MaxLength,int Offset) { string ASCIIString = string.Empty; try { for (int x = Offset;x < Offset+MaxLength;x++) { int lByte = dreg_array[x] & 0xff; int hByte = dreg_array[x] / 0x100; // If the input numbers need to be reversed if (Reversed) { // Low Byte ASCIIString += Convert.ToChar(lByte); // High Byte ASCIIString += Convert.ToChar(hByte); } else { // High Byte ASCIIString += Convert.ToChar(hByte); // Low Byte ASCIIString += Convert.ToChar(lByte); } } } catch (Exception err) { MessageBox.Show("IntToASCIIConversion Error: " + err.Message); } return ASCIIString.TrimEnd(); } /// <summary> /// Converts a string to a fixed length Int16 array. /// </summary> /// <param name="numberString"> /// The string to convert</param> /// <param name="noOfRegisters"> /// The number of Int16 values for the array</param> /// <param name="Reversed">true if the the ligh/low bytes should be reversed</param> /// <returns>The converted array</returns> private int[] StringToRegisters(string numberString, int noOfRegisters, bool Reversed) { int[] Int16array = new int[noOfRegisters]; Int16array = StringTo16BitRegisters(Reversed, numberString); //Insert spaces (0x2020) into array items not used for (int arrayIndex = noOfRegisters - 1; arrayIndex >= 0; arrayIndex--) { if (Int16array[arrayIndex] != 0) { break; } Int16array[arrayIndex] = 0x2020; } return Int16array; } /// <summary> /// Writes a block of text to the PLC. /// </summary> /// <param name="deviceID"> /// The ID of the block of D registers to write</param> /// <param name="fieldText"> /// The text to write (max 30 characters)</param> public void WriteTextToPLC(PLCDevice TextDevice, string fieldText, int maxSize) { int[] BlockData = StringTo16BitRegisters(true, fieldText.PadRight(maxSize)); WriteDeviceBlock(TextDevice, maxSize / 2, BlockData); } /// <summary> /// Reads a block of text from the PLC. /// </summary> /// <param name="deviceID"> /// The ID of the block of D registers to write</param> /// <param name="maxSize">The Size of the text to return</param> /// <returns>The PLC Text</returns> public string ReadTextFromPLC(PLCDevice TextDevice, int maxSize) { int[] BlockData; ReadDeviceBlock(TextDevice, (maxSize + 1) / 2, out BlockData); string Text = Int16RegistersToString(true, BlockData,BlockData.Length); if (Text.Length > maxSize) { Text = Text.Substring(0, maxSize - 1); } return Text; } /// <summary> /// Convert 2 16 Bit Registers to a single 32 bit register /// </summary> /// <param name="hNumber">High Register value</param> /// <param name="lNumber">Low Register value</param> /// <returns>32Bit Register Value</returns> public static System.Int32 ConvertTwo16bitTo32Bit(int hNumber, int lNumber) { //JF: Fixed 09/03/06 System.Int32 Result; int hValue; int lValue; // Make Sure the values are only 16 Bits in size hValue = hNumber & 0xffff; lValue = lNumber & 0xffff; // Create 32bit value Result = (((System.Int32)hValue) << 16) + lValue; return Result; } /// <summary> /// Retrieves the PLC CPU type. /// </summary> /// <param name="CPUType"> /// The PLC CPU type name</param> /// <param name="CPUCode"> /// The PLC CPU ID type code</param> /// <returns>the resultcode of the operation</returns> public int GetCPUType(out string CPUType, out int CPUCode) { int result = PLC.GetCpuType(out CPUType, out CPUCode); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// Set the PLC CPU state. /// </summary> /// <param name="NewStatus"> /// The new state (Run/Stop/Pause)</param> public void SetCPUState(PLCStatus NewStatus) { PLC.SetCpuStatus((int)NewStatus); } /// <summary> /// Retrieves the value from a single device. /// </summary> /// <param name="device"> /// The device to retrieve the value from</param> /// <param name="deviceValue"> /// The value retrieved</param> /// <returns>the resultcode of the operation</returns> public int GetDevice(PLCDevice device, out int deviceValue) { int result = PLC.GetDevice(device.Name, out deviceValue); if (result != 0) { Debug.WriteLine("Get Device ERROR: " + Hex(result)); } //Debug.WriteLine("GET " + device.Name + " = " + deviceValue); return result; } /// <summary> /// Retrieves the value from a single device. /// </summary> /// <param name="device"> /// The device to retrieve the value from</param> /// <param name="deviceValue"> /// The value retrieved</param> /// <returns>the resultcode of the operation</returns> public int GetDevice2(PLCDevice device, out short deviceValue) { int result = PLC.GetDevice2(device.Name, out deviceValue); if (result != 0) { Debug.WriteLine("Get Device ERROR: " + Hex(result)); } //Debug.WriteLine("GET " + device.Name + " = " + deviceValue); return result; } /// <summary> /// writes a value to a single device. /// </summary> /// <param name="device"> /// The device to write the value to</param> /// <param name="deviceValue"> /// The value to write</param> /// <returns>the resultcode of the operation</returns> public int SetDevice(PLCDevice device, int deviceValue) { Debug.WriteLine("SET " + device.DeviceName + " = " + deviceValue); int result = PLC.SetDevice(device.Name, deviceValue); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// writes a short value to a single device. /// </summary> /// <param name="device"> /// The device to write the value to</param> /// <param name="deviceValue"> /// The value to write</param> /// <returns>the resultcode of the operation</returns> public int SetDevice2(PLCDevice device, short deviceValue) { Debug.WriteLine("SET " + device.DeviceName + " = " + deviceValue); int result = PLC.SetDevice2(device.Name, deviceValue); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// Read a contiguous block of device values. /// </summary> /// <param name="startDevice"> /// The start device of the block to read</param> /// <param name="dataSize"> /// The number of devices to read</param> /// <param name="deviceValue"> /// An array of the values returned</param> /// <returns>the resultcode of the operation</returns> public int ReadDeviceBlock(PLCDevice startDevice, int dataSize, out int[] deviceValue) { deviceValue = new int[dataSize]; int result = PLC.ReadDeviceBlock(startDevice.Name, dataSize, out deviceValue[0]); // The amount of time this output takes can cause synchronisation errors //The ideal solution would be to tell the HMI to wait until all //data reads are complete before allowing any more operations /* #if (DEBUG) Debug.Write("ReadBlock " + startDevice.DeviceName + ", " + dataSize + " = "); for (int blockIndex = 0; blockIndex < dataSize; blockIndex++) { Debug.Write(deviceValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); #endif */ return result; } /// <summary> /// Write to a contiguous block of devices. /// </summary> /// <param name="startDevice"> /// The start device of the block to write to</param> /// <param name="dataSize"> /// The number of devices</param> /// <param name="deviceValue"> /// An array of the values to write</param> /// <returns>the resultcode of the operation</returns> public int WriteDeviceBlock(PLCDevice startDevice, int dataSize, int[] deviceValue) { Debug.Write("Writeblock " + startDevice.DeviceName + ", " + dataSize + " = "); int[] blockValue = new int[dataSize]; int dataLength; if (deviceValue.Length > dataSize) { dataLength = dataSize; } else { dataLength = deviceValue.Length; } for (int blockIndex = 0; blockIndex < dataLength; blockIndex++) { blockValue[blockIndex] = deviceValue[blockIndex]; Debug.Write(blockValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); int result; if (blockValue.Length > 0) { result = PLC.WriteDeviceBlock(startDevice.Name, dataSize, ref blockValue[0]); } else { result = 0; } return result; } /// <summary> /// Retrieve a non-contiguous set of device values. /// </summary> /// <param name="devices">An array of devices to read from</param> /// <param name="deviceValue">The device values read</param> /// <returns>the resultcode of the operation</returns> public int ReadDeviceRandom(PLCDevice[] devices, out int[] deviceValue) { string deviceString = string.Empty; int dataSize = devices.Length; int result = 0; deviceValue = new int[dataSize]; if (dataSize > 0) { foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.Name + "\n"; } result = PLC.ReadDeviceRandom(deviceString, dataSize, out deviceValue[0]); } return result; } /// <summary> /// Set clock data on PLC. /// </summary> /// <param name="clockData">The date and time to which the PLC will be set</param> /// <returns>the resultcode of the operation</returns> public int SetClockData(DateTime clockData) { //NOTE FOR FX PLC's THE YEAR CAN ONLY BE 00-99 NOTE 2007 AS IN THE Q SERIES int result = PLC.SetClockData((short) ( (int) clockData.Year - 2000), (short)clockData.Month, (short)clockData.Day, (short)clockData.DayOfWeek, (short)clockData.Hour, (short)clockData.Minute, (short)clockData.Second); return result; } /// <summary> /// Write to a non-contiguous set of devices. /// </summary> /// <param name="devices">An array of devices to write to</param> /// <param name="deviceValue">The values to write</param> /// <returns>the resultcode of the operation</returns> public int WriteDeviceRandom(PLCDevice[] devices, int[] deviceValue) { string deviceString = string.Empty; int dataSize = devices.Length; foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.Name + "\n"; } Debug.Write("Writeblock " + deviceString + ", " + dataSize + " = "); for (int blockIndex = 0; blockIndex < dataSize; blockIndex++) { Debug.Write(deviceValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); int result = PLC.WriteDeviceRandom(deviceString, dataSize, ref deviceValue[0]); return result; } public bool Connected { get { return m_Connected; } set { m_Connected = value; } } } #region PLCDevice Class /// <summary> /// A class to encapsulate a PLC Device /// </summary> public class PLCDevice { DType m_DeviceType; int m_deviceID; int m_DataSize; string m_DeviceDesc; string m_DeviceName; /// <summary> /// Simple constructor, no device values set /// </summary> public PLCDevice() { } /// <summary> /// Constructor to allow multiple devices of the /// same type to be created easily. /// </summary> /// <param name="deviceType">The type of the device</param> /// <param name="deviceID">The numeric ID of the device</param> /// <param name="deviceName">The devices friendly name</param> public PLCDevice(DType deviceType, int deviceID, string deviceName) { m_DeviceType = deviceType; m_deviceID = deviceID; m_DataSize = ReturnDeviceDataSize(deviceType); m_DeviceDesc = ReturnDeviceDesc(deviceType); m_DeviceName = deviceName; } /// <summary> /// Constructor allowing devices to be created /// by providing the standard string value /// </summary> /// <param name="device">The device string</param> /// <param name="deviceName">The devices friendly name</param> public PLCDevice(string device, string deviceName) { string prefix; // Isolate the prefix letter from the device number if (device.Length < 3) { prefix = device; } else { prefix = device.Remove(2, device.Length - 2); } if (prefix.Length > 1 && (prefix[1].ToString().ToUpper() != "N")) { prefix = prefix.Remove(1, 1); } // Check the prefix is valid const string DevicePrefixes = "XYMSTCDRVZ"; int prefixIndex = -1; // If the prefix is not an empty string, search // for the prefix in the device prefixes if (prefix.Length > 0) { prefixIndex = DevicePrefixes.IndexOf(prefix.Substring(0, 1)); } // if the prefix is not found, indicate it as a // missing type, otherwise set the details to be the // correct values for the type of device if (prefixIndex == -1) { // Device type not found m_DeviceType = DType.Missing; prefix = string.Empty; } else { // Device is valid m_DeviceType = (DType)prefixIndex; m_DataSize = ReturnDeviceDataSize(m_DeviceType); m_DeviceDesc = ReturnDeviceDesc(deviceType); m_DeviceName = deviceName; } // If the device number is valid, set it if (((device.Length - prefix.Length) > 0) && (m_DeviceType != DType.Missing)) { string IDstring = device.Substring(prefix.Length, device.Length - prefix.Length); if (IsNumeric(IDstring)) { m_deviceID = Convert.ToInt32(IDstring); } else { m_deviceID = -1; } } else { m_deviceID = -1; } } /// <summary> /// Returns the desciription of the given device type /// </summary> /// <param name="deviceType">The PLC device type</param> /// <returns>The device description</returns> private string ReturnDeviceDesc(DType deviceType) { string deviceDesc = string.Empty; switch (deviceType) { case DType.X: deviceDesc = "Input"; &

  12. Hi, Just moved up to Works3 and I was wondering if anybody has found a way to show the full name of a label in the FBD/Ladder editor. It currently just shows the first 15 characters or so and then three ellipses (...). My label/tags are usually defined much longer than this. I know you get the full name on mouse-over it's just that I am finding it to be a bit of a pain to be honest. Cheer

  13. I would do something like the following... subscript := 0; requiredMatch := 3000; smallestDiff := 32767; FOR X:= 1 TO 15 DO diff := requiredMatch - myArray[X]; (* get the difference between the search item and the item in the array *) IF diff < 0 THEN (* if the difference is negative then make it positive *) diff := diff * -1; END_IF; IF diff <= smallestDiff THEN (* if it is the smallest difference then record where it is in the array *) smallestDiff := diff; (* if there are two items with the same difference to the one you are comparing *) subscript := X; (* then using < will find the first match using <= the last one *) END_IF; END_FOR; myArray[subscript] (* the nearest match *) but I'm sure somebody could do it more elegantly! Regards

  14. It could be that the program is using a digital or analog "Fill" object that fills in a "framed" area with a certain colour. if the "Fill" object is not totally enclosed (it has no frame area to fill only the entire screen or there is an small gap where it can bleed out) then this might give such an error.

  15. I would at a minimum ask the following... What are you going to do with the data you have captured? How will the data recorded in the database be presented to the user? What about visualising and searching the data you have captured? do you need by date or batch, or good vs bad, per day or batch etc? What about printing and saving to excel or pdf etc? is this a requirement. I would address these questions before picking a solution. How will the "lists" created on the computer be transferred to the HMI? I presume there would not need to be any technical knowledge required to do this. For example a user just enters the details within a form presses a save button etc. And it appears on the HMI. Will the PC in the office be used for anything else other than data capture? If the PC is purely for the use of data capture you could go with a SCADA or cheap PC "HMI runtime" depending on your needs on visualising the data you have captured. You could create and edit the lists that are required to follow on the screen and punch them in directly into the PLC (not HMI). This would only work if the language require could be covered by ASCII. Problem with this would be if you needed to show pictures as well (to compare the product against a known good example for instance). Just a few thoughts

  16. We also used the whole 32K of R registers in the FX3U (to hold recipe information sent from a PC). Never once lost any info and we have a hundred or so installations worldwide. Think it's a bit different on the 3G though - fairy sure we needed an extra battery to hold up the R registers (we don't use 3G much so I could be wrong)

  17. Hi Colin, Yes you can do all the settings via programming but it is much easier in the configurator. Otherwise you would need to add PLC code for every HMI you use - and to be honest to the PLC, SCADA is just another HMI. Only time I have ever coded for Ethernet on Mitsubishi (Fx & Q) was for PLC to PLC Comms. Otherwise I just use the configurator. Your SCADA will use an OPC Server to connect to the PLC. The settings I gave you were the recommended ones for Kepserver (probably the most common OPC server). Might want to check that the port numbers entered into the PLC and SCADA / HMI are in the same format. For example the Beijer HMI's we use want the port number to be entered in decimal. But the PLC in Hexadecimal - it's easy to enter the value in the wrong format especially if the HEX value does not have any alphabetic characters in it. This has got me more than once before. Regards

  18. For the 71 settings you could try... Protocol: TCP Open system: Unpassive Fixed Buffer: Send Fixed Buf. Com: Procedure exist Pairing: No pairs Existence Conf: No confirm Port: 1389 OR UDP Open system: --- Fixed Buffer: Recive Fixed Buf. Com: Procedure exist Pairing: No pairs Existence Conf: No confirm Port: 1388 Dest IP: No Settings Dest Port: FFFF We always use UDP - needless to say port number must match up with SCADA. Regards