Example: machine with Microsoft Visual C#

Microsoft Visual Studio 2005 is a development environment for creating C# projects. The machine example is used for familiarisation with the integration of the TwinCAT ADS .NET component with the programming language C#.

Required software:

- Microsoft .NET Framework Version 2.0, for more information click here
- Microsoft Visual Studio 2005
- TwinCAT 2.10

Before you can start the C# program, TwinCAT and the PLC program must be active. If Microsoft Visual Studio 2005 is not installed on your computer, please install Microsoft .NET Framework Version 2.0. This sets up the required DLLs on your system.

First steps...

Step by step familiarisation with the development of a C# program and integration of the TwinCAT ADS .NET component based on an example.

1. Create new project:

Start Visual Studio 2005. Create a new project by clicking File -> New -> Project in the menu. A new project based on different templates can be created via the dialog box 'New Project'. Under 'Project Types' select the programming language Visual C#, and under the templates select 'Windows Application'. Enter a new name for your project, in this case please enter 'Machine'. Then select the directory path for your project under 'Location'.

Example: machine with Microsoft Visual C# 1:

2. Creating a user interface

First create an interface in the design mode of the form 'frmMachine' with the Toolbox. The settings for the different controls (such as 10 labels, 2 radio buttons, 1 progress bar, 1 picture box, group box...) can be viewed and set in the Visual Studio Properties window.

// Group fields (group box)
grpDevice.Text = "";
grpCount.Text = "";
grpSpeed.Text = "Speed";

// Labels
lblMachine.Text = "Machine";
lblDeviceDown.Text = "Device Down";
lblDeviceUP.Text = "Device Up";
lblCount.Text = "0";
lblCountLabel.Text = "Count:";
lblSteps.Text = "Steps:";
lbl100Procent.Text = "100%";
lbl0Procent.Text = "0%";

// These are the DeviceDown and DeviceUp arrows with a different font and size (label) 
DeviceDown.Text = "ê";
DeviceDown.Font = new System.Drawing.Font("Wingdings", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(2)));
DeviceUp.Text = "é";
DeviceUp.Font = new System.Drawing.Font("Wingdings", 20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(2)));

// Progress bar
prgSteps.Name = "prgSteps";

// Option fields (radio button)
optSpeedSlow.Text = "slow";
optSpeedFast.Text = "fast";
Example: machine with Microsoft Visual C# 2:

In the upper left you see the two outputs that are also output to the Bus Terminals. The bottom left shows the variable for counting the workpieces. The cycle speed of the motor can be changed via the 'Speed' field on the right. The 'Steps' display shows the number of cycles that are output on output 1.

3. Adding a reference

First a reference called TwinCAT.Ads.dll must be added. The TwinCAT ADS .NET component is integrated via the menu -> Project -> Add Reference. To check whether the reference was actually integrated, you can call up the Solution Explorer (CTRL + W + S).

Example: machine with Microsoft Visual C# 3:

4. Edit source text

Once the interface has been created and the TwinCAT ADS component has been integrated, you can change to the C# source text. The required namespaces 'System.IO' and 'TwinCAT.Ads' are added in the top row of the source text.

using System.IO;
using TwinCAT.Ads;

This is followed by declarations within the frmMachine class.

privateTcAdsClient tcClient;
privateAdsStream dataStream;
privateBinaryReader binReader;
private int hEngine;
private int hDeviceUp;
private int hDeviceDown;
private int hSteps;
private int hCount;
private int hSwitchNotify;
private int hSwitchWrite;

The method 'frmMachine_Load' is started when the Windows application is called. This method is linked by linking the 'Load' event of the form with the method in the Properties window. It is used to generate instances of different classes and create a link with runtime system 1 of the TwinCAT.Ads component via port 801.

//-----------------------------------------------------//This is called first when the program is started//-----------------------------------------------------private void frmMachine_Load(object sender, EventArgs e)
{
    try
    {
     // Create a new instance of the AdsStream class
     dataStream = newAdsStream(7);

     // Create a new instance of the BinaryReader class
     binReader = newBinaryReader(dataStream);

     // Create a new instance of the TcAdsClient class
     tcClient = newTcAdsClient();
     
     // Linking with local PLC - runtime 1 - port 801 
     tcClient.Connect(801);
    }
    catch
    {
     MessageBox.Show("Fehler beim Laden");
    }    

    //...

Linking PLC variables:

In the frmMachine_Load event of the form, a connection to each variable in the PLC is created via the TcAdsClient.AddDeviceNotification()method. The handle for this connection is stored in an array. The TransMode parameter specifies the data exchange type. In this case AdsTransMode.OnChange is used to specify that the PLC variable is only transferred if the value in the PLC has changed (see AdsTransMode). The parameter cycleTime determines how often the PLC should check whether the corresponding variable has changed. The variables are then linked with a method 'tcClient_OnNotification' (that still has to be written), which is called when a variable changes.

try
    {
    // Initialising of PLC variable monitoring
    hEngine = tcClient.AddDeviceNotification(".engine", dataStream, 0, 1, AdsTransMode.OnChange, 10, 0, null);
    hDeviceUp = tcClient.AddDeviceNotification(".deviceUp", dataStream, 1, 1, AdsTransMode.OnChange, 10, 0, null);
    hDeviceDown = tcClient.AddDeviceNotification(".deviceDown", dataStream, 2, 1, AdsTransMode.OnChange, 10, 0, null);
    hSteps = tcClient.AddDeviceNotification(".steps", dataStream, 3, 1, AdsTransMode.OnChange, 10, 0, null);
    hCount = tcClient.AddDeviceNotification(".count", dataStream, 4, 2, AdsTransMode.OnChange, 10, 0, null);
    hSwitchNotify = tcClient.AddDeviceNotification(".switch", dataStream, 6, 1,  AdsTransMode.OnChange, 10, 0, null);

    // Retrieving of the "switch" handle. This is required for writing the value
    hSwitchWrite = tcClient.CreateVariableHandle(".switch");

    // Creating an event for changes in the PLC variable values 
    tcClient.AdsNotification += newAdsNotificationEventHandler(tcClient_OnNotification);
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
}

Definition:

The method 'AddDeviceNotification()' was used for linking the variables.

public int AddDeviceNotification(string variableName, AdsStream dataStream, int  offset, int length, AdsTransMode transMode, int cycleTime, int maxDelay, object userData);

The method 'CreateVariableHandle' was used for linking the variable 'hSwitchWrite'.

int TcAdsClient.CreateVariableHandle(string variableName);

Write method:

A method that does not exist yet was referred to above. This method ('tcClient_OnNotification') is written next. The method is called if one of the PLC variables has changed.

//------------------------------------------------//This is called if one of the PLC variables changes//------------------------------------------------private void tcClient_OnNotification(object sender, AdsNotificationEventArgs e)
{
    try
    {
    // Setting the position of e.DataStream to the position of the current required value
    e.DataStream.Position = e.Offset;

    // Determining which variable has changedif(e.NotificationHandle == hDeviceUp)
    {
        //Adapting the colours of the diagrams to match the variablesif (binReader.ReadBoolean() == true)
        {
        DeviceUp_LED.ForeColor = Color.Red;
        }
        else
        {
        DeviceUp_LED.ForeColor = Color.White;
        }
    }
    else if(e.NotificationHandle == hDeviceDown)
    {
        if (binReader.ReadBoolean() == true)
        {
        DeviceDown_LED.ForeColor = Color.Red;
        }
        else
        {
        DeviceDown_LED.ForeColor = Color.White;
        }
    }
    else if(e.NotificationHandle == hSteps)
    {
        // Setting the progress bar to the current step
        prgSteps.Value = binReader.ReadByte();
    }
    else if(e.NotificationHandle == hCount)
    {
        // Displaying the "count" value
        lblCount.Text = binReader.ReadUInt16().ToString();
    }
    else if(e.NotificationHandle == hSwitchNotify)
    {
        // Selecting the correct radio buttonif (binReader.ReadBoolean() == true)
        {
        optSpeedFast.Checked = true;
        }
        else
        {
        optSpeedSlow.Checked = true;
        }
    }
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
}

Lastly, we require two methods for setting the machine to fast or slow. They are used to switch a virtual switch by writing a value to the PLC variable 'switch'.

//------------------------------------------------------//This is called if the 'slow' field is selected//------------------------------------------------------private void optSpeedFast_Click(object sender, EventArgs e)
{
    try
    {
    tcClient.WriteAny(hSwitchWrite, true);
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
}

//------------------------------------------------------//This is called if the 'fast' field is selected//------------------------------------------------------private void optSpeedSlow_Click(object sender, EventArgs e)
{
    try
    {
    tcClient.WriteAny(hSwitchWrite, false);
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
}

Last but not least we need to ensure that the methods 'optSpeedFast_Click' and 'optSpeedSlow_Click' are called for the right event. To this end switch to Design view, select the radio button 'optSpeedFast', click on 'Click' under Events in the Properties window and select the method 'optSpeedFast_Click'. Proceed accordingly for the radio button 'optSpeedSlow' and the method 'optSpeedSlow_Click'.

Delete notifications and handles:

In the frmMachine_FormClosing event of the form the links are activated again with the method DeleteDeviceNotification().

//------------------------------------------//is called when the program is terminated//------------------------------------------private void frmMachine_FormClosing(object sender, FormClosingEventArgs e)
{
    try
    {
    // Delete notifications and handles
    tcClient.DeleteDeviceNotification(hEngine);
    tcClient.DeleteDeviceNotification(hDeviceUp);
    tcClient.DeleteDeviceNotification(hDeviceDown);
    tcClient.DeleteDeviceNotification(hSteps);
    tcClient.DeleteDeviceNotification(hCount);
    tcClient.DeleteDeviceNotification(hSwitchNotify);

    tcClient.DeleteVariableHandle(hSwitchWrite);
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
    tcClient.Dispose();
}

The PLC programMachine_Final.proshould start on runtime system 1, and the created C# programMachine.execan be tested.

Download C# program example:

CSharp example