Table of Contents

Equipment - Analog Inputs and Outputs

Zeugwerk Framework provides a high variety of digital and analogue inputs and outputs. These objects can of course be used with Zeugwerk Framework template but also without this template in legacy applications. Here is an overview of all IOs.

  • Digital
    • DigitalInput
    • DigitalOutput
    • DebouncedInput
    • DigitalArray
    • ImpulseOutput
    • PulsedOutput
    • Light
  • Analog
    • AnalogInput
    • AnalogOutput

Some of them can be used without calling them every plc cycle like DigitalInput or AnalogOutput, some of them have cyclic behavior like DebounceInput or PulsedOutput.

Here we will make some small examples on how to initialize and use some of those objects in real day applications. For more details on each feature please refer to the API-documentation here.

All of the following examples start with a prepared solution for testing in a usermode runtime environment and with our logging object to observe whats going on. See how to use the Usermode Runtime in TwinCAT

AnalogInput

Analog inputs are a little more complex because of the high variety of datatypes which are available for all those different fieldbus terminals. In Zeugwerk Framework the following datatypes are supported for now:

  • 2Byte -> some terminals offer a 2Byte representation for a 16Bit value
  • Byte
  • Uint
  • Usint
  • Int
  • Word
  • Dint
  • Dword
  • Udint
  • Real

This topic gets even more complex when using a fieldbus terminal with a sampling resolution of 12Bit. Here we use a Word or Int representation and do a proper scaling.

Analog inputs require a proper initialization, which is done in a similar way like the one of a digital input, but with more options. Lets make an example: Lets assume we have a 12Bit terminal EL3061 and we want to read a 0..10V water level sensor signal whereas 0 is 0mm water level and 10v is maximum with 320mm.

PROGRAM MAIN
VAR
  DateTime : ZAux.DateTimeUM;
  Logger : ZAux.LoggerFile7FFUM(datetime:=DateTime, filePath:='C:\temp\logfile.log', target:='');
  Step : ZCore.Step(0, 100);
  Ain : ZEquipment.AnalogInputWord; 
  StringBuilder : ZAux.StringBuilder;
END_VAR
------------------------------
DateTime.Cyclic();
Logger.Cyclic();

CASE Step.Index OF
  0:
    IF Logger.Operational
    THEN
      Logger.Info('Appliation started');
      Step.SetNext(10);
    END_IF

  10:
    Ain.SetConversionParameters(terminalMin:=0, terminalMax:=10, elecMin:=0, elecMax:=10, 
                                physMin:=0, physMax:=320, physicalUnit:='mm');
    Ain.SetDigitalThreshold(200);
    Ain.SetLogger(Logger);
    Ain.SetName('Water Level');
    Ain.SetSimulation(TRUE);
    Ain.SetTerminalResolution(12);
    Ain.SetTriggerLogic(DigitalLogic.Normal);
    Step.SetNext(20);
    
  20:
    IF Ain.Read() > 100 THEN
      Logger.Info('Water Level above 100mm');
      Step.SetNext(30);      
    END_IF

  30: 
    IF Ain.RisingTrigger() THEN
      Logger.Warning(StringBuilder.Append('Water Level now above 200mm (').
                                   AppendParamLreal('WaterLevel', Ain.Read(), 2, 'mm').
                                   Append(')').ToString());
      Step.SetNext(40);
    END_IF

  40:  
    ;
    
END_CASE

The first steps are done as in all other examples above, but now we have to initialize an analog input. Here we first set the terminal measurement type (e.g. 0..10V, 4..20mA), then we set the electrical value of the sensor which is in our case 0..10V. After that we have to set the physical value which we want to use in our application, here in this example 0..320mm and last but not least the unit is in millimeters (mm).

We also set the simulation to TRUE in order to be able to run this program in the Usermode Runtime without access to real hardware.

The analog input and output objects always work with LREAL values on the application side so when we call read we get the physical value as an LREAL value. In step 20 we wait until the input reaches a level above 100mm, so lets set this in online mode of TwinCAT.

When you look at the init-code of the analog input we set a digital threshold which is a method to evaluate the analog input in a way that you get a boolean TRUE or FALSE if a certain water level is reached.

If you now manually override the simulated analog input with a value greater than 200, the logger should now show another log message.

If you do have a terminal which directly sends you the physical value needed but only with wrong decimal point, there is another method of initializing the analog input.

For example: Assume we have a Beckhoff terminal EL3201 which is a 1-channel analog input terminal for Pt100 sensors. This terminal delivers degree celsius right away on the fieldbus but in 0.1°C.

Here we have to use a different method to initialize which is only a scaling of the input value to the output value for the application like so:

PROGRAM MAIN
VAR
  DateTime : ZAux.DateTimeUM;
  Logger : ZAux.LoggerFile7FFUM(datetime:=DateTime, filePath:='C:\temp\logfile.log', target:='');
  Step : ZCore.Step(0, 100);
  Ain : ZEquipment.AnalogInputWord; 
  StringBuilder : ZAux.StringBuilder;
END_VAR
--------------------------------
DateTime.Cyclic();
Logger.Cyclic();

CASE Step.Index OF
  0:
    IF Logger.Operational
    THEN
      Logger.Info('Appliation started');
      Step.SetNext(10);
    END_IF

  10:
    Ain.SetConversionScaling(scale:=10, 'Celsius');
    Ain.SetDigitalThreshold(40);
    Ain.SetLogger(Logger);
    Ain.SetName('Temperature');
    Ain.SetSimulation(TRUE);
    Ain.SetTerminalResolution(12);
    Ain.SetTriggerLogic(DigitalLogic.Normal);
    Step.SetNext(20);
    
  20:
    IF Ain.Read() > 30 THEN
      Logger.Info('Temperature above 30 degree celsius');
      Step.SetNext(30);      
    END_IF

  30: 
    IF Ain.RisingTrigger() THEN
      Logger.Warning(StringBuilder.Append('Attention, environment gets too hot > 40°C (').
                                   AppendParamLreal('Temperature', Ain.Read(), 1, '°C').
                                   Append(')').ToString());
      Step.SetNext(40);
    END_IF

  40:  
    ;
    
END_CASE

The second variant of initializing this analog input is by setting a conversion scaling. Here we get the temperature in 0.1 degrees Celsius but want to use Celsius as physical value. Therefore we have to set the scale to 10.

AnalogOutput

The analog outputs are working exactly the same way as an analog input and there are also the same types available. In the following example we want to command a frequency converter with an analog input for commanding velocity from 0..10V is a velocity from 0..1470rpm.

PROGRAM MAIN
VAR
  DateTime : ZAux.DateTimeUM;
  Logger : ZAux.LoggerFile7FFUM(datetime:=DateTime, filePath:='C:\temp\logfile.log', target:='');
  Step : ZCore.Step(0, 100);
  Aout : ZEquipment.AnalogOutputWord; 
  StringBuilder : ZAux.StringBuilder;
END_VAR
--------------------------------------
DateTime.Cyclic();
Logger.Cyclic();

CASE Step.Index OF
  0:
    IF Logger.Operational
    THEN
      Logger.Info('Appliation started');
      Step.SetNext(10);
    END_IF

  10:
    Aout.SetConversionParameters(terminalMin:=0, terminalMax:=10, elecMin:=0, elecMax:=10, 
                                 physMin:=0, physMax:=1470, physicalUnit:='rpm');
    Aout.SetDigitalThreshold(1000);
    Aout.SetLogger(Logger);
    Aout.SetName('FC-Velocity');
    Aout.SetSimulation(TRUE);
    Aout.SetTerminalResolution(12);
    Aout.SetTriggerLogic(DigitalLogic.Normal);
    Step.SetNext(20);
    
  20:
    Aout.Write(500);
    Logger.Info('Frequency Converter moving 500rpm');
    Step.SetNext(30);      

  30:
    Aout.Write(1100);
    Step.SetNext(40);  

  40:  
    ;
    
END_CASE

IF Aout.RisingTrigger() THEN
  Logger.Warning(StringBuilder.Append('Frequency Converter moving above 1000rpm (').
                               AppendParamLreal('Velocity', Aout.Read(), 0, 'rpm').
                               Append(')').ToString());
END_IF