Estruturação de dados e mensagens entre camadas para iniciantes

estruturação de dados

Em se tratando de programação de software embarcado, conforme manda o bom senso e a experiência, a organização é tudo. A fim de organizar melhor dados e informações importantes, recorrer à estruturação de dados sempre é uma boa ideia quando se busca um código enxuto e eficaz.

 

Sendo assim, este artigo tem como objetivo explicar o que é estruturação básica de dados (desde as definições formais até a "mão na massa") e como utilizar esse recurso para uma melhor comunicação/troca de mensagens entre as camadas de um software embarcado.

 

 

Pré-requisitos

 

Para compreender de forma satisfatória este artigo, é necessário:

  • Saber como declarar variáveis locais e globais;
  • Conhecer os tipos básicos de variáveis (int, char, short, float, etc.) em C++;
  • Ter noção de funções (passagem de parâmetros e retorno de dados);
  • Saber o que é debouncing.

 

Além disso, recomendo fortemente a leitura de meu artigo anterior, Arquitetura de software em camadas para iniciantes, pois assim ficará mais familiar o conceito de camadas em uma arquitetura de software embarcado, conceito o qual irei me referir neste artigo.

 

Como o foco deste artigo é para quem está começando nos softwares embarcados (além da conhecida abrangência do Arduino entre os que estão iniciando seus estudos e trabalho em softwares embarcados), todos os exemplos feitos aqui serão para Arduino.

 

 

Afinal, o que é estruturação de dados?

 

Para me ajudar a responder essa pergunta, irei recorrer a uma situação rotineira: fazer uma viagem.

 

Ao fazer uma viagem, qualquer um de nós leva coisas conosco. Essas coisas podem ser de qualquer tipo: roupas, sapatos, equipamentos eletrônicos, chapéu, acessórios, etc. Como não seria nada prático carregar cada item isoladamente conosco (ou, do mesmo modo, colocar cada coisa em uma sacola tornaria o transporte tão complicado quanto), nós colocamos tudo em compartimentos grandes, ou seja, colocamos os objetos em malas e mochilas. Fazemos isso pois assim poderemos nos deslocar movendo todos os itens da viagem somente movendo um (ou alguns) compartimentos, pois este(s) contém tudo o que precisamos.

 

Pois bem, com dados/variáveis em softwares embarcados, a situação é exatamente a mesma! No desenvolvimento de softwares embarcados, as coisas que levamos na viagem são dados/variáveis, as malas/mochilas são estruturas de dados e a viagem em si é o transporte de dados entre uma camada do software embarcado para outra.

 

O mesmo ocorre quanto ao tamanho deste pacote de dados. Na vida cotidiana, o peso total desta mala/mochila é a somatória do peso de cada coisa dentro dela. No software embarcado, o tamanho (bytes) de um pacote de dados é igual à soma dos dados/variáveis que nele constam.

 

Em suma, estruturar dados é organizá-los de forma que seja possível enviá-los ou recebê-los de outras camadas de uma só vez, em um único pacote de dados.

 

 

Como estruturar dados?

 

Para isto, os dados são agrupados na forma de estrutura. Dentro da estrutura declaramos as variáveis que desejamos agrupar. Um exemplo de como declarar e utilizar uma estrutura pode ser visto abaixo:

 

 

No exemplo acima, nota-se que a variável "VariavelDeCadastro", feita a partir do esqueleto/struct "Cadastro" manipula seus elementos/campos através de um ponto (NOMEDAVARIAVEL.CAMPODESEJADO). Assim, é possível ler o conteúdo dos elementos ou escrever nos mesmos como se faz com variáveis convencionais.

 

A saída de dados no vista no Serial Monitor é contínua (são repetidos os mesmos dados indefinidamente), e um fragmento da saída é exibido na figura abaixo:

 

Estruturação de dados - Saída no Serial Monitor
Figura 1 - Saída de dados no Serial Monitor

 

Neste contexto, a variável “VariavelDeCadastro” pode ser considerada como um pacote de dados, e como qualquer outro tipo de variável, este pacote pode ser passado como parâmetro para outra função. Para ilustrar a passagem de parâmetros deste tipo, observe o exemplo abaixo. Ele tem exatamente o mesmo objetivo do exemplo 1, porém nele é mostrada como é feita a passagem de parâmetros onde o parâmetro é um pacote de dados.

 

 

Desta forma, com uma única passagem de parâmetros podem ser passadas N variáveis, o que deixa o código mais limpo e fácil de ser entendido do que se fossem passadas as variáveis uma a uma. No exemplo dado, foram passados 6 parâmetros em um só parâmetro, o pacote de dados.

 

Outro fato interessante é que, neste caso, o software foi dividido em camadas, sendo a camada mais especialista a função EnviaCamposCadastroParaSerial() e a camada menos especialista a própria função loop(). Logo, pode-se observar que uma mensagem pode ser passada de uma camada a outra de forma limpa, enxuta e eficaz.

 

 

Muito interessante! Mas o que mais é possível fazer com dados estruturados?

 

A resposta desta pergunta é: o que você conseguir imaginar. A estruturação de dados é um recurso muito poderoso e, com criatividade, é possível resolver problemas complexos com a estruturação de dados adequada. Citarei a seguir um outro exemplo de aplicação de estruturação de dados aplicado a um caso muito comum a nós desenvolvedores (profissionais ou hobbyistas): mostrar telas diferentes em um display.

 

Embora seja uma simples tarefa, dependendo da complexidade do software embarcado que está sendo desenvolvido, pode ser necessário usar vários tipos telas para exibição num display. Isto ocorre pois, na grande maioria dos produtos embarcados que possuem display, há diversos tipos de telas a serem desenhadas. Isto pode parecer simples no começo, mas à medida que o projeto evolui, pode se tornar uma dor de cabeça desenhar vários tipos de telas toda hora, assim como pode tornar o código extenso e “gastão” (muitos trechos repetidos fazendo a mesma tarefa).

 

Considerando este caso, irei mostrar um exemplo de como estruturar telas. Ou seja, todos os dados que serão utilizados para a desenhar a tela estarão em um só pacote de dados, e a tela é desenhada em uma única função (camada mais especialista de display). Esta função irá ser responsável por interpretar os dados do pacote de dados e desenhar a tela conforme é solicitado. Há também uma camada especialista de teclado, responsável por fazer a varredura de teclado (com debouncing) e retornar à camada menos especialista a tecla pressionada. Desta forma, além de utilizar de arquitetura de software em camadas e fazer bom uso da estruturação de dados, tem-se economia de código.

 

Para fazer este exemplo, foi utilizado:

  • Arduino Duemilanove;
  • Shield de display LCD com teclado integrado (exatamente igual este).

 

O exemplo funciona da seguinte maneira: primeiramente, é exibida uma tela inicial (chamada de Splash Screen). A seguir, é consultado continuamente qual tecla foi pressionada e para cada tela há uma ação correspondente. As ações para cada tecla pressionada são exibidas abaixo:

  • Tecla up:  mostra uma tela com um texto e faz scroll para esquerda;
  • Tecla down: mostra uma tela com texto que pisca 5 vezes;
  • Tecla left: mostra uma tela com texto simples/estático;
  • Tecla right: mostra uma tela com um texto e faz scroll para direita.

 

Uma foto do Arduino ligado ao Shield pode ser vista abaixo:

 

Estruturacao de dados - Arduino com shield
Figura 2 - Arduino com shield

 

O código do exemplo pode ser visto abaixo.

 

Observação: O debouncing do teclado possui uma rotina bem versátil (e não tão intuitiva), a qual já utilizei com sucesso antes neste tipo de teclado (por isso a utilizei aqui). Portanto, preste atenção nos defines do código que dizem respeito ao debouncing para ajustá-lo conforme sua necessidade.

 

 

Conforme pode ser visto no exemplo, o software desenvolvido possui três camadas: uma camada menos especialista (representada pelas funções loop() e MostraSplashScreen()), uma camada intermediária (representada pela função ExibeTelaSolicitada()) e, por fim, uma camada mais especialista (representada pelas funções DesenhaTela() e LeTeclado()). Logo, as camadas estão isoladas. Ou seja, se for necessário substituir o display ou teclado, basta alterar as camadas mais especialistas respectivas e o software funcionará normalmente.

 

Nota-se neste exemplo que toda exibição de tela no display é feita por meio de dados estruturados, logo com apenas uma função é possível desenhar a tela do jeito que quiser.

 

 

Conclusão

 

A estruturação de dados é um recurso muito importante na programação de software embarcado, pois permite condensar em somente uma variável vários tipos de dados diferentes, além de permitir a passagem de todos eles de uma só vez a outras camadas de software.

 

Conforme visto no último exemplo, se bem utilizada, a estruturação de dados permite que somente uma função construa algo conforme os parâmetros da estrutura passada como parâmetro, o que garante economia de código-fonte e uma melhor organização (já que se um bug for descoberto nesta função, basta corrigi-la e a correção será aplicada a todos os pontos do código em que a função é chamada).

 

 

Saiba mais sobre arquitetura de software em sistemas embarcados

 

Arquitetura de Software em Sistemas Embarcados

Arquitetura de software em camadas para iniciantes

Arquitetura de desenvolvimento de software

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Pedro Bertoleti
Sou engenheiro eletricista formado pela Faculdade de Engenharia de Guaratinguetá (FEG - UNESP) e trabalho com Android embarcado em Campinas-SP. Curioso e viciado em tecnologia, sempre busco me aprimorar na área de sistemas embarcados (modalidades bare-metal, RTOS, Linux embarcado e Android embarcado).Para mais informações, acesse minha página no Facebook:https://www.facebook.com/pbertoleti

1
Deixe um comentário

avatar
 
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Rafael Dias Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Rafael Dias
Visitante
Rafael Dias

muito bom. a escolha de uma boa arquitetura de software, dos abstracts data types (ADTs) e as estruturas de dados é que podem determinar se um projeto pode ser extensível e mantenível com o passar do tempo. É importante sempre olharmos para estes aspectos e não cair na armadilha de escrever um firmware/software que serve somente para um projeto,não podendo reutilizar as estruturas de software em outro contexto. Ah, só uma observação... Acho que vc passou uma struct como parâmetro de algumas funções somente para fins didáticos... O recomendado para estruturas grandes é de se passar somente uma referência (ou… Leia mais »