Iniciando C++ em sistemas embarcados

cpp

 Objetivo

O objetivo deste artigo é apresentar uma aplicação fazendo-se o uso da linguagem C++ em sistemas embarcados, sem se preocupar em abordar todas as características da linguagem, muito menos o ambiente de desenvolvimento e o hardware. Ou seja, o intuito principal é passar a filosofia de encapsulamento, levando o código ao mais alto nível possível. Entendendo esta essência, pode-se conseguir boa estruturação e reutilização do código sem muitas preocupações. Vale lembrar que é necessário que o leitor tenha conhecimentos sobre linguagens de orientação a objetos (OOP – Object-Oriented Programming).

Aplicação

A ferramenta utilizada para desenvolvimento desta aplicação foi o Keil uVision 5.20, o qual pode ser adquirido no próprio site, bastando apenas preencher um simples formulário. A versão vigente é v5.21a e o hardware utilizado é o kit STM32F0 Discovery, o qual já utilizei em Primeiros passos com a Placa STM32F0 Discovery.

Código

O código da aplicação será apresentado em três partes. Na primeira será apresentado o arquivo “main.cpp”, cujo conteúdo é os includes, a inicialização do hardware, as declarações dos objetos e a aplicação. A segunda parte apresenta o arquivo “GPIO.cpp” o qual contém o código de todos os métodos da classe. E, por fim, na terceira parte é apresentado o arquivo “GPIO.h”, onde temos a declaração de uma variável global, enumerações e a criação da classe.

No arquivo “main.cpp” podemos ver que dentro da rotina principal há a criação do objeto “Obj_GPIO” que será alvo da aplicação, a rotina de inicialização/configuração do clock do microcontrolador “vSystemCoreClockSetHSE()”, a inicialização da instância por meio da função-membro construtora e, por último, o loop já com a aplicação em uso. Vide código 1 logo abaixo.

Código 1: 

 
Percebe-se a nomeação dos métodos (construtora e rotinas de aplicação) que remetem claramente às suas respectivas funções, sem ao menos sabermos o que de fato é feito dentro deles. Isso nos permite entender rapidamente o código, ou seja: a inicialização dos ports “8” e “9” como saídas, ambos do port “C”. Já na aplicação, a qual é nada mais do que um blink LED (pisca-pisca), vemos ambos os “GPIO_PIN_8” e “GPIO_PIN_9” alternarem seus respectivos valores por meio do método “vGPIOWriteOutput()” quando o objeto “Obj_GPIO” utiliza o operador de acesso “.” para utilizar os recursos disponíveis da classe em que ele foi instanciado. Neste caso, “Obj_GPIO.vGPIOWriteOutput()”.
 
 
 
O ponto mais importante é que somente objetos instanciados a partir da “GPIOClass” podem acessar os métodos e dados dessa classe, remetendo ao encapsulamento. Vale ressaltar (antes que polêmicas sejam feitas) que esta classe poderia ser acessada por outro objeto instanciado à outra classe, desde que esta outra constasse em sua declaração “friend GPIOClass“. Todavia, isto elimina o conceito de encapsulamento e isto não queremos e muitos menos o faremos aqui!
 
 
A classe “GPIOClass” é constituída por cinco métodos:
  • a construtora GPIOClass(), a qual inicializa o dado pGPIO com “NULL”;
  • vGPIOEnable(), que habilita o clock do GPIO informado como parâmetro;
  • vGPIOGetAddress(), que obtêm o endereço do port que se deseja inicializar;
  • o vGPIOInit(), que realiza a inicialização do pino e, por fim;
  • vGPIOWriteOutput(), que altera o nível lógico do(s) pino(s) informado(s).

O código de cada um pode ser visto abaixo.

Código 2: 

 
E por fim, temos o arquivo “GPIO.h”, onde declaramos a classe “GPIOClass”, um vetor mascarável para acessar os pinos de cada port e alguns “enums”. Vide código 3.
 
Código 3:
 
 
Depois de verificar os arquivos “GPIO.cpp” e “GPIO.h”, entendemos o que acontece quando os pinos alternam seus níveis lógicos e, consequentemente, piscam o LED. Exatamente neste ponto em que chegamos e, se relermos a aplicação na “main.cpp”, vemos que criamos nada mais do que uma abstração de camada além do encapsulamento. Isso de fato é muito bom desde que tanto a classe quanto seus respectivos conteúdos (dados e métodos) sejam bem elaborados e amplamente testados, possibilitando o bom uso e a reutilização em outros projetos, além de servir de base para uma biblioteca (“lib”).
 
 

Conclusão

Vimos que o exemplo apresentado cria um encapsulamento para o GPIO do microcontrolador, consequentemente, uma abstração de camada. Porém, este exemplo não determina nenhuma regra, assim o leitor poderá realizar seu encapsulamento da forma que lhe for conveniente. Além disso, poderá também estender a outros periféricos. Realizando este trabalho aos poucos, pode-se conseguir uma grande herança no futuro, pois ao criar classes para certos tipos de periféricos, cria-se, assim, uma biblioteca. 

Saiba mais

Orientação a objeto em C: Encapsulamento com estruturas opacas

Orientação a objeto em C: Polimorfismo

Referências 

A Complete Guide to Programming C++ –  Ulla Kirch-Prinz/Peter Prinz

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

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

Software
,
Comentários:
Notificações
Notificar
guest
6 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Mauricio Oliveira Costa
Mauricio Oliveira Costa
19/09/2016 12:58

Muito bacana iniciar esta conversa sobre C/C++. O mito de que C/C++ infla o código ou mesmo complica demais é para aqueles que estão acomodados com o C. Uma vez iniciado no C/C++, você não volta mais atrás e começa a ver o C como uma linguagem tão limitada quanto o Basic, principalmente no quesito reuso de código e sucessão do conhecimento.

Rafael Dias
Rafael Dias
Reply to  Mauricio Oliveira Costa
19/09/2016 14:05

Embora que dá para usar boas práticas de OOP em C. A meu ver, OOP está mais ligada a metodologia de desenvolvimento de que a linguagem propriamente dita.

Eder Andrade
Eder
Reply to  Rafael Dias
16/08/2017 14:56

Sim, e também a capacidade do compilador.

Rafael Gebert
Rafael Gebert
Reply to  Mauricio Oliveira Costa
21/09/2016 09:05

Amigo Mauricio, acomodado é uma palavra muito forte… Até porque você está precisando estudar um pouco mais… Pergunto, se C++ não gasta processo extra e não “infla” conforme você comentou então me explique porque o uso de C++ exige memória heap? É porque ele usa alocação dinâmica de memória…. então as estruturas, ah desculpa, os objetos são alocados dinamicamente.

Rafael Dias
Rafael Dias
19/09/2016 12:08

Há uma lenda acerca do overhead de C++ em sistemas embarcados baremetal. Eu mesmo não tenho opinião formada a respeito.

Eder Andrade
Eder
Reply to  Rafael Dias
16/08/2017 15:02

Sim, porém esse “overhead” está mais ligado ao “leakage of memory” (RAM) devido a criação de objetos e o não “free()” deles, já que, eles são alocados no heap. Ou seja, falta de gerenciamento ou “carinho” no código, leva ao desperdício de memória e “bugs”.

Talvez você goste:

Séries

Menu

EVENTO ONLINE

Simplificando seus projetos de Internet das coisas com o iMCP HT32SX Sigfox

DATA: 18/05 às 15:00h