Signal Forming Function Block Design with State Diagrams

In this tutorial you will learn

how to use conditions to trigger state transitions in your state machine

how to benefit from adding attributes to a stateful class

using state machines to create library of reusable function blocks for control signal forming

In another example you can learn how to create a PLCOpen safety function block using the same concept.

What are conditional events

The code generator supports two basic modes of operation which should not be mixed. Either it processes events. Only if an event is present a transition is taken. Events are eventually send to the state machine using an event queue. Alternatively transitions are triggered by boolean conditions. If a boolean condition is true a state change happens. The latter one is useful if binary signals should be processed like we will see in our example. In this case the state machine runs without receiving a dedicated event but depending on state boolean state is used to trigger state transitions.

The Problem

Image an embedded system - such as an industrial control device - which has several binary inputs. Often the behaviour of such a device is influenced by the state of these inputs. E.g. an actor should be switched on, a lamp should be activated etc. But often not the raw input signal should be used but a preprocessed signal such as:

Trigger an activity on the rising or falling edge of an input signal (ftrig, rtrig). These bocks are useful to create an event from a boolean signal.

Delay the input signal for some time (so called on-delay)

Wait until an input signal was switched off again (so called off-delay)

Combination of the two above (on/off delay)

Offering a pause input to pause the time condition of the above signals

Offer an option to reset a started timing

Shaping an input signal - i.e. creating a pulse of defined length independent from the length of the input signal

Debounce inputs

There exist many more such functions. You might have come across them in your own practise.

The Solution

It would be very beneficial to have a library of such functions that can be easily integrated into a system design. All the above ones require some state so it makes sense of course to model them as state machines. The design presented here is based on Enterprise Architect and uses the option to model additional attributes in the class. Such attribute are added to the instance data. It can be used for internal variables but also as interface to the outside. We will use both in the examples here. Lets start with the ftrig and rtrig functions first. They do not depend on time and are therefor a bit simpler to model.

Before looking into the state machines take a look in the class diagram first.

Class diagram of the function block library

Each function is modelled as class. The classes have more or less additional attributes. All have binary signals such as q (output) and set. Others have also the additional binary signals pause and reset or variables defining the delay times. Then also internal data is modelled e.g. to store the elapsed time.

To model attributes it is recommend to define your own data types using the 'primate data type' feature of UML. This allows to ensure the use of a consistent set of data types with the rest of your code not modelled in UML. The following figure shows the model tree with the classes and data type definitions inside a common package. Model tree with classes and data type definitions

RTRIG and FTRIG Function

The following two state diagrams show the models for the falling edge (ftrig) and the rising edge (rtrig) function. There is no time information needed. Only the status of the previous input signal. Conditional triggers are marked with a hash # as first character. rising edge state machine falling edge state machine

Pulse Function

The single pulse function is shaping the length of an input signal to a defined pulse length at the output. It requires a notion of time. The implementation just uses the system tick to get time information and calculating the elapsed time with each call of the state machine.

Pulse former state machine

On/Off Delay with Pause and Reset Inputs

This function block is the most complex one. It requires several internal variables to store temporary information and two independent time settings. The reset and pause inputs make the function even more flexible.

On/off delay state machine

Generating Code

To generate code from the state machine model the following command lines were used (the class path -cp points to the location of the codegen.jar file):

java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:on_off" -o ton_toff signalprocessing.xmi java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:ftrig" -o ftrig signalprocessing.xmi java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:rtrig" -o rtrig signalprocessing.xmi java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:single_pulse" -o single_pulse signalprocessing.xmi clang -l ncurses ton_toff.c main_on_off.c -o ton_toff clang -l ncurses main_rtrig.c rtrig.c -o rtrig clang -l ncurses main_ftrig.c ftrig.c -o ftrig clang -l ncurses main_single_pulse.c single_pulse.c -o single_pulse

The only two additional functions that must be provided are the ones delivering the elapsed time information.

uint32_t getSystemMilli(){ struct timeval now; gettimeofday(&now, NULL); return now.tv_usec/1000 + now.tv_sec*1000; } uint32_t getDiffMilli(uint32_t old_milli){ uint32_t milli = getSystemMilli(); uint32_t diff = milli - old_milli; //printf("Milli=%d, old_milli=%d Diff=%d", milli, old_milli, diff); return diff; }

That's all. All the rest is generated!

Testing the Implementation

To test the implementations test patters were generated with which the state machines were called. The inputs and outputs of relevant signals were displayed via the curses library over time. Some examples:

ton with pause tond=500, toffd=0 Set:___***************_______________ Reset:_________________________________ Pause:_____****________________________ Q:____________******_______________ ton/toff tond=300, toffd=800 Set:__*******___________***__________ Reset:_____________________*___________ Pause:_________________________________ Q:_____************________________ rtrig testcase 2 Set:___****__*___ Q:___*_____*___ ftrig testcase 1 Set:___****_*__*_ Q:_______*_*__* single pulse false at begin Set:___*************______*__________ Q:___***________________***________ Debounce button test Input__*__*_**__****************_*_**_*_*___*____*__________ Out _____________*************************_________________ Cnt 0011120120012345678999999997867867564201111120000000000

Final Thoughts

State machines with conditional transitions are a powerful way to model signal forming functions. The shown approach makes reuse more easily possible within the same or further projects. In addition it has the general benefit that the model is the documentation and both is always 100% in sync with the implementation. Alone this benefit should motivate you to not write your next state based design by hand but use a modelling tool and generate the code.

If you are interested in the complete code just send me a mail. The model files are available here:

EA: Enterprise Architect Model file (created with version 16)

UModel: UModel Model file

Built in Editor: Model files for the built-in state diagram editor

Looking forward to receive your thoughts and ideas for other useful blocks.

~~DISCUSSION:closed|Leave your comments~~