Microcontrolling Projects Using UML Language (MIC015E)

The development of a microcontroller design can be done in many ways. Each programmer or group of programmers will likely use the form which best fits their way of working. In recent years, the UML or Unified Modeling Language has become popular as a programming method for microcontroller-based projects. Some compilers such as the IAR, supporting diagrams and state machines, are one of the diagrams used in the UML language.

To get an idea of what a microcontroller design can be, without using Unified Modeling Language (UML) or a similar method, it can be compared to someone who wants to build a building and does not use an architect to shape the project.

We can also compare it to who wants to make a mechanical part and does not make a plan, drawing or diagram of this part. It can be said that the UML language is like the architecture or plan of a microcontroller project.

Initially the language was created to be able to develop software programs and projects for computers, but nowadays it is being used to develop programs or projects with microcontrollers. As the UML language was developed for object-oriented languages (classes) such as C++/C # and most of the microcontroller projects are written in C language, it is necessary to make some adaptations to support UML in C language.

The UML language is formed by a series of diagram for the purpose of describing, organizing, formatting, classifying, etc. the project to be developed. In the case of projects with microcontrollers, the most used diagrams are:

 

Use Case Diagrams.

Class Diagrams.

State Diagrams.

 

In this article we will explain how to use these diagrams in the development of a project or idea which uses microcontrollers.

 

USE CASE DIAGRAM

The use case diagrams indicate the uses which the project can have, that is, what the project is for and who will use them. For this reason, this diagram has two important components.

 

1 - Users.
1 - Users.

 

 

2 - The Use Cases.
2 - The Use Cases.

 

 

Users are represented in the diagram by a symbol similar to the one given in Figure 1. The Use Cases are represented in the diagram by a symbol similar to the one in Figure 2. Next to the symbols Users it is placed a text describing their role and within the symbols Use Cases it is placed a text describing its function.

 

 

3 - Case Diagram
3 - Case Diagram

 

Figure 3 shows an example Case of Uses diagram for a design of a basic car alarm. In this diagram, the line with arrow indicates that the User (actor) makes use of the project.

 

CLASS DIAGRAM

The Class Diagrams describe the functions and data (variables) of the project. This diagram is in charge of classifying the functions (routines) in modules or blocks for a better organization of the software. These modules or blocks are called Classes.

 

Each Class in the diagram is formed by 3 main parts:

1- Class Name.

2- Properties or variables.

3- Functions or Routines

 

 

 


 

 

 

Figure 4 describes the points where each part of a class is placed. The class name should indicate to whom variables and functions are oriented. For example, in an alarm, this class can be called Alarm. Variables are the data required for the module or class to work.

These variables can be organized into a structure. For the Alarm class this structure is encoded in the header file (alarm.h) and is as follows:

 

typedef struct

{

uint32_t state;

}Alarm;

 

 

Figure 5 - Class Diagram
Figure 5 - Class Diagram

 

 

Functions are codes organized by routines. Figure 5 shows an example of a class diagram for a car alarm. From this diagram we can generate the code for each class. For example, for the Alarm class we have:

 

#include "Alarm.h"

Alarm a;

******************************************************************/

void Alarm_StateMachine(Event event)

  {

  }

 

******************************************************************/

void Alarm_Init(void)

  {

  }

 

 

Figure 6 - Block diagram of a car alarm
Figure 6 - Block diagram of a car alarm

 

 

Similar codes are generated for the other classes. Figure 6 shows the block diagram for a basic car alarm. It may be noted that there is a relation between the blocks and the classes in the diagrams. This is an orientation, but depending on the project we can have more classes.

 

STATE MACHINE DIAGRAM

 

This diagram describes the dynamic operation of the project, i.e., how the project should work. This diagram is formed by the following symbols:

1- States.

2- Transitions.

3- Events.

4- Actions.

 

Figure 7 - Symbol for The States
Figure 7 - Symbol for The States

 

 

Figure 8 - Symbol for the Events
Figure 8 - Symbol for the Events

 

 

Figure 9 - Symbol for the Transitions
Figure 9 - Symbol for the Transitions

 

 

 

Figure 10 - Symbol for the Actions
Figure 10 - Symbol for the Actions

 

 

In Figure 7 we have the symbol for the States. Figure 8 shows the symbol for the transitions. Figure 9 shows the Events, being names (texts) which are placed next to the transitions. Figure 10 shows the Actions, which are routines or functions of the class diagram.

 

   Figure 11 shows a state diagram for the car alarm.
Figure 11 shows a state diagram for the car alarm.

 

 

switch(a.state)

  {

  case Alarm_Disarmed:

   break;

 

   case Alarm_Armed:

   break;

 

   case Alarm_Triggered:

   break;

  }

 

 

Once the state diagram is drawn, it is necessary to do its coding. For this, a case is pointed out in a switch instruction. The code for the state diagram in Figure 11 is:

 

case Alarm_Disarmed:

switch(event)

  {

   case BUTTON:

   a.state = Alarm_Armed;

   break;

  }

 

  break;

 

 

Now, in each case corresponding to each state is necessary to treat the events that this state can handle. For example, for the Alarm_Disarmed state, the events are:

 

case Alarm_Disarmed:

switch(event)

  {

   case BUTTON:

   a.state = Alarm_Armed;

   break;

  }

 

  break;

 

 

 

For the Alarm_Armed state the handled events are:

 

case Alarm_Armed:

switch(event)

  {

   case BUTTON:

   a.state = Alarm_Disarmed;

   break;

  }

  break;

 

 

For the Alarm_Triggered state the handled events are:

 

case Alarm_Triggered:

 

  switch(event)

  {

   case DOOR_OPEN:

   Siren_On();

   a.state = Alarm_Triggered;

   break;

 

   case ULTRASONIC:

   Siren_On();

   a.state = Alarm_Triggered;

   break;

 

   case BUTTON:

   a.state = Alarm_Disarmed;

   break;

  }

  break;

 

This form of codification is called the State Machine. Next, you need to merge all of this code and a single function to create the project state machine. The function will be:

 

 

 

******************************************************************/

void Alarm_StateMachine(Event event)

  {

    switch(a.state)

  {

   case Alarm_Disarmed:

   switch(event)

  {

   case BUTTON:

   a.state = Alarm_Armed;

   break;

  }

  break;

 

  case Alarm_Armed:

  switch(event)

   {

     case BUTTON:

     a.state = Alarm_Disarmed;

     break;

   }

   break;

 

   case Alarm_Triggered:

   switch(event)

     {

        case DOOR_OPEN:

        Siren_On();

       a.state = Alarm_Triggered;

       break;

 

       case ULTRASONIC:

       Siren_On();

       a.state = Alarm_Triggered;

       break;

 

       case BUTTON:

       a.state = Alarm_Disarmed;

       break;

    }

   break;

  }

}

 

 

For both states and events it is necessary to create enumerators (enum) so that the code in the Alarm.c file recognizes these names. This is done on the header file, i.e., in Alarm.h. The code is:

 

enum ALARM_EVENTS

 {

   BUTTON,

   DOOR_OPEN,

   ULTRASONIC

 };

 

enum Alarm_State

  {

    Alarm_Disarmed,

    Alarm_Armed,

    Alarm_Triggered

  };

 

 

The main.c file for the car alarm project will then be:

 

#include "Alarm.h"

#include "RemoteControl.h"

#include "Ignition.h"

#include "Door.h"

#include "UltraSonic.h"

#include "Siren.h"

 

int main()

 {

   Init_IO();

  Alarm_Init();

  RemoteControl_Init();

  UltraSonic_Init();

 

  while(1)

    {

      RemoteControl_Events();

      Ignition_Events();

      Door_Events();

      UltraSonic_Events():

    }

  }

 

 

Note in the main loop the call to the Events () functions of each class. And in this function or routine where the events for the project are coded. The following code shows an example for the Door class.

 

 

******************************************************************/

void Door_Events(void)

   {

     if( Door_IsOpen() )

      {

         Alarm_StateMachine( DOOR_OPEN );

       }

   }

 

So for any door of the car that is opened the Alarm_StateMachine () function is sent to the DOOR_OPEN event and the state machine is in charge of processing the event according to the state in which it is.

 

The example in this article is simple, but demonstrates how to use the UML diagram to create a microcontroller project. In a real project, you can usually use more functions such as locking the car doors, raising the door windows if they are open, or locking the car if it is stolen.

 

There are programs to edit UML diagrams. Some examples are: Visual Paradigm, Enterprise Architect, Microsoft Visual Studio, and many others, but Figure 12 shows the class diagram editor of the Visual Paradigm program. These programs are easy to use and very intuitive in their handling.

 

Figure 12 - Class Editor on Visual Paradigm
Figure 13 - Class Editor on Visual Paradigm

 

 

 


Circuit Bench