Internal workings of process controllers II.

Continued from the previous post

In practice, all these process controllers incorporate a microcontroller.

But microcontrollers are programmed in assembly or in C language, so to create a function block programmable process controller from a C programmable microcontroller, an intermediate firmware must be written.

At first, let’s look at how a function block is defined.

– order number of the function (sequence number)

– the block’s function (adder, multiplication…)

– input connections.

In order to create a usable code for this, the output value of a function block must be stored as well.

The followings will contain code written in C, because usually microcontrollers’ development environment has C compiler.

The functions used will follow the basic functions of a Siemens DR 24 process controller.

There must be an array for holding each function block`s type. Its name is FBD_type_uchar.

The function types are:
0 : undefined function
1 : Absolute value
2 : Addition
3 : Analog memory
4 : Amplification
5 : Logical AND
6 : Analog selector
7 : Binary selector
8 : Comparator
9 : Counter
10: Dead band
11: D flip-flop
12: Differentiator
13: Division
14: Exclusive OR
15: First order analog filter
16: 10 base logarithm
17: Limiter
18: Line equation
19: Natural logartihm
20: Maximum memory
21: Maximum selection
22: Minimum memory
23: Minimum selection
24: Multiplication
25: Logical NAND
26: Logical NOR
27: Logical OR
28: Exponential function
29: Square root
30: Subtraction
31: T flip-flop
32: Timer

33: Write analog constant (write to EEPROM)
34: Write bus communication analog value
35: Write bus communication digital value

For example FBD_type_uchar[3] =2 means that the 4th function block is an adder.

There must be a 2 dimensional array for holding the pointers. These pointers show where each input information is coming from.

These are the minimal informations to define a block (five in a row: function number, function type, input 1 pointer, input 2 pointer and input 3 pointer).

In order to make it work, additional variables are needed.

There must be a separate array for holding the output value. Since the function block either have bit output, or floating point output, there must be two arrays: FBD_output_float and FBD_output_bit_uchar.

fbd

Function block variables explained

One more note: the bit information is stored in a byte (in the Output_bit_uchar array), this is because some block needs a rising or a falling edge input, so not only a single bit, but the edge information is needed.

The byte’s (unsigned char in C language) least significant bit represents the bit information, while the second least significant bit stores the edge information.

0x00 means the actual bit is zero, and there was no falling edge.

0x01 means that the actual bit is logical one, and there was no rising edge.

0x02 means that actual bit is zero, but there was a faliing edge (the bit’s former state was one).

0x03 means that he actual bit is logical one, and there was a rising edge (the bit’s former state was zero).

After all these, the functions’ processing algorithm must be defined and then that’s it!

Of course there are complex functions beside the basic ones in the Siemens DR24 manual, but understanding the basic ones are enough to understand the process controller working principle.

All the previously mentioned functions and variables are included in the source code attached to this post.

Note: the source code is minimalistic: no header files, no variable structures… just a simple main.c file which includes the function block processing algorithm. There’s a lot to optimize for sure, but compactness and optimal coding were not the goal of this post.

The process controllers with all these blocks are very easy to handle and program, but they are still not comparable to a PLC.

The main difference is that the function blocks doesn’t contain the IF decision. Once a block is defined it will be processed. there is no way to “jump over it”. So this approach is only suitable for continuous processes.

That’s why intelligent transmitters and drag and drop audio DSPs are mentioned in the examples.


#include <stdio.h>
#include <math.h>

// Constant definitions, these define the maximum memory usage
#define max_nr_FBD 1000u;              // maximum number of FBDs
#define max_nr_analog_inputs 1000u;    // maximum number of analog inputs
#define max_nr_digital_inputs 1000u;   // maximum number of digital inputs
#define max_nr_analog_outputs 1000u;   // maximum number of analog outputs
#define max_nr_digital_outputs 1000u;  // maximum number of digital outputs
#define max_nr_analog_constants 1000u; // maximum number of analog constants
#define max_nr_bus_analog 1000u;       // maximum number of comm. bus analog values
#define max_nr_bus_digital 1000u;      // maximum number of comm. bus digital values

unsigned int nr_FBD_uint,   // actual number of function blocks
             nr_AI_uint,    // actual number of analog inputs
             nr_DI_uint,    // actual number of digital inputs
             nr_AO_uint,    // actual number of analog outputs
             nr_DO_uint,    // actual number of digital outputs
             nr_AC_uint,    // actual number of analog constants
             nr_SA_uint,    // actual number of bus comm. analog values
             nr_SD_uint;    // actual number of bus comm. digitalvalues
             
unsigned char Function_type_uchar[max_nr_FBD], // array for holding the individual function types
              Digital_input_uchar[max_nr_digital_inputs], // array for holding the digital input pins state
              FBD_output_bit_uchar[max_nr_FBD], // array for holding the function blocks' digital outputs
              Digital_output_uchar[max_nr_digital_outputs], // array for holding the digital output pins state
              Bus_digital_uchar[max_nr_bus_digital]; // array for holding the bus comm. digital values
              
unsigned int Input_pointer_uint[3,max_nr_FBD],        // 2-dimensional array for holding the FBDs input pointer
             AO_pointer_uint[max_nr_analog_outputs],  // array for holding the analog output pointers
             DO_pointer_uint[max_nr_digital_outputs], // array for holding the digital output pointers

float Analog_input_float[max_nr_analog_inputs+1], // array for holding analog input pins' values
      FBD_output_float[max_nr_FBD], // array for holding the FBDs' floating outputs
      Analog_output_float[max_nr_analog_outputs], // array for holding the analog output pins' values
      Analog_constants_float[max_nr_analog_constants], // array for holding the analog constants
      Bus_analog_float[max_nr_bus_analog]; // array for holding the bus comm. analog values
      
unsigned int i;      

void init(void);
void read_inputs(void);
void process_FBDs(void);
void write_outputs(void);
void serve_communication(void);
void self_diagnostics(void);


int main()
{
    init();
    while(1)
    {
        read_inputs();
        process_FBDs();
        write_outputs();
        serve_communication();
        self_diagnostics();
    }
    return 0;
}

/*
function definitions:
0 : not defined
1 : Absolute value
2 : Addition
3 : Analog memory
4 : Amplification
5 : Logical AND
6 : Analog selector
7 : Binary selector
8 : Comparator
9 : Counter
10: Dead band
11: D flip-flop
12: Differentiator
13: Division
14: Exclusive OR
15: First order analog filter
16: 10 base logarithm
17: Limiter
18: Line equation
19: Natural logartihm
20: Maximum memory
21: Maximum selection
22: Minimum memory
23: Minimum selection
24: Multiplication
25: Logical NAND
26: Logical NOR
27: Logical OR
28: Exponential function
29: Square root
30: Subtraction
31: T flip-flop
32: Timer

33: Write analog constant (write to EEPROM)
34: Write bus communication analog value
35: Write bus communication digital value
*/

/*
pointer meanings:

0     -   999 : FBD output,
10000 - 10999 : Analog Input pin,
11000         : last cycle time in sec.
15000 - 15999 : Digital Input pin,
20000 - 20999 : Analog output pin,
25000 - 25999 : Digital output pin,
30000 - 30999 : Analog constants,
33000         : Digital 0,
33001         : Digital 1,
35000 - 35999 : Bus communication analog value,
40000 - 40999 : Bus communication digital value,
*/

void init()
{
    nr_FBD_uint = 100; // actual number of function blocks = 100
    nr_AI_uint = 10;   // actual number of analog inputs = 10
    nr_DI_uint = 20;   // actual number of digital inputs = 20
    nr_AO_uint = 10;   // actual number od analog outputs = 10
    nr_DO_uint = 20;   // actual number of digital outputs = 20
    nr_SA_uint = 100;  // actual number of bus analog values = 100
    nr_SD_uint = 100;  // actual number of bus digital values = 100
    // loading analog constant values into Analog_constants_float[] array from EEPROM
}

void read_inputs()
{
    /*
    Subroutine that reads the analogue, digital and communication bus inputs
    and stores them in the corresponding variables:
    Analog values into Analog_input_float[],
    Digital values into Digital_input_float[]
    */
}

process_FBDs()
{
    float in_1_float, in_2_float, in_3_float;
    unsigned char in_1_dig, in_2_dig, in_3_dig, temp_bit_uchar;

    for (i=0;i<nr_FBD_uint;i++)
    {
        if (FDB_type_uchar[i] != 0) // if the function is not "undefined"
        {
        //  processing inputs from pointers regarding input pointer 1
            if (Input_pointer_uint[0,i] < nr_FBD_uint) // FBD outputs
            {
                in_1_float = FBD_output_float(Input_pointer_uint[0,i]);
                in_1_dig = FBD_output_bit_uchar(Input_pointer_uint[0,i]);
            }
            else if (Input_pointer_uint[0,i] < 11000) // Analog input pin
            {
                in_1_float = Analog_input_float[(Input_pointer_uint[0,i]-10000)];
            }
            else if (Input_pointer_uint[0,i] < 16000) // Digital input pin
            {
                in_1_dig = Digital_input_uchar[(Input_pointer_uint[0,i]-15000)];
            }
            else if (Input_pointer_uint[0,i] < 31000) // Analog constants
            {
                in_1_float = Analog_constants_float[(Input_pointer_uint[0,i]-30000)];
            }
            else if (Input_pointer_uint[0,i] == 33000) // Digital 0
            {
                in_1_dig = 0;
            }
            else if (Input_pointer_uint[0,i] == 33001) // Digital 1
            {
                in_1_dig = 1;
            }
            else if (Input_pointer_uint[0,i] < 36000) // Bus analog value
            {
                in_1_float = Bus_analog_float[(Input_pointer_uint[0,i]-35000)];
            }
            else if (Input_pointer_uint[0,i] < 41000) // Bus digital value
            {
                in_1_dig = Bus_digital_uchar[(Input_pointer_uint[0,i]-40000)];
            }

        //  processing inputs from pointers regarding input pointer 2
            if (Input_pointer_uint[1,i] < nr_FBD_uint)
            {
                in_2_float = FBD_output_float(Input_pointer_uint[1,i]);
                in_2_dig = FBD_output_bit_uchar(Input_pointer_uint[1,i]);
            }
            else if (Input_pointer_uint[1,i] < 11000) // Analog input pin
            {
                in_2_float = Analog_input_float[(Input_pointer_uint[1,i]-10000)];
            }
            else if (Input_pointer_uint[1,i] < 16000) // Digital input pin
            {
                in_2_dig = Digital_input_uchar[(Input_pointer_uint[1,i]-15000)];
            }
            else if (Input_pointer_uint[1,i] < 31000) // Analog constants
            {
                in_2_float = Analog_constants_float[(Input_pointer_uint[1,i]-30000)];
            }
            else if (Input_pointer_uint[1,i] == 33000) // Digital 0
            {
                in_2_dig = 0;
            }
            else if (Input_pointer_uint[1,i] == 33001) // Digital 1
            {
                in_2_dig = 1;
            }
            else if (Input_pointer_uint[1,i] < 36000) // Bus analog value
            {
                in_2_float = Bus_analog_float[(Input_pointer_uint[1,i]-35000)];
            }
            else if (Input_pointer_uint[1,i] < 41000) // Bus digital value
            {
                in_2_dig = Bus_digital_uchar[(Input_pointer_uint[1,i]-40000)];
            }

        //  processing inputs from pointers regarding input pointer 3
            if (Input_pointer_uint[2,i] < nr_FBD_uint)
            {
                in_3_float = FBD_output_float(Input_pointer_uint[2,i]);
                in_3_dig = FBD_output_bit_uchar(Input_pointer_uint[2,i]);
            }
            else if (Input_pointer_uint[2,i] < 11000) // Analog input pin
            {
                in_3_float = Analog_input_float[(Input_pointer_uint[2,i]-10000)];
            }
            else if (Input_pointer_uint[2,i] < 16000) // Digital input pin
            {
                in_3_dig = Digital_input_uchar[(Input_pointer_uint[2,i]-15000)];
            }
            else if (Input_pointer_uint[2,i] < 31000) // Analog constants
            {
                in_3_float = Analog_constants_float[(Input_pointer_uint[2,i]-30000)];
            }
            else if (Input_pointer_uint[2,i] == 33000) // Digital 0
            {
                in_3_dig = 0;
            }
            else if (Input_pointer_uint[2,i] == 33001) // Digital 1
            {
                in_3_dig = 1;
            }
            else if (Input_pointer_uint[2,i] < 36000) // Bus analog value
            {
                in_3_float = Bus_analog_float[(Input_pointer_uint[2,i]-35000)];
            }
            else if (Input_pointer_uint[2,i] < 41000) // Bus digital value
            {
                in_3_dig = Bus_digital_uchar[(Input_pointer_uint[2,i]-40000)];
            }

        // Processing Function blocks            
            switch (FDB_type_uchar[i])
            {
                case 1 : // Absolute value
                   FBD_output_float[i] = abs(in_1_float);
                   break;
                case 2 : // Addition
                   FBD_output_float[i] = in_1_float + in_2_float + in_3_float;
                   break;
                case 3 : // Analog memory
                   in_2_dig &= 0x01;
                   if (in_2_dig == 0)
                   {
                       FBD_output_float[i] = in_1_float;
                   }
                   break;
                case 4 : // 4 : Amplification
                   FBD_output_float[i] = (in_1_float - in_2_float) * in_3_float;
                   break;
                case 5 : // 5 : Logical AND
                   temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                   FBD_output_bit_uchar[i] = in_1_dig && in_2_dig && in_3_dig && 0x01; // processing logical function
                   temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                   if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                   {
                       FBD_output_bit_uchar[i] |= 0x02;
                   }
                   break;
                case 6 : // 6 : Analog selector
                   FBD_output_float[i] = in_1_float;
                   if ((in_3_dig && 0x01) == 1)
                   {
                       FBD_output_float[i] = in_2_float;
                   }
                   break;
                case 7 : // 7 : Binary selector
                   in_3_dig &= 0x01;
                   FBD_output_bit_uchar[i] = in_1_dig;
                   if (in_3_dig == 0x01)
                   {
                       FBD_output_bit_uchar[i] = in_2_dig;
                   }
                   break;
                case 8 : // 8 : Comparator
                    temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                    if (in_1_float >= (in_2_float + in_3_float/2))
                    {
                        FBD_output_bit_uchar[i] = 1;
                    }
                    if (in_1_float < (in_2_float - in_3_float/2))
                    {
                        FBD_output_bit_uchar[i] = 0;
                    }
                    temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                    if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                    {
                        FBD_output_bit_uchar[i] |= 0x02;
                    }
                    break;
                case 9 : // 9 : Counter
                    if ((in_3_dig) == 0x03) // Reset condition
                    {
                        FBD_output_float[i] = 0;
                    }
                    else                         // not in reset condition
                    {
                        if ((in_1_dig && 0x01) == 0) // if counting enabled
                        {
                            if (in_2_dig == 0x03)    // if rising edge on in2
                            {
                                FBD_output_float[i] += 0.001;
                            }
                        }
                    }
                    break;
                case 10 : // 10: Dead band
                    if (in_1_float >= 0) // if the input value is positive
                    {
                        if (in_1_float <= in_2_float) // if the input is in the dead band
                        {
                            FBD_output_float[i] = 0;  // output vlaue is zero
                        }
                        else
                        {
                            FBD_output_float[i] = in_1_float - in_2_float;
                        }
                    }
                    else                // if the input value is negative
                    {
                        in_2_float *= -1;
                        if (in_1_float > in_2_float) // if the input is in the dead band
                        {
                            FBD_output_float[i] = 0; // output value is zero
                        }
                        else
                        {
                            FBD_output_float[i] = in_1_float - in_2_float;
                        }
                    }
                    break;
                case 11 : // 11: D flip-flop
                    in_3_dig &= 0x01;
                    temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                    if (in_3_dig == 1) // if D flip-flop is in reset output is zero
                    {
                        FBD_output_bit_uchar[i] = 0;
                        if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                        {
                            FBD_output_bit_uchar[i] |= 0x02;
                        }
                    }
                    else // if D flip-flop is not in reset
                    {
                        if (in_2_dig == 0x03) // if there was a rising edge on the clock input
                        {
                            FBD_output_bit_uchar[i] = in_1_dig && 0x01;
                            temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                            if ( temp_bit_uchar == 1) // if there was rising or falling edge
                            {
                                FBD_output_bit_uchar[i] |= 0x02;
                            }
                        }
                        else
                        {
                            FBD_output_bit_uchar[i] &= 0x01;
                        }
                    }
                    break;
                case 12 : // 12: Differentiator
                    // little modification was needed in contrast to Siemens DR24 DFF function
                    // in1 is the actual input
                    // in2 is the former input (the input value one cycle before)
                    // in3 is the time constant (it was not changed)
                    FBD_output_float[i] = (in_1_float - in_2_float + FBD_output_float[i])/exp(Analog_input_float[1000]/in_3_float);
                    break;
                case 13 : // 13: Division
                    if (in_3_float > 0) // if in3 is positive
                    {
                        if (in_2_float < in_3_float)
                        {
                            in_2_float = in_3_float;
                        }
                    }
                    if (in_3_float < 0) // if in3 is negative
                    {
                        if (in_2_float > in_3_float)
                        {
                            in_2_float = in_3_float;
                        }
                    }
                    if (in_2_float == 0) // division with zero
                    {
                        FBD_output_float[i] = 0; // output value is zero
                    }
                    else
                    {
                        FBD_output_float[i] = in_1_float / in_2_float;
                    }
                    break;
                case 14 : // 14: Exclusive OR
                   temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                   FBD_output_bit_uchar[i] = in_1_dig && 0x01;
                   FBD_output_bit_uchar[i] ^= (in_2_dig && 0x01);
                   temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                   if ( temp_bit_uchar == 1) // if there was rising or falling edge
                   {
                       FBD_output_bit_uchar[i] |= 0x02;
                   }
                   break;
                case 15 : // 15: First order analog filter
                    in_1_float *= in_2_float;
                    in_2_float = FBD_output_float[i];
                    FBD_output_float[i] = in_1_float - (in_1_float - in_2_float)/exp(Analog_input_float[1000]/in_3_float);
                    break;
                case 16 : // 16: 10 base logarithm
                    if (in_1_float > 0 // if logarithm function is valid
                    {
                        FBD_output_float[i] = log10(in_1_float);
                    }
                    else                // if logarithm function is not vlaid
                    {
                        FBD_output_float[i] = -10E19;
                    }
                    break;
                case 17 : // 17: Limiter
                    if (in_2_float >= in_3_float) // if in2 is greater than in3 then output is in3
                    {
                        FBD_output_float[i] = in_3_float;
                    }
                    else // valid limits (in2 < in3)
                    {
                        FBD_output_float[i] = in_1_float;
                        if (in_1_float > in_3_float)
                        {
                            FBD_output_float[i] = in_3_float;
                        }
                        if (in_1_float < in_2_float)
                        {
                            FBD_output_float[i] = in_2_float;
                        }
                    }
                    break;
                case 18 : // 18: Line equation
                    FBD_output_float[i] = in_1_float * in_2_float + in_3_float;
                    break;
                case 19 : // 19: Natural logartihm
                    if (in_1_float > 0 // if logarithm function is valid
                    {
                        FBD_output_float[i] = log(in_1_float);
                    }
                    else                // if logarithm function is not vlaid
                    {
                        FBD_output_float[i] = -10E19;
                    }
                    break;
                case 20 : // 20: Maximum memory
                    if ((in_2_dig && 0x01) == 0x01) // logical one on reset input
                    {
                        FBD_output_float[i] = in_1_float;
                    }
                    else // not in reset
                    {
                        if (in_1_float > FBD_output_float[i])
                        {
                            FBD_output_float[i] = in_1_float;
                        }
                    }
                    break;
                case 21 : // 21: Maximum selection
                    if (in_1_float > in_2_float)
                    {
                        if (in_1_float > in_3_float)
                        {
                            FBD_output_float[i] = in_1_float;
                        }
                        else
                        {
                            FBD_output_float[i] = in_3_float;
                        }
                    }
                    else // in2 >= in1
                    {
                        if (in_2_float > in_3_float)
                        {
                            FBD_output_float[i] = in_2_float;
                        }
                        else
                        {
                            FBD_output_float[i] = in_3_float;
                        }
                    }
                    break;
                case 22 : // 22: Minimum memory
                    if ((in_2_dig && 0x01) == 0x01) // logical one on reset input
                    {
                        FBD_output_float[i] = in_1_float;
                    }
                    else // not in reset
                    {
                        if (in_1_float < FBD_output_float[i])
                        {
                            FBD_output_float[i] = in_1_float;
                        }
                    }
                    break;
                case 23 : // 23: Minimum selection
                    if (in_1_float < in_2_float)
                    {
                        if (in_1_float < in_3_float)
                        {
                            FBD_output_float[i] = in_1_float;
                        }
                        else
                        {
                            FBD_output_float[i] = in_3_float;
                        }
                    }
                    else // in2 >= in1
                    {
                        if (in_2_float < in_3_float)
                        {
                            FBD_output_float[i] = in_2_float;
                        }
                        else
                        {
                            FBD_output_float[i] = in_3_float;
                        }
                    }
                    break;
                case 24 : // 24: Multiplication
                    FBD_output_float[i] = in_1_float * in_2_float * in_3_float;
                    break;
                case 25 : // 25: Logical NAND
                    temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                    FBD_output_bit_uchar[i] = (in_1_dig && in_2_dig && in_3_dig && 0x01)^0x01;
                    temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                    if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                    {
                        FBD_output_bit_uchar[i] |= 0x02;
                    }                
                    break;
                case 26 : // 26: Logical NOR
                    temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                    FBD_output_bit_uchar[i] = (in_1_dig || in_2_dig || in_3_dig && 0x01)^0x01;
                    temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                    if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                    {
                        FBD_output_bit_uchar[i] |= 0x02;
                    }                
                    break;
                case 27 : // 27: Logical OR
                    temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                    FBD_output_bit_uchar[i] = in_1_dig || in_2_dig || in_3_dig && 0x01;
                    temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                    if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                    {
                        FBD_output_bit_uchar[i] |= 0x02;
                    }                
                    break;
                case 28 : // 28: Exponential function
                    FBD_output_float[i] = in_1_float * pow(in_2_float, in_3_foat);
                    break;
                case 29 : // 29: Square root
                    if (in_2_float < 0) // if the limit is negative
                    {
                        in_2_float = 0;
                    }
                    if (in_1_float < in_2_float)
                    {
                        in_1_float = in_2_float;
                    }
                    FBD_output_float[i] = sqrt(in_1_float);
                    break;
                case 30 : // 30: Subtraction
                    FBD_output_float[i] = in_1_float - in_2_float - in_3_float;
                    break;
                case 31 : // 31: T flip-flop
                    temp_bit_uchar = in_3_dig && 0x01;
                    if (temp_bit_uchar == 0x01) // reset the flip-flop
                    {
                        temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01;
                        FBD_output_bit_uchar[i] = 0;
                        temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                        if ( temp_bit_uchar == 1) // if there was rising or falling edge
                        {
                            FBD_output_bit_uchar[i] |= 0x02;
                        }
                    }
                    else // if the flip-flop in not in reset
                    {
                        FBD_output_bit_uchar[i] &= 0x01;
                        if ((in_1_dig == 0x03) && (in_2_dig == 0x01))
                        {
                            FBD_output_bit_uchar[i] ^= 0x01; // negation the last bit
                            FBD_output_bit_uchar[i] |= 0x02; // output will be an edge
                        }
                        if ((in_1_dig == 0x01) && (in_2_dig == 0x03))
                        {
                            FBD_output_bit_uchar[i] ^= 0x01; // negation the last bit
                            FBD_output_bit_uchar[i] |= 0x02; // output will be an edge
                        }
                    }
                    break;
                case 32 : // 32: Timer
                    temp_bit_uchar = in_2_dig && 0x01;
                    if (temp_bit_uchar == 0x01) // timer is in reset
                    {
                        temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01;
                        FBD_output_bit_uchar[i] = 0;
                        temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                        if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                        {
                            FBD_output_bit_uchar[i] |= 0x02;
                        }
                    }
                    else // timer not in reset
                    {
                        temp_bit_uchar = FBD_output_bit_uchar[i] && 0x01; // storing the former value of FBD output
                        FBD_output_bit_uchar[i] = 0;
                        if (in_3_float < 1) // if preset time is too little
                        {
                                in_3_float = 1;
                        }
                        if (in_1_dig == 0x03) // rising edge on in1
                        {
                            FBD_output_float[i] = in_3_float; // setting the output elapsed time to in3
                        }
                        if (FBD_output_float[i] > 0) // if the time has not elapsed
                        {
                            FBD_output_float[i] -= Analog_input_float[1000]; // output elapsed time decreasing with last cycle time
                            FBD_output_bit_uchar[i] = 1;
                        }
                        temp_bit_uchar ^= FBD_output_bit_uchar[i]; // XORing temp_bit_uchar
                        if ( temp_bit_uchar == 1) // if there was rising or falling edge regarding the former output state
                        {
                            FBD_output_bit_uchar[i] |= 0x02;
                        }
                    }
                    break;
                    
                // added extra functions
                case 33 : // 33: Write analog constant (write to EEPROM)
                    if ((in_2_float >= 0) && (in_2_float < 1000)) // if in2 points to a FBD output
                    {
                        if (in_3_dig == 0x03) // value stored if in3 has a rising edge
                        {
                            Analog_constants_float[(int)in_2_float] = in_1_float;
                            FBD_output_float[i] = in_1_float;
                            // value must be stored to EEPROM as well
                        }
                    }
                    break;
                case 34 : // 34: Write bus communication analog value
                    if ((in_2_float >= 0) && (in_2_float < 1000)) // if in2 points to a FBD output
                    {
                        if (in_3_dig == 0x03) // value stored if in3 has a rising edge
                        {
                            Bus_analog_float[(int)in_2_float] = in_1_float;
                            FBD_output_float[i] = in_1_float;
                        }
                    }
                    break;
                case 35 : // 35: Write bus communication digital value
                    if ((in_2_float >= 0) && (in_2_float < 1000)) // if in2 points to a FBD output
                    {
                        if (in_3_dig == 0x03) // value stored if in3 has a rising edge
                        {
                            Bus_digital_uchar[(int)in_2_float] = (in_1_dig && 0x01);
                            FBD_output_bit_uchar[i] = (in_1_dig && 0x01);
                        }
                    }
                    break;

                default : 
                    // function type out of range, report an error to the system
                    break;
            }
        }
    }    
}

write_outputs()
{
    // writing analog output array
    for (i=0;i<nr_AO_uint;i++)
    {
        if (AO_pointer_uint[i] < 1000)
        {
            Analog_output_float[i] = FBD_output_float[i];
        }
        else if (AO_pointer_uint[i] < 11001)
        {
            Analog_output_float[i] = Analog_input_float[(AO_pointer_uint[i]-10000)];
        }
        else if (AO_pointer_uint[i] < 31000)
        {
            Analog_output_float[i] = Analog_constants_float[(AO_pointer_uint[i]-30000)];
        }
    }
    
    // writing digital output array
    for (i=0;i<nr_DO_uint;i++)
    {
        if (DO_pointer_uint[i] < 1000)
        {
            Digital_output_uchar[i] = (FBD_output_bit_uchar[i] && 0x01);
        }
        else if (DO_pointer_uint[i] < 16000)
        {
            Digital_output_uchar[i] = Digital_input_uchar[(DO_pointer_uint[i]-15000)];
        }
        else if (DO_pointer_uint[i] < 33002)
        {
            Digital_output_uchar[i] = (char)(DO_pointer_uint[i]-33000);
        }
    }
}

serve_communication()
{
    /*
    Subroutine that reads/writes values from/to the bus communication peripheral.
    */
}

self_diagnostics()
{
    /*
    Subroutine that checks the whole system's consistency (calculate EEPROM, RAM checksum,
    verifying peripherals...)
    */
}
Advertisements

3 thoughts on “Internal workings of process controllers II.”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s