To leverage the power of the FSC (File Search and Compare) instruction, it's essential to utilize it effectively. Begin by referring to the help documentation related to this instruction to familiarize yourself with its functionality. Your search expression should resemble the following format:
`Part_Recipe[FSC_Control_Tag.POS].Part_Number = PartNumberYouAreSearchingFor`
When the FSC instruction successfully identifies a match, the operation will terminate at that specific position, enabling you to pinpoint the corresponding array element. Subsequently, you will need to execute a COPY command structured as follows:
- **Source:** `Part_Recipe[FSC_Control_Tag.POS]`
- **Destination:** `RecipeTagYouWantTheDataIn`
- **Length:** `1`
This process will help streamline your data retrieval and management tasks efficiently.
ASF recommends utilizing the FSC (File Search and Compare) instruction, as it's specifically designed for this purpose. To get started, consult the help file associated with the instruction. Your expression should be structured as follows:
`Part_Recipe[FSC_Control_Tag.POS].Part_Number = PartNumberYouAreSearchingFor`
If the FSC instruction successfully locates a match, it will stop at that position, allowing you to identify which element of the array you're working with. Next, you'll want to execute a COPY operation similar to this:
- **Source:** `Part_Recipe[FSC_Control_Tag.POS]`
- **Destination:** `RecipeTagYouWantTheDataIn`
- **Length:** `1`
Please note that this approach won’t work if the string belongs to a User-Defined Type (UDT). I initially encountered an error stating "Invalid array subscript specifier" when I tried various methods. However, I realized that I had been using an existing array of control tags, specifically `R[1]`, in my live program. This caused issues with nested indexing, which the system could not process correctly. After creating a new control tag named `R1`, the verification process completed successfully.
By following these steps, you can effectively leverage the FSC instruction to optimize your file search and comparison tasks.
According to ASF, to utilize the FSC (File Search and Compare) instruction effectively, start by consulting the help documentation related to this feature. This will provide essential guidance for your implementation. Your expression should resemble the following format:
```
Part_Recipe[FSC_Control_Tag.POS].Part_Number = PartNumberYouAreSearchingFor
```
When the FSC instruction identifies a match, it will pause at that specific position, indicating the corresponding index within the array. At this point, you can execute a COPY operation similar to the following:
```
Source: Part_Recipe[FSC_Control_Tag.POS]
Destination: RecipeTagYouWantTheDataIn
Length: 1
```
Remember, it's easy to overlook that the Logix platform has the capability to search strings effectively. This functionality can significantly enhance your workflow and data handling.
Is it necessary to use ladder logic? Utilizing structured text can make this process simpler, and I believe you can access the members of an AOI (Add-On Instruction) easily.
Subject: Inquiry About Tag "NAME" in HMI Configuration for Expression Setup
Hello OkiePC,
I noticed that your setup includes an additional tag in the expression: `HMI_Name_Entry=Part_Recipe[R1.POS]NAME`. I'm curious about the purpose of this "NAME" tag. What is its data type, and is its inclusion essential for functionality?
In a similar project, I'm utilizing the FSC instruction and I haven't had to include anything beyond the [.POS] segment, and everything operates smoothly. However, when I attempt to replicate this setup, I encounter errors such as "Invalid Expression" or "Invalid Array Subscript Specifier."
I would greatly appreciate any insights you can provide on why your configuration works while I'm facing challenges. Thank you!
User bbishop108 commented:
"OkiePC, I initially configured my setup similarly to yours, but I noticed you have an additional tag in your expression: `HMI_Name_Entry=Part_Recipe[R1.POS]NAME`. What exactly does the tag 'NAME' represent? Additionally, what is its data type, and is it essential? I have a comparable program utilizing the FSC instruction that does not require anything after the [.POS] segment, and it operates smoothly. However, when I attempt to replicate this process, I either encounter an 'Invalid Expression' or 'Invalid Array Subscript Specifier' error. I'm intrigued as to why your setup functions correctly while mine does not!
To elaborate, the User-Defined Data Type (UDT) I created includes NAME as the text for the recipe name. In many of my systems, I prefer to use the term 'Title' for UDT elements, especially since 'NAME' is often reserved. Also, ensure that you place a period after the closing bracket of the control position tag and before the UDT member you're searching for. In my case, it appears as follows:
```plaintext
Part_Recipe[R1.POS].NAME
```
It's crucial that your control tag is not an array tag. This detail had me confused earlier; the control tag should be a standalone tag rather than an array. Moreover, I observed that when all my string tags were empty and I first verified and assembled, the EN bit remained 'stuck' on, while the FD bit was not set, although the IN bit was active. After entering some text in the HMI_Name_Entry, those bits did not change. According to the help file, the IN bit turns true when a match is found and must be deactivated to continue searching. To experiment further, I incorporated the Test bit and Match bit, along with some latch and unlatch instructions. Once I unlatch the IN bit and toggle the Test bit again, it seemed to work.
I’m puzzled as to why the FD bit was not activated when all the strings were empty. This example was just a quick test, so for your practical application, keep in mind that you need to manage scenarios where there may be multiple matches or no matches by monitoring the IN bit, the POS register, and the FD bit.
The other example you mentioned that successfully uses the FSC is likely referencing a tag of type STRING instead of a UDT member, which defaults to the DATA portion of the string tag."
Feel free to ask if you need further insights or clarifications!
Here’s my current setup, but unfortunately, it’s not functioning correctly. I'm encountering an "Invalid member specifier" error. Here’s how I have structured my expression:
`Part_Select = Part_Data[Control.POS].Part_Recipe.Part_Select`
In this context, `Part_Select` is a string tag that corresponds to the entry from the HMI (Human Machine Interface). `Part_Data` refers to the tag name utilized in my User Defined Type (UDT), specifically `Part_Recipe(50)`. I've defined the `Control` tag as a control type within this configuration.
If you're facing similar issues with tag specifications or UDTs, you may want to explore troubleshooting methods for resolving invalid member specifier errors.
User bbishop108 shared their current setup, which has encountered an issue resulting in an "Invalid member specifier" error. The expression they are using is: `Part_Select=Part_Data[Control.POS].Part_Recipe`. Here, `Part_Select` is a string tag that accepts input from the HMI. The `Part_Data` represents the tag associated with my User-Defined Type (UDT), specifically `Part-Recipe`, and utilizes the index `Part_Data(50)`. I have designated `Control` as a control type. To clarify, is "Part_Recipe" indeed a UDT member of the STRING type? Additionally, is `Part_Data` a UDT tag that incorporates `Part_Recipe` as its string component?
The Part-Recipe structure serves as the User Defined Type (UDT), which encompasses three previously discussed data types: SINT, String, and INT. The identifier for this UDT is referred to as Part_Data, where Part_Data denotes the tag name that utilizes the UDT as its data type. To specify, the complete reference for the data type is expressed as Part_Recipe[50].
Perhaps a screenshot would be beneficial—especially one that also displays the tag, similar to the example I'm using.
Let's find out if this screenshot will be effective for me!
This approach is highly effective for my needs. Instead of including "Part_Recipe" at the end of your expression, you should use "Part_Number"—that's the specific detail you are looking for.
daba: WOW, I can’t believe it! After changing the expression to "Part_Number" as you recommended in your example, all my errors disappeared! I found the previous setup confusing; I initially had nothing following [Control.POS], which resulted in several issues. Once I added "Part_Recipe," new errors emerged. However, after implementing your suggestion, it was like magic—no more errors! I want to extend my gratitude to everyone who patiently guided me through this process. It’s reassuring to know that I wasn’t too far off with my original expression. I just needed that crucial nudge (like a locomotive full steam ahead) to make the connections! Now that the Functional Specification Document (FSD) is error-free, I'm confident I can successfully configure the remaining logic for this project. Incredible advice, and yet another issue resolved! Thank you all once again!
When designing your User-Defined Types (UDTs), it's important to consider the efficient use of the STRING data type. This data type supports strings of up to 82 characters, which can lead to significant memory wastage. To optimize memory usage, you can create custom STRINGxx data types that are tailored for shorter or longer strings. For instance, if your Part_Number is limited to a maximum of 8 digits, defining a STRING8 data type can result in substantial memory savings. While the standard STRING type consumes 88 bytes, a STRING8 only requires 12 bytes. By applying this optimization across 50 Recipe tags, you can save over 3 kilobytes of memory. Embracing such strategies not only enhances system performance but also contributes to a more resource-efficient database design.
User bbishop108 expressed their surprise: "What?! I followed your suggestion to change the expression to 'Part_Number,' and just like that, all my errors disappeared! Initially, I was confused because I didn’t have anything after [Control.POS], which led to errors. Then, when I added 'Part_Recipe,' I encountered even more issues. However, after making the adjustment you recommended, voila—no more errors! I truly appreciate the patience and support from everyone who helped me through this challenge. It’s reassuring to know my initial expression wasn’t too far off; I just needed that extra push (likely a significant one!) to connect all the dots. Now that the FSC is error-free, I feel confident in configuring the rest of the logic for this project. Fantastic advice, and yet another problem solved! Thank you once again! Remember, sometimes the details can cloud your vision..."
Great observation, Daba! I missed that as well. Everything appears to be in order. You can implement a solution such as copying `part_data[control.pos]` to `current_recipe` and then refining your search. Additionally, consider incorporating some conditional logic for scenarios where the search is `.dn` and the part is not `.fd`. This will enhance your code's functionality.
DonBlack: I am currently focused on developing this feature, and I will also incorporate a "not found" condition that will be visible on the Human-Machine Interface (HMI).
Here's a helpful suggestion: once you've located and copied the part recipe and reset your search, consider clearing the HMI input tag. I recommend doing this to ensure it's empty for the next user who needs to enter a part number. This small step enhances usability and streamlines the process for future tasks.
bbishop108 shared: DonBlack, I'm currently focused on that exact task, and I plan to incorporate a 'not found' status that will be displayed on the HMI. One additional point I’d like to touch on is the use of INT and SINT data types. You should only utilize these data types if you need to communicate with another device that exclusively operates on 8 or 16-bit data, such as a PLC5. However, since ControlLogix controllers operate on a 32-bit architecture, any time you reference a tag (or its member) that is smaller than a DINT, it must be transformed into a DINT for processing and converted back for storage. This process can lead to inefficiencies. To optimize your application, consider defining all your numeric data as DINTs and/or REALs for enhanced performance. Additionally, your "Part_Number" could potentially be a DINT, as it can accommodate positive integers up to 2,147,483,647. This approach may provide ample digits for your needs while also improving overall efficiency and memory utilization.
DonBlack: It seems we’re aligned in our thoughts today! I've just completed a similar task! Daba: I'm utilizing the INT data type to assign a value to a counter preset, while the SINT data type is designed for an external device that necessitates such specifications. Since my part numbers are alphanumeric, I need to utilize the STRING data type for accurate representation. Thank you!
User bbishop108 commented: "DonBlack, it seems we are in sync today! I just completed that task! Regarding my setup, I'm utilizing the INT data type to transfer values into a counter preset, while the SINT data type is necessary for interfacing with an external device that requires this specific format. Since my part numbers are alphanumeric, I also need to use the STRING data type for those elements. I appreciate your input!"
To respond: "No worries! It looks like you're on the right track. Just a thought — have you considered optimizing the STRING type to reduce memory usage? That could be beneficial!"
Thank you for your insights! You're absolutely right; I need to conduct some tests to identify areas for optimization. I truly appreciate all your assistance—it has significantly expedited the resolution process. Understanding that a Programmable Logic Controller (PLC) can perform a specific task is very different from knowing how to effectively program it to achieve that task. This forum has been an invaluable resource for me as I navigate the complexities of PLC programming. With each passing day in this field, I strive to leverage more of the capabilities that PLCs offer. I must say, the expertise shared here far surpasses that of RA Tech Support, especially concerning Allen Bradley products. Once again, thank you for your continued support!
User bbishop108 commented: "DonBlack, I see we're on the same wavelength today! That's exactly what I just accomplished! As for my programming, I'm utilizing the INT data type to assign a value to a counter preset. The SINT type is specifically required for an external device that operates with this data format. Since all of my part numbers are alphanumeric, I'm in need of the STRING data type for those entries. Thank you!
To elaborate on a crucial point I initially overlooked: a Logix 5000 counter preset utilizes a DINT data type. Therefore, integrating a DINT into your User Defined Type (UDT) is not only suitable but also enhances program scan efficiency. Moreover, considering the memory allocation in your UDT, using a DINT will have no negative impact on the overall byte count of your UDT.
I want to emphasize this for everyone reading: it is advisable to stick with DINTs as your primary data type—unless there’s a compelling reason to choose a different data type."