We've Moved!

Please update your bookmarks from embeddedarm.com to embeddedts.com. You've already been redirected and may close this modal to continue.

TS-PLC Ladder Logic Tutorial

Published as a Documentation on Jan 10, 2019

In this tutorial we will write a ladder logic program for two TS-PLC units utilizing the RADIO option. The main unit "DOOR" will control a lock (either locking or unlocking it) and will have a switch input which will toggle the lock state whenever the switch is toggled. The green LED will be lit when the door is unlocked, and the red LED will be lit when the door is locked.

The second unit "REMOTE" will have basically this same functionality (minus the lock output), except that it will communicate with "DOOR" to tell it when to toggle the lock, and "DOOR" will communicate with it the current lock state.

Next, we will add to the "DOOR" the function where the door will automatically lock itself after a delay has occurred after each time the door is unlocked. Add a dial input to control the length of the delay, between 1 and 60 seconds.

Then we will add an alarm output and a door sensor (open/close). If the door is open and the lock is locked, sound the alarm forever.

Finally, given a controller with an RTC option in range of both units during normal operation, we will add functionality whereby the lock will not unlock on Saturday or Sunday, or between the hours or 10p.m. and 5a.m.

Note: If you want to try this example with only one unit, just skip the parts that involve the REMOTE unit.

Figuring out the specification details

First, the door lock should normally be locked, so that nobody can gain entry by means of a power failure. We can connect the door lock via a solenoid on one of the outputs. When the solenoid is energized the door will be unlocked. Our solenoid is energized by pulling one end to ground, therefore we can connect it to any of OUT4, OUT5, OUT6, OUT7, and OUT8.

We can use a SPDT switch for both devices with the end contacts connects to Vcc and GND, and the center contact connected to one of our input ADCs. Since we are using RADIO and not RS485, we have ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, and ADC8 to choose from.

Our pot can also be connected between Vcc and GND, with the center tap feeding into one of our ADCs.

Our door sensor will be a switch that closes when the door is shut, and opens when the door is open. We will connect one side of the circuit to Vcc, and the other to one of our ADCs with a pull-down resistor so that when the door is shut, we will have Vcc at our input, but when the door is open, we will have GND.

Our alarm will be activated by feeding it Vcc. Therefore we can use either OUT7 or OUT8 with a positive polarity.

To summarize our hardware requirements:

  • a solenoid
  • 2 SPDT switches
  • a suitable potentiometer
  • a contact switch
  • a suitable alarm device

To summarize our port requirements:

  • low side switch for the solenoid
  • an ADC input for the SPDT switch
  • an ADC input for the potentiometer
  • an ADC input for the door sensor
  • high side switch for the alarm

From these requirements we can make the following assignments to the TS-PLC (model 701) signals:

  • OUT7 = ALARM
  • POL7 = 1
We have chosen these values such that the name corresponds to the active (high or 1) state.

Figuring out the logic we will need

First, since we are running on a RADIO device, we will need to set the RS485_PROT signal to 1, so as to enable Peer mode.

Next, we want a change on either switch input to toggle the UNLOCK output. Since we have ADC inputs and not digital inputs, the first thing we must do for both signals is to create a digital signal. We do this by setting up voltage thresholds: if the input voltage exceeds our upper threshold we set our digital signal to 1, while if it goes below our lower threshold we clear our digital signal to 0. Next, to detect when the digital value of the switch changes we use an "ANY EDGE DETECTOR" on each signal. This will create a high output for one scan cycle each time either input changes. We will connect each of these outputs to a toggle coil for the UNLOCK signal.

Using a contact input from the UNLOCK signal we will connect to two coils to control the red and green LEDs. The green LED will connect directly from the UNLOCK contact, as it should be high when the UNLOCK signal is high. The red LED will be inverted, so we will use an inverted coil in this case.

Making the door automatically re-lock after a period of time is fairly easy. The "TURN-ON DELAY" (TOD) allows us to generate a true output when the input has been true for a specified amount of time. The input of the TOD is the UNLOCK signal. The delay value comes from the pot ADC run through a scaler to adjusts the pot range of 0 to 0x3ff to our desired values of 1 to 60. First we note that 0x3FF is 1023 decimal, but since 0 is also a value we actually have 1024 possible values, and since the minimum value we want is 1 we will first add 1 to our ADC value. Then integer division of 1024 by 60 gives us 17. Therefore we will divide our incremented ADC value by 17 every cycle and then store that in a register which we use to time the turn-on delay. The output of the TOD will be connected to a reset coil on UNLOCK, which will turn unlock off when it is activated, thereby locking the door.

To implement the alarm we will use DOOR_SHUT and UNLOCK from two inverted contacts, in series. If DOOR_SHUT is false and UNLOCKED is false the signal will propagate through to our final element, a set-only coil connected to alarm. This will cause the alarm to sound until the system is reset (by cycling power).

To prevent the lock from unlocking at specific dates or times we first must determine the logic to generate a signal that is high when the door should not be unlocked. Saturday and Sunday correspond to the DayOfWeek signal being a value of 7 or 1. We can create two comparisons for equality (==) between DayOfWeek and the values 7 and 1. The output of each of these goes to a reset coil on UNLOCK. (Note that we create this rung after our other rungs, because it will essentially override any former values of UNLOCK. There will not be a momentary unlocking of the door on Saturday if the switch is toggled, because signal values are not updated to the hardware until after the compute phase is completed.) Next we create similar constructs for the Hour signal. If it is greater than or equal to 22 (10p.m.) or less than 5 (5a.m.) the UNLOCK signal is reset in the same manner as it is for Saturday and Sunday.

Creating the Mappings

Now that we have finished our design, it is time to enter it into the PLC controller. Bring up the ladder logic page in your browser by entering the IP address of the PLC controller. The current ladder logic program will automatically come up. Click on the "Load" button at the top of the page. At the bottom of the page the list of available files will be shown. Scroll down to the bottom of this list, if needed, and enter the name door in the text box next to the button which reads Create New File . Make sure the checkbox Copy from current file is not checked and then click on Create New File . If there was an existing program by that name it would be loaded and you would need to click on the Clear button at the top to get rid of it; otherwise you will be presented with an empty ladder logic program.

Before we enter our ladder logic we want to create the mappings necessary for our program. Click on the Mappings links at the top of the page on the right side. The Mappings Editor will come up in a new window or tab. First we want to assign a physical device to each of our logical devices, which we are calling DOOR and REMOTE . If you do not see the device id of the devices you want to use in the top pane, check that they are on and connected properly (485) or in range (RADIO) of the PLC controller, and then click on the Scan button. During the scan you should see the green and red LEDs on all connected or in range units blinking rapidly. When the scan is complete you should see your devices in the list. Change the device name of the devices you want to use to DOOR and REMOTE , respectively.

Next we need to create signal names for each of our I/O signals. Use the New button at the bottom of the screen to create new entries as needed, and enter the following information:

Signal Name Arch Device Name Device Signal
DayOfWeek T701 DOOR DayOfWeek
Hour T701 DOOR Hour

When you are finished click on the Save button and return to the ladder logic editor for the next step.

Creating the Ladder Logic

Now it is time to create our ladder logic. We have already loaded a new empty file called door and now we will enter our ladder logic into it, using the names we defined in the mappings editor. We will take the logic directly from what we deduced in section 2, "Figuring out the logic we will need".

Since the document is empty, the cursor should already be in the right place on the first empty rung. We are going to create an element for each of our devices to initialize them to peer mode since we are using the wireless radio. An assignment to a multi-bit signal is accomplish using the REGISTER STORE constructs, so we will click on that button on the right side. You should now see something that looks like this on the first rung:

      {  := }     
------{     }-----
Also note that at the bottom there are now three labeled text boxes, followed by a description of the construct. The first text box already contains the name of the construct, which in this case is "MOV". Do not touch that field. Hit the enter key and the cursor will jump to the text box labeled Destination Register , or you can also click the mouse in this field if you like. Now type DOOR_PEER and hit the tab key to jump to the next field ( Source Register ) and type 1 in that field. Hit enter again and focus will jump back to your ladder logic. (You should be able to tell this because the cursor will start blinking again on the right side of the selected construct.)

Note that if you make any mistakes along the way, you have several options. You can hit the delete or backspace key (depending on your computer and browser version) to delete the currently selected element. You can also click on the Delete button at the top of the screen to delete the current rung. As a last resort, you can also click on the Clear button at the top to completely erase the document. You may wish to click on the Save button at the top periodically when you are pleased with the current state of the logic. Then if you make a mistake later and have trouble fixing it you can click Revert to go back to the saved state.

Note that the way we have done this assignment means DOOR_PEER will be assigned the value of one every scan cycle. We could also have created additional logic to condition our assignment on the INIT_COMPLETE bit not being set, in which case the assignment would only have been made once per startup. However in this case it is fine to assign it every scan cycle, as this effectively make the value a constant, as any change to this register (for instance during debugging) will revert to the correct value on the next scan cycle.

Next we need to create the same construct for the REMOTE unit. However since it is on a different unit we need to create a new rung, as each rung can only contain ladder logic for a single unit. Click on the Below button at the top to create a new rung below the current rung. Then follow the same steps as before to create a REGISTER STORE construct to assign a value of 1 to REMOTE_PEER .

Now we need to create the voltage thresholds to convert our switch inputs from 12-bit analog values to one bit digital signals which will either by true or false. Click on the Below button at the top to create another new rung below the current rung, which should be the REMOTE_PEER assignment. Now we need to enter two comparators. Click on the "GREATER THAN" button on the left to create the first comparator, and in the text fields at the bottom enter SWITCH for "Source Register 1" and 0x200 for "Source Register 2". This construct will produce a true output with the switch is on. Now select the new comparator construct either by hitting enter or clicking on the construct, so that it is selected and the cursor is blinking. Press the down arrow key. You should notice at this point that the cursor has moved and is now flashing below the construct instead of to the right. This means that the next construct we insert at the point will be in parallel with our current construct and underneath it. Now click on the "LESS THAN" button on the far left. For the second construct enter SWITCH for "Source Register 1" and 0x100 for "Source Register 2". The rung should now look like this:

    [ SWITCH> ]   
+---[  0x200  ]---
|   [ SWITCH< ]   
+---[  0x100  ]---

Next we need to use the output of these comparators to set and clear the value of our digital version of the switch. Select the top comparator and hit the right arrow key. You should see the cursor flashing on the right of the construct again. Now click on the "COIL" button on the left side. Enter SW for the name, and click on the Set radio box in the bottom pane. Next, select the bottom comparator, make sure the arrow is on the right, and click on the "COIL" button. Enter SW for the name, and click on the Reset radio box in the bottom pane. The rung should now look like this:

    [ SWITCH> ]            SW       
+---[  0x200  ]-----------(S)-------
|   [ SWITCH< ]            SW
+---[  0x100  ]-----------(R)-------

Next we need to repeat the last steps to create another comparator for the switch on the remote. Create a new rung below the current one and repeat the above steps to create a rung that looks like this:

    [ SWITCH2> ]          SW2       
+---[  0x200   ]----------(S)-------
|   [ SWITCH2< ]          SW2
+---[  0x100   ]----------(R)-------

Now we need to connect both of our digital signals to any-edge detectors and use those to set the UNLOCK signal. We will put each of these on a new rung below the previous one. For the first rung, first click on "CONTACT" on the left. Set the Name to SW and make sure the Normal radio box is checked. Position the arrow on the ride side of the contact and then click on "ANY EDGE DETECT" on the left side. This construct has no parameters, so next click on "COIL" and enter "UNLOCK" for the name as click on the Toggle radio box. Next we need to create create the same functionality for the SW2 signal. However the SW2 signal is not on the same device as the SW signal. We can just repeat the above steps, replacing SW with SW2 . However we must keep in mind that we our rungs are assigned to devices, the device will be chosen based on assignment first. What this means is this: a coil assigns the value of a bit, whereas a contact merely gets the value of a bit. Since UNLOCK is being assigned, and UNLOCK is known to be a signal on device DOOR , then logic for the rung will be put on device DOOR . Therefore SW2 will be a virtual output from device REMOTE which device DOOR will listen to and use to set its own local copy of SW2 . In this case this is fine, but it is important to consider which device a signal will be assigned to if the signal is changing frequently. In general, try to minimize the quantity of signal changes that must be propagated around the serial network in order to maximize the efficiency and reliability of an implementation. For example, we would not want the value of SWITCH2 to be sent, as it could change (albeit only slightly) every scan phase due to ADC noise. By performing the digital conversion on the same device as the ADC we greatly reduce the traffic required.

The two new rungs should look like this:

         SW                               UNLOCK
--------[ ]-------------[OSA/\]-------------(T)-------
SW2                               UNLOCK
--------[ ]-------------[OSA/\]-------------(T)-------

The next step was to set the LEDs from the UNLOCK signal. However we know that the UNLOCK signal might be overridden in subsequent rungs so we will defer setting the LEDs until last.

Next we will add ladder logic to re-lock the door automatically. Create a new rung beneath the bottom rung so far. First we need to take our potentiometer value and scale it into a delay. Click on the "ADD" button and enter DELAY_POT for the "Destination Register" and "Source Register 1", and 1 for "Source Register 2". Then add a "DIVIDE" construct to the right of the ADD construct, and enter the same values except for "Source Register 2" which will have a value of 17. Create another new rung below, and click on the "TURN ON DELAY" button on the right. Enter DELAY_POT for the "milliseconds" value. Since the output of our scaler is in second, but the turn-on delay is in milliseconds, we need to add a multiplier to our DELAY_POT value. Note that so far we have operated directly on DELAY_POT which is a physical input from the ADC. This would work perfectly fine because DELAY_POT will be re-loaded with the current ADC value before the next compute phase. However, consulting the documentation for the ADC signals we find that they are only 12 bits in size. Therefore if we try to multiple by 1000 we will overflow our bits at some point. Therefore we need to create a new register name to hold the scaled value. Change the "Destination Register" field for the ADD construct to DELAY , and both the "Destination Register" and "Source Register 1" of the divided to DELAY as well. Since we have not defined DELAY anywhere, it will be inferred that it is a new 32-bit register. Since there are no assignments to registers of known devices in this rung, the source register DELAY_POT will be used to infer that this rung belongs in device DOOR . Now create another construct "MULTIPLY" between the "ADD" and "DIVIDE" constructs. This can be done either by setting the arrow on the right side of the add, or on the left side of the divide, and then clicking on "MULTIPLY". When you have finished this step the rung should look like this:

  {   DELAY:=   }    {  DELAY:=   }     { DELAY:=  }  
--{ DELAY_POT+1 }----{ DELAY*1000 }-----{ DELAY/17 }--
Modify the next rung to use DELAY for the TON parameter instead of DELAY_POT . Then insert a COIL to the right of the TON and set its "Name" to "UNLOCK" and click on the Reset radio box. This rung should now look like this:
---[TON DELAY ms]---------(R)-------

Next create a new rung below for the alarm logic. Create two contacts in series followed by a coil, and make sure the "Inverted" radio box is checked for each contact. Set the name of the first contact to DOOR_SHUT and the second to UNLOCK . Set the name of the coil to ALARM and make sure the Set radio box is checked. The rung should look like this:

     DOOR_SHUT     	 UNLOCK            ALARM      

Finally we need to implement the overrides to keep the door locked at specific times and days of the week. In this example we create the COIL after the first == construct, and then insert all the other conditions that can override the door in parallel. The rung containing this logic should look like this:

  [ DayOfWeek== ] 	 UNLOCK     
+-[      7      ]-+-------(R)-------
|                 |
| [ DayOfWeek== ] |
+-[      1      ]-+
|	          |
|    [ Hour>= ]   |
+----[   22   ]---+
|	          |
|    [ Hour< ]    |
+----[   5   ]----+

Finally we need to set the LED values from the final UNLOCK state that is going to be output to the OUT6 pin when the compute phase is finished. There are two rungs to accomplish this, one for the DOOR device:

       UNLOCK          DOOR_GLED
--------[ ]-------+-------( )-------
|    DOOR_RLED    
and one for the REMOTE device:
       UNLOCK         REMOTE_GLED
--------[ ]-------+-------( )-------

After a final save to make sure all our work is store on the controller, we are now ready to try out the design. If you do not have all of the components you can still test the design with just the switches and potentiometer, as the LED states will show the lock status. Click on the Commit button to start the process of committing your ladder logic to your devices. This will take between thirty seconds and a minute to complete at which time you will get a message indicating whether or not the commit was successful and if not what went wrong.

Analyzing the design for potential problems

Since we are using wireless radio to communicate between devices it is possible that interference or collisions might cause some of or signals to be lost. How will this affect our system, and what steps do we need to take to try to proactively avoid any problems that might arise?

If the SW2 signal is lost between "REMOTE" and "DOOR", then the door will not be unlocked. One solution to this might be to simply toggle the switch again if the door does not unlock the first time.

If the lock state changes and the changes is not received by the remote, then the remote could show the wrong door state to the remote user. This is more serious than the first problem, since in conjunction with the first problem the user might have no feed back as to whether or not they needed to try to unlock the door. One possible solution is to periodically send the current value of the UNLOCK signal. Then if the receiver does not get the current value it is likely to receive it on the next transmission. However this may be undesirable if we do not want to be sending data wirelessly all the time. In addition, it does not show off a feature of the TS-PLC unit: if the "REMOTE" powers up in range of the "DOOR" it will automatically query for the value of the UNLOCK signal at startup, and thus (assuming no interference) it should learn the value of the UNLOCK state automatically in that case. (We could also send the red and green LEDs separately, so that if both LEDs were off or on we would know that the power-up sequence failed to find a door to talk to.) Another method of insuring the door state was transmitted would be to send the door state whenever it changed until an acknowledgment was received back from the remote. Obviously this would not work well if later we decided that we wanted multiple receivers. Another approach would be to send a new unlock state several times, for example three times, to reduce the likelihood that all transmissions would be lost.

The examples shipped with the TS-PLC controller show a couple examples of schemes that might be adopted to ensure reliability of critical signals in a wireless environment. The beacon program demonstrates how the presence of another device can be established, and a signal value can be resent repeatedly to ensure its arrival. The ack program demonstrates sending a signal with an acknowledgment. Finally, the relay program demonstrates how a device can repeat a signal in case the intended receiver is out of range of the sender.