O desenvolvimento de um projeto com microcontrolador pode ser feito de muitas formas ou maneiras. Cada programador ou grupo de programadores usará provavelmente a forma que mais seja adequada a sua maneira de trabalhar. Nos últimos anos, está se tornando popular a linguagem UML ou Linguagem Unificada de Modelagem como método de programação para projetos baseados em microcontroladores. Alguns compiladores como da IAR, oferecendo suporte aos diagramas e máquinas de estado, são um dos diagramas usados na linguagem UML.

Para ter uma ideia geram do que pode ser um projeto com microcontrolados, sem usar a linguagem UML (Unified Modeling Language) ou um método similar, pode se comparar a alguém que deseja construir um edifício e não faz uso de um arquiteto para dar forma ao projeto.

Também podemos comparar a quem deseja fazer uma peça mecânica e não faz antes um plano, desenho ou diagrama desta peça. Pode-se dizer que a linguagem UML é como a arquitetura de ou plano de um projeto com microcontrolador.

 Inicialmente a linguagem foi criada para poder desenvolver programas e projetos de software para computadores, mas nos dias atuais, está sendo usada para o desenvolvimento de programas ou projetos com microcontroladores. Como a linguagem UML foi desenvolvida para linguagens orientadas a objeto (classes) como o C++/C# e a maioria dos projetos com microcontroladores está escrita em linguagem C, é necessário fazer algumas adaptações para suportar UML na linguagem C. 

A linguagem UML é formada por uma série de diagrama com a finalidade de descrever, organizar,formatar, classificar, etc. o projeto que se pretende desenvolver. Para o caso de projetos com microcontroladores, os diagramas mais usados são:

Diagramas de Casos de Uso.

Diagramas de Classes.

Diagramas de Estado.

Neste artigo explicaremos como usar estes diagramas nos desenvolvimento de um projeto ou ideia que use microcontroladores.

 

DIAGRAMAS DE CASO DE USO (USE CASE DIAGRAM)

Os diagramas de caso de uso indicam os usos que o projeto pode ter, ou seja, para que serve o projeto e quem vai usá-los. Por este motivo este diagrama tem dois componentes importantes.

 

1 – Os Usuários.
1 – Os Usuários.

 

 

2 – Os Casos de Uso.
2 – Os Casos de Uso.

 

 

Os usuários são representados no diagrama por um símbolo similar ao da figura 1. Os Casos de Uso são representados no diagrama por um símbolo similar ao da figura 2. Ao lado dos símbolos Usuários é colocado um texto descrevendo seu papel (rol) e dentro dos símbolos Casos de Uso é colocado um texto descrevendo sua função.

 

 

3 – Diagrama de Casos
3 – Diagrama de Casos

 

 

A figura 3 mostra um exemplo de diagrama de Casos de Usos para um projeto de um alarme básico para carro. Neste diagrama, a linha com seta indica que o Usuário (ator) faz uso do do projeto.

 

 

DIAGRAMA DE CLASSES (CLASS DIAGRAM).

 

Os Diagramas de Classes descrevem as funções e dados (variáveis) do projeto. Este diagrama se encarrega de classificar as funções (rotinas) em módulos ou blocos para uma melhor organização do software. A estes módulos ou blocos é dado o nome de Classes.

Cada Classe no diagrama é formada por 3 partes principais:

1- Nome da classe.

2- Propriedades ou variáveis.

3- Funções ou Rotinas

 

4 – As partes de uma Classe
4 – As partes de uma Classe

 

 

A figura 4 descreve os pontos onde são colocadas cada uma das partes de uma classe. O nome da classe deve indicar a quem estão orientadas as variáveis e as funções. Por exemplo, em um alarme, esta classe pode chamar-se Alarm. As variáveis são os dados necessários para que o módulo ou classe trabalhe.

Estas variáveis podem ser organizadas em uma estrutura. Para a classe Alarm esta estrutura é codificada no arquivo de cabeceira (alarm.h) e é a seguinte:

 

typedef struct

{

uint32_t state;

}Alarm;

 

 

Figura 5. Diagrama de Classes
Figura 5. Diagrama de Classes | Clique na imagem para ampliar |

 

As funções são códigos organizados por rotinas. A figura 5 mostra um exemplo de um diagrama de classe para um alarme de carro. A partir deste diagrama podemos gerar o código para cada classe. Por exemplo, para a classe Alarm temos:

 

#include "Alarm.h"

Alarm a;

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

void Alarm_StateMachine(Event event)

{

}



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

void Alarm_Init(void)

{

}

 

Figura 6. Diagrama de blocos de um alarme de carro
Figura 6. Diagrama de blocos de um alarme de carro | Clique na imagem para ampliar |

 

Para as demais classes são gerados códigos similares. A figura 6 mostra o diagrama de blocos para um alarme de carro básico. Pode-se notar que existe uma relação entre os blocos e as classes nos diagramas. Isso é uma orientação, mas dependendo do projeto podemos ter mais classes.

 

 

DIAGRAMA DE ESTADO DE MÁQUINA (STATE MACHINE DIAGRAM).

Este diagrama descreve o funcionamento dinâmico do projeto, ou seja, como o projeto deve funcionar. Este diagrama é formado pelos seguintes símbolos:

1- Estados.

2- Transições.

3- Eventos.

4- Ações.

 

 Figura 7. Símbolo para os Estados
Figura 7. Símbolo para os Estados

 

 

 

 Figura 8. Símbolo para os Eventos
Figura 8. Símbolo para os Eventos

 

 

 

 Figura 9. Símbolo para las Transições
Figura 9. Símbolo para las Transições

 

 

 

 Figura 10. Símbolo para as Ações
Figura 10. Símbolo para as Ações

 

Na figura 7 temos o símbolo para os Estados. A figura 8 mostra o símbolo para as transições. A figura 9 mostra os Eventos, sendo nomes (textos) que são colocados ao lado das transições. A figura 10 mostra as Ações, as quais são rotinas ou funções do diagrama de classes.

A figura 11 mostra um diagrama de estado para o alarme de carro.

Uma vez desenhado o diagrama de estado, é necessário fazer sua codificação. Para isso, se assinala um case em uma instrução switch. O código para o diagrama de estado da figura 11 é:

 

 Figura 11. Diagrama de Estado
Figura 11. Diagrama de Estado | Clique na imagem para ampliar |

 

 

switch(a.state)

{

case Alarm_Disarmed:

break;

 

case Alarm_Armed:

break;

 

case Alarm_Triggered:

break;

}

 

Agora, dentro de casa case correspondente a cada estado é necessário tratar os eventos que esse estado pode manusear. Por exemplo, para o estado Alarm_Disarmed, os eventos são:

 

case Alarm_Disarmed:

switch(event)

{

case BUTTON:

a.state = Alarm_Armed;

break;

}

 

break;

 

Para o estado Alarm_Armed os eventos manuseados são:

case Alarm_Armed:

switch(event)

{

case BUTTON:

a.state = Alarm_Disarmed;

break;

}

break;

 

Para o estado Alarm_Triggered os eventos manueados são:

 

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;

 

A esta forma de codificação se dá o nome de Máquina de Estado. A seguir, é necessário juntar todo este código e uma única função, para criar a máquina de estado do projeto. A função será:

 

*****************

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;

}

}

 

Tanto para os estados como para os eventos é necessário criar enumeradores (enum) para que o código no arquivo Alarm.c reconheça esses nomes. Isso se faz no arquivo de cabeceira (head), ou seja em Alarm.h. O código é:

 

enum ALARM_EVENTS

{

BUTTON,

DOOR_OPEN,

ULTRASONIC

};

 

enum Alarm_State

{

Alarm_Disarmed,

Alarm_Armed,

Alarm_Triggered

};

 

O arquivo main.c para o projeto de alarme de carro será então:

#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():

}

}

Notemos no loop principal as chamada para as funções Events() de cada classe. E nesta função ou rotina onde os eventos para o projeto são codificados. O seguinte código mostra um exemplo para a classe Door.

 

******************

void Door_Events(void)

{

if( Door_IsOpen() )

{

Alarm_StateMachine( DOOR_OPEN );

}

}

 

Assim para qualquer porta do carro que seja aberta é enviado a função Alarm_StateMachine() o evento DOOR_OPEN e a máquina de estado se encarrega de processar o evento de acordo com o estado em que se encontra.

O exemplo deste artigo é simples, mas demonstra como usar os diagrama UML para criar um projeto com microcontrolador. Em um projeto real, normalmente podem ser usadas mais funções como, por exemplo, bloquear as portas do carro, elevar os vidros das portas, caso estejam abertos, ou bloquear o carro, caso se detecte que está sendo roubado.

Existem programas para editar os diagramas UML. Alguns exemplos são: Visual Paradigm, Enterprise Architect, Visual Studio da Microsoft e muitos outros, mas a figura 12 mostra o editor de diagrama de classes do programa Visual Paradigma. Estes programas são de fácil uso e muito inttuitivos em seu manejo.

 

 

Figura 12. Editor de Classes em Visual Paradigm
Figura 12. Editor de Classes em Visual Paradigm | Clique na imagem para ampliar |

 

 

 

 

NO YOUTUBE


NOSSO PODCAST