IPC90 read inputs->calculate outputs->set outputs.

softport

Member
Join Date
Feb 2021
Location
Texas
Posts
3
Hello, I am trying to write a program to simulate an ISSC IPC90.

The IPC90 has some internal variables, I think the correct name is 'internal relays'. As far as the cycle: read inputs, calculate outputs, set outputs, should these internal 'relays' be treated the same as the real outputs, and not modified till it is time to set the real outputs?

Example:
An internal relay state is 'off'.

While stepping down the ladder, I find the internal relay as an output, which, according to the logic on the left side of the rung, should be set. I set the internal relay state to 'on'.

Further down the ladder, I find the same internal relay as an input, on the left side of the ladder. Here, do I need to use the original state of the internal relay, which was 'off', or the new state 'on', set higher up on the ladder?

Thank you
 
Last edited:
I think you are confusing yourself.
The original convention of a PLC (well most) was update the inputs before the scan of the program, scan (run) the program update the outputs.
Internal relays are not like real I/O, Real I/O is mapped into internal memory so I0 (first input) is not generally the real input but a copy of it.
What they call internal relays are accessed directly so it depends on the state of the logic before it. if true then it stays true while the logic in front of it is true.
Even I/O in some respects works like this for example if you use say an output as a relay contact if it is true because it has been switched on previously in the program it will be true further down the program, however the real output will not be on until it has been updated at the end of scan of the program when the I/O map is transferred to the real I/O, before others start going on about asynchronous I/O, yes some PLC's update the real I/O either on a time basis, directly or by an interrupt, In saying that even those PLC types that update before the beginning and after the program scan can update immediate if they have the functions to do so.
 
Further down the ladder, I find the same internal relay as an input, on the left side of the ladder. Here, do I need to use the original state of the internal relay, which was 'off', or the new state 'on', set higher up on the ladder?

Consider carefully what @parky wrote, but your simulation should use the new value i.e. the value written by the earlier (higher up) rung.

TL;DR


I find @Ron Beaufort's YouTube training sequence to be most helpful here; it takes less than 2h to watch but provides a solid basis for understanding how a PLC program scan works.

Regarding @parky's post: there are exceptions of course, but in general, the fundamental concept is that any input bit read or or output bit written by rungs during the program scan is a copy (in memory, presumably) of the physical I/O state; how and whether the PLC updates memory copies from physical inputs or writes memory copies to physical outputs, either between or during program scans, is dependent on the PLC design and implementation. Since the OP's particular case is dealing with a physical output, and specifically the memory copy of the output, the information flow would almost certainly be from memory to physical output, so using the memory copy in in any contact (i.e. on the "left" side of the rung) should be the correct thing to do.


The term 'internal relay' is not necessarily wrong, but it can be misleading: internally they are memory bits, not relays, although the difference between the two is somewhat semantic.
 
As DR has re-iterated, it does depend on the PLC, but in any case if an output coil whether it be real I/O or internal bit, if it is on before the use of the contact (as you put it input contact) then what ever it drives in the following logic will be true. so it does not matter what the real I/O's state is it becomes what ever the coil is before the use of a contact that determines what will happen.
A simple example is the creation of a one shot or OSR.

this uses the scan of the PLC to turn on a bit for one scan only so
AND My Input AND not Oneshot_Latch = Oneshot
AND My_Input = Oneshot_Latch.
So when the input goes true the oneshot latch is false so the oneshot turns on
the second rung turns on the oneshot latch so on the next scan of the program the first rung turns false because the input is on and the oneshot latch is on so the not contact becomes false thereby the oneshot goes back off. it will stay in this state until the input goes false then back to true to enable the oneshot.
Hope that explains it a little.
 
Thank parky and DR, I think it's a little clearer now: treat the internal relays (or bits) just like
any output. That is, while executing the ladder, work only on the copies.

At the moment I have an internal array of inputs, and an internal array of outputs. If I understand
correctly, I should also make an array of internal relays (bits).

Before starting the scan of the ladder, I should first make a copy of the output array, and a copy
of the internal relay array. These arrays will be modified while going down the ladder.

Once the ladder scan is complete, transfer the -copies- of the output and internal relay arrays,
into the originals, then set the real outputs from the new internal output array.

I have a feeling there may be some unnecessary duplication here. That is, maybe there is no need
to make copies of the internal arrays, just use the originals for the ladder scan.

After watching a few videos and browsing through this forum, I thought all was clear, till I came
across the internal relays. I will re-read your posts, and look at the videos that were mentioned.


Thanks again... and thanks for the latch example.
 
Last edited:
Before starting the scan of the ladder, I should first make a copy of the output array, and a copy
of the internal relay array. These arrays will be modified while going down the ladder.
To reiterate:

This is called an input map. Cf. here, which has some use cases.

It may or may not be necessary, depending on the hardware and firmware implementation of any particular PLC, as well as what the program is trying to do. My understanding is that is never necessary with A-B SLC and MicroLogix*, but it would be necessary with CompactLogix and ControlLogix if the program needed to see the same value for an input bit more than once in the same scan.

Also, it may not be necessary to map all inputs.

There are some who always create the input map, and there are valid reasons for that other than "once bitten twice shy."


* It may make sense to map some values in Micrologix at the start of a scan e.g. S:4, the free-running clock.
 
Most PLC's automatically map the bits for example Siemens the mapped bit could be I 0.0 the actual I/O is usually addressed as PIW 0 (Peripheral input word), Mitsubishi the mapped bit would be X0 the real I/O is DX0
So in many PLC's the I/O bits you use are the mapped bits like X0 or output Y0 etc.
To write or read directly to the I/O on Mitsubishi (Immediate update) you would use DX or DY.
It will depend on the platform but if the manual says I is input it normally referrers to the mapped area unless otherwise stated, either way, it will not matter unless you need to update the in/out actual I/O for example high speed (greater than the scan time), this is only usually needed for example if you need to catch a pulse faster than say 50 to 100ms.
Most PLC's will have a scan time of less than 20ms for the average sized program.
 
Thanks parky and DR.

I have made a program to simulate the latch example. It seems
to work, and it has helped me understand better how the program
should be structured, at least better than before (trying to
juggle a bunch of different arrays).

The simulation has a single array that stores all the inputs,
outputs, and internal variables. The array size is the same
as the maximum number of io's (external + internal). Each array
entry is a structure, which holds all the channel's info:

Interface card number (1-12)
Interface card channel (0-15)
Global channel number (0-255)
Channel name

The array entries are in order: array[0] is channel 0,
array[255] is channel 255.

What I like about it is that writing the ladder logic is very easy,
compared to before, when I was trying to pick channel states from
different arrays. Now everything is easy to find by channel name,
making the ladder logic a lot cleaner. And the big bonus is that it
seems to work, so even if I'm still a bit confused, I can go ahead
with the real project.

Thanks for all your input.


Code:
#ifdef __cplusplus
extern "C" {
#endif

// Compiler gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0


#include <stdio.h>
#include <unistd.h> // for sleep()
//#include <stdlib.h> // for system("clear")  Linux clear screen

#define CHANNEL_NAME_LEN 15
#define INTERNAL -1


void ladder(void);
void set_outputs(void);


enum State{ OFF=0, ON };
const char* state_names[] = {"OFF", "ON"};  // Used to print "OFF" and "ON", from 0 and 1


// IPC90 Handles a maximum of 12 interface cards, and 256 io channels (0-255)
// Each interface card can control 16 channels
// Maximum real io channels: 12*16 = 192, in global address range 0 - 191
// Channel numbers higher than 191 are internal relays
struct Channel{
    int global_address;         // 0-255
    char name[CHANNEL_NAME_LEN];    
    int interface_card_num;     // 1-12
    int interface_card_channel; // 0-15
    enum State state;           // ON/OFF
};

struct Channel channel_array[256];

#define BUTTON          channel_array[0].state
#define LAMP            channel_array[16].state
#define ONESHOT         channel_array[200].state
#define ONESHOT_LATCH   channel_array[201].state 


int main() {

    printf("Starting...\n\n");
    
    // Create input channel "Button"
    struct Channel button = {
        .global_address = 0,
        .name = "Button\0",
        .interface_card_num = 1,
        .interface_card_channel = 0,
        .state = ON
    };
    
    // Create input channel "Lamp"
    struct Channel lamp = {
        .global_address = 16,
        .name = "Lamp\0",
        .interface_card_num = 2,
        .interface_card_channel = 0,
        .state = OFF
    };
    
    // Create internal relay "OneShot"
    struct Channel oneshot = {
        .global_address = 200,
        .name = "OneShot\0",
        .interface_card_num = INTERNAL,
        .interface_card_channel = INTERNAL,
        .state = OFF
    };
    
    // Create internal relay "OneShotLatch"
    struct Channel oneshotlatch = {
        .global_address = 201,
        .name = "OneShotLatch\0",
        .interface_card_num = INTERNAL,
        .interface_card_channel = INTERNAL,
        .state = OFF
    };
    
    // Save input channels to array
    channel_array[button.global_address] = button;
    channel_array[oneshot.global_address] = oneshot;
    channel_array[oneshotlatch.global_address] = oneshot;
    channel_array[lamp.global_address] = lamp;
    
    
    // Clear screen for both Windows and Linux
    printf("\033[2J\033[1;1H"); 
    
    int run = 1;
    int loop_count = 0;
    while(run){

        ladder();
        set_outputs();
        
        sleep(2);
        
        loop_count++;
        if(loop_count == 3) run = 0;
        
    }
   
    return 0;
}

int scan_count = 0;
void ladder(){

    // Ladder start
    
    // Line 1
    ONESHOT = BUTTON & !ONESHOT_LATCH;
    
    // Line 2
    ONESHOT_LATCH = BUTTON;
    
    // Line 3
    LAMP = ONESHOT;
    
    // End ladder
    
    scan_count++;
    printf("Scan number %d\n", scan_count);
    printf("System state: \n Button: %d\n Oneshot latch: %d\n Oneshot: %d\n Lamp: %d\n  ", 
                                BUTTON, ONESHOT_LATCH, ONESHOT, LAMP );
    printf("\n");
}

void set_outputs(){

    printf("Turning lamp %s\n\n", state_names[LAMP]);

 }


/*
References:
ipC90 Installation and Maintenance Manual ISSC I-201
https://stackoverflow.com/questions/3789340/combining-c-and-c-how-does-ifdef-cplusplus-work
https://codeforwin.org/2018/07/how-to-declare-initialize-and-access-structures-in-c.html
https://stackoverflow.com/questions/17335816/clear-screen-using-c
https://stackoverflow.com/questions/3168306/print-text-instead-of-value-from-c-enum
*/
Output:
Code:
Result of scan 1
----------------
System state: 
 Button: 1
 Oneshot latch: 1
 Oneshot: 1
 Lamp: 1
  
Turning lamp ON

Result of scan 2
----------------
System state: 
 Button: 1
 Oneshot latch: 1
 Oneshot: 0
 Lamp: 0
  
Turning lamp OFF

Result of scan 3
----------------
System state: 
 Button: 1
 Oneshot latch: 1
 Oneshot: 0
 Lamp: 0
  
Turning lamp OFF
 
Last edited:

Similar Topics

Hi everyone; Could anyone help me about the ladder symbols of IPC90? I have a software and inside it there is a symbol called as TRO, I want to...
Replies
0
Views
1,630
Hi everyone i have a customer, who wants to show an alarm on the machine, if the I/O forces are enabled and set, on at ControlLogix L81E with...
Replies
3
Views
140
Hi Iam using monitouch hmi(V9 soft) with omron plc cj2m (CX programmer). In this I want to read a data from hmi to plc. The data was like...
Replies
0
Views
73
Hi everyone. Quick questions. On UnityPro, I want to open and quickly read tags from a .STA files witouth opening the program. I have 30 plc...
Replies
2
Views
103
Hi everyone, I am working on a project that needs to expose the SV (Set Value) of a temperature controller to a SCADA system. SCADA <-...
Replies
4
Views
134
Back
Top Bottom