Posts com Tag ‘microcontrolador’

Caro Colega,

controle PID é uma das formas mais conhecidas e tradicionais de se implementar controle de processos. O desafio é embutir esse controle em microcontroladores e de baixo custo e com recursos de hardware limitados. No artigo técnico Controlador PID digital: Uma modelagem prática para microcontroladores – Parte 1, de Felipe Neves,  publicado originalmente no site Embarcadosé  apresentado com detalhes o controlador PID, sua arquitetura típica, o desenvolvimento das equações para o controle e alguns exemplos de como se pode desenvolver um controle PID. Nesse artigo, também publicado originalmente no site Embarcados,  serão retomados alguns conceitos sobre esse tipo de controle e serão apresentadas formas de cálculo numérico para implementar a parte diferencial e a integral do controlador, de forma a viabilizar esses cálculos em microcontroladores. No final são apresentados códigos que você pode executar diretamente no Scilab para experimentar e explorar os detalhes dos resultados obtidos. Divirta-se!

Abraço,

 

Henrique

consulte sempre um engenheiro eletrônico

======================================================

PID_Capa

Introdução

 

No artigo técnico Controlador PID digital: Uma modelagem prática para microcontroladores – Parte 1é  apresentado com detalhes o controlador PID, sua arquitetura típica, o desenvolvimento das equações para o controle e alguns exemplos de como se pode desenvolver um controle PID. Nesse artigo serão retomados alguns conceitos sobre esse tipo de controle e serão apresentadas formas de cálculo numérico para implementar a parte diferencial e a integral do controlador. Essa forma alternativa de cálculo casa muito bem com a aplicação em microcontroladores ou processadores de 8 bits ou outros relativamente lentos. Os resultados que serão apresentados a seguir, foram largamente aplicados nos primeiros controladores PID digitais e certamente ainda são úteis nos dias de hoje, por sua simplicidade e velocidade de processamento.

Arquitetura típica de um controlador PID

 

Um sistema de controle típico de PID em malha fechada tem o aspecto mostrado na Figura 1. Nessa figura pode-se observar uma entrada, referente a um sinal de referência ou setpoint, um bloco onde essa referência é subtraída de um sinal proveniente do processo, em geral medido de alguma forma por um sensor, transdutor etc. Essa subtração produz um sinal de erro que entra no controlador PID propriamente dito, e a saída do controlador, que atua sobre o processo que está sendo controlado, é aplicada para conduzir o processo ao estado desejado.

.

PID_1a

 Figura 1: Controle PID típico

 

Na prática, o controlador PID digital destacado na Figura 1 em vermelho, pode ser representado como mostrado na Figura 2. O erro é amostrado, produzindo assim um conjunto de amostras discretizadas do sinal de erro, que é conduzido a um conversor analógico / digital (A/D), depois são calculados os valores da derivada, da integral e do valor proporcional, em seguida esses valores calculados são somados e conduzidos a um conversor digital / analógico (D/A).  

PID_2a

Figura 2: Controlador PID em blocos

 

O desenho da Figura 2 representa o fluxo do sinal de erro para o controlador PID de forma a simplificar o desenvolvimento dos cálculos que serão apresentados a seguir. É evidente que num controlador real, os sinais de SP (setpoint) e PV (present value) também são digitalizados e subtraídos para que se obtenha o erro. O importante é fixar o conceito de que o erro deve ser entregue ao controlador numa frequência ou taxa fixa. Isso é requisito para o desenvolvimento que será realizado a seguir. Para que o sistema funcione bem, também é necessário que a atualização do sinal de saída pelo conversor D/A seja feito na mesma frequência do amostrador de entrada. Na Figura 3 é mostrado um sinal analógico como exemplo de sinal de erro e são destacadas as amostras realizadas num período fixo (Δ).

PID_3

Figura 3: Exemplo de sinal de erro e de sua amostragem

A seguir será desenvolvido um pouco de teoria, o suficiente para que se possa saber de onde foram tiradas as equações que resultarão desse desenvolvimento. Se você preferir, pode consultar direto os quadros resumo que apresentam as equações resultantes desses cálculos.

 

Séries de Taylor

 

Brook Taylor elaborou uma teoria a respeito de funções matemáticas em 1715, conhecida como teorema de Taylor ou séries de Taylor. Esse teorema estabelece que: sendo f  uma função  infinitamente diferenciável, ela pode ser representada pela seguinte fórmula:

Equação_1a(1)

onde:

  • fx0a  representa a k-ésima derivada da função avaliada no ponto x0;
  • X0             é um ponto arbitrário de referência;
  • k              é o fatorial de k.

Se a somatória acima convergir, a função pode ser representada por uma série finita de termos. Como por exemplo a expansão da série (1):

seriea(2)

 

Obs: Quando x0 = 0, a série (2) é conhecida como série de McLaurin.

A seguir serão utilizadas as séries de Taylor para deduzir formas simples para o cálculo da primeira derivada de uma função e a integral dessa função.

 

Derivação Numérica

 

Seja definida uma função f(x), representada por uma série de Taylor, tal como mostrada em (1), onde x = i é uma amostra arbitrária de índice i tal como mostrado na Figura 3. O valor de f(x) será batizado de fi. Seja f(i-1) o valor dessa mesma função calculado no índice (i-1). A distância entre essas amostras é de Δ, correspondente a uma unidade de tempo relacionada com a frequência ou taxa de amostragem. Daí obtemos:

Equação_fi(3)

Para avaliar a função em (i-1), vamos substituir i por (i-Δ). Realizando a substituição e rearranjando a equação obtida, chega-se na equação (4).

Equação_fi_1(4)

Escrevendo essa somatória na forma expandida, obtém-se:

Equação_fi_1a (5)

Se desprezarmos os termos de segunda ordem e superiores e rearranjando, a equação fica assim:

Equação_2pontos(6),  e o erro = erro_2pontos

 

A expressão (6) é conhecida como a derivada com 2 pontos.

 

É evidente que nesse cálculo, o erro é relativamente grande. Pode-se estender o raciocínio desenvolvido acima para um cálculo mais preciso, que pode ser obtido com 3, 4 ou mais amostras do sinal.

 

Se substituirmos i por (i- 2*Δ) e for desenvolvido o mesmo raciocínio que foi utilizado para i-1 poderemos levantar a equação de f(i-2) em função de fi.

Equação_fi_2(7)

Usando a equação (5) e rearranjando, obtém-se:

 

derivada_3pontos(8), onde o erro = erro_3pontos

 

Essa é a equação de cálculo de derivada com 3 pontos. De maneira análoga pode-se desenvolver a derivada de 4 pontos, mostrada na equação (9).

 

derivada_4pontos(9), onde o erro = erro_4pontos

 

A seguir será apresentado um quadro resumo com as fórmulas desenvolvidas até aqui.

 

Quadro resumo da diferenciação digital

 

Aqui será adotada uma nova notação, mais frequentemente utilizada em processamento digital de sinais (DSP) e em controle digital. Isso facilitará o entendimento de quem está habituado a essa notação e introduz a notação para quem ainda não a conhece. A notação é assim:

  • y = saída (nesse caso a derivada da função);
  • x = amostra atual da função;
  • z-n = n-ésima amostra anterior;
  • Δ = intervalo de tempo entre amostras.

Resumo das fórmulas referentes à diferenciação digital:

 

=====================================================================

  • Derivada calculada com 2 pontos:

der_2p_z(10)

—————————————————————————————————————————

  • Derivada calculada com 3 pontos:

der_3p_z(11)

————————————————————————————————————————–

  • Derivada calculada com 4 pontos:

der_4p_z(12)

===================================================================

 

Os resultados obtidos nas equações acima são facilmente implementáveis em microprocessadores.

 

 

Integração Numérica

 

Para desenvolver as equações referentes à integração numérica, o raciocínio é o mesmo já desenvolvido para a diferenciação. Voltando à Figura 3, onde temos representada uma forma de onda arbitrária amostrada em intervalos regulares de Δ segundos, pode-se definir que:

Integral_0(13)

Seja o segundo termo da equação (13):

integral0a(14)

Desenvolvendo a série para Ii-1 se obtém uma equação semelhante à equação (5):

integral1(15)

Rearranjando, obtém-se:

Integral2(16)

Desenvolvendo:

integral3(17)

Substituindo:

integral4(18)

desprezando os termos de segunda ordem ou superiores chega-se à equação para o cálculo da integral com 2 pontos.

 

integral5(19), onde o erro = erro_integral

 

A fórmula (19) é conhecida como “regra do trapézio”.

 

O cálculo da integral pode ser estendido para mais pontos, para aumentar a precisão do resultado. A seguir, a equação para o cálculo com 3 pontos (20) e 4 pontos (21).

 

integral6(20), onde o erro =erro3i

.

integral7(21), onde o erro = erro4i

 

Quadro resumo da integração digital

Aqui também será adotada a nova notação, mais frequentemente utilizada em processamento digital de sinais (DSP) e em controle digital.  A notação é assim:

  • y = saída (nesse caso a integral da função);
  • x = amostra atual da função;
  • z-n = n-ésima amostra anterior;
  • Δ = intervalo de tempo entre amostras.

Resumo das fórmulas referentes à integração digital:

 

=====================================================================

  • Integral calculada com 2 pontos:

Integralz2p(22)

 

—————————————————————————————————————————

  • Integral calculada com 3 pontos:

integral3pz(23)

 

————————————————————————————————————————–

  • Integral calculada com 4 pontos:

integral4pz(24)

===================================================================

 

Observe que as fórmulas acima calculam a integral incremental entre uma amostra e a anterior. Para que seja realizado um cálculo de integral de fato é necessário acumular os resultados.

 

Obtidos os resultados  acima, é interessante verificar se eles realmente funcionam. Para isso eles serão simulados num programa para cálculos matemáticos conhecido por Scilab. Serão mostrados os respectivos códigos e os resultados. Para que você possa testar e explorar na sua própria máquina será necessário instalar o Scilab nela. Baixe o programa aqui: SCILAB vers. 5.5.0. O programa é gratuito e tem versões para Windows, GNU/Linux e Mac OS X.

Inicie o programa e digite o código a seguir. Se você preferir, você pode marcar o código, copiá-lo (Ctrl-C) e colá-lo no Scilab (Ctrl-V). Para iniciar as operações basta teclar o “Enter”.

 

Cálculo de Integrais numéricas utilizando o Scilab

 

// Inicializar as variáveis e a forma de onda para os testes

nCiclos = 10; // Define o núemro de ciclos da forma de onda
nAmostras = 40; // Define o número de amostras por ciclo

// Gera o vetor de referência para a produção da forma de onda

t = (1:2*%pi/nAmostras:nCiclos * 2 * %pi + (1-2*%pi/nAmostras)); 
nvErro = squarewave(t); // Gera uma onda quadrada com 400 amostras

// Gera o gráfico para essa forma de onda

a0 = figure(0);
a0.background = -2;

plot(nvErro);

// Gera o grid e as legendas

xtitle('Forma de onda do Erro para testes', 'Indice das amostras', 'Amplitude');
set(gca(), "data_bounds", [0,400,-1.2,1.2]);
set(gca(), "grid", [1,1]);

 

 

Os comandos acima geram um gráfico parecido com o apresentado na Figura 4.

PID_Fig_1a

Figura 4: Gráfico do forma de onda quadrada gerada no Scilab

 

Como não há formas de onda triangulares prontas no Scilab, será utilizada a forma de onda quadrada, calculada sua integral para formar a onda triangular e calculada a diferencial da onda triangular para formar a onda quadrada novamente. Digite o seguinte código no Scilab (ou copie e cole):

 

// Inicializa as variáveis para o cálculo da integral com 2 pontos

Int2p = zeros(1, size(nvErro,2));
Int2pAcum = 0;
Z1 = 0;
Delta = 1;

// Calcula a Integral com 2 pontos


for nIndice = 1:size(nvErro,2)
    Int2p(nIndice) = ((nvErro(nIndice) + Z1)* Delta/2) + Int2pAcum;
    Int2pAcum = Int2p(nIndice);
    Z1 = nvErro(nIndice);
end;

// Apresenta a integral no gráfico

a1 = figure(1);
a1.background = -2;

plot(Int2p, 'm');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Integral da forma de onda calculada com 2 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-10,20]); 
set(gca(), "grid", [1,1]);

//==========================================================================

// Inicializa as variáveis para o cálculo da integral com 3 pontos

Int3p = zeros(1, size(nvErro,2));
Int3pAcum = 0;
Z1 = 0;
Z2 = 0;
Delta = 1;

// Calcula a Integral com 3 pontos

for nIndice = 1:size(nvErro,2)
     Int3p(nIndice) = ((5*nvErro(nIndice) + 8*Z1- Z2)* Delta/12) + Int3pAcum;
     Int3pAcum = Int3p(nIndice);
     Z2 = Z1;
     Z1 = nvErro(nIndice);
end;

// Gera gráfico

a2=figure(2);
a2.background = -2;

plot(Int3p, 'b');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Integral da forma de onda calculada com 3 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-10,20]); 
set(gca(), "grid", [1,1]);

//========================================================================================================= // Inicializa as variáveis para o cálculo da integral com 4 ponto

Int4p = zeros(1, size(nvErro,2));
Int4pAcum = 0; 
Z1 = 0; 
Z2 = 0; 
Z3 = 0; 
Delta = 1; 

// Calcula a Integral com 4 pontos 

for nIndice = 1:size(nvErro,2) 
    Int4p(nIndice) = ((9*nvErro(nIndice) + 19*Z1- 5*Z2 + Z3)* Delta/24) + Int4pAcum;
    Int4pAcum = Int4p(nIndice); 
    Z3 = Z2; 
    Z2 = Z1; 
    Z1 = nvErro(nIndice);
end; 

// Gera gráfico figure(3);

a3 = figure(3);
a3.background = -2;

plot(Int4p, 'r');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Integral da forma de onda calculada com 4 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-10,20]); 
set(gca(), "grid", [1,1]); 

 

Os gráficos obtidos são como o mostrado na Figura 5.

Integral_1a

Figura 5: Gráfico da integral calculada com 3 pontos

 

Os três gráficos obtidos parecem ser iguais, por motivo da forma de onda quadrada ser muito simples. Se olharmos com detalhes os “bicos” das formas de onda ampliadas, poderemos observar as diferenças (Figura 6). Quanto maior o número de pontos usados para o cálculo, menor a diferença se comparada com a onda triangular ideal.

Integral_detalhe

Figura 6: Gráfico das integrais calculadas sobrepostas

 

Cálculo de Diferencias numéricas utilizando o Scilab

 

Em seguida serão mostradas a utilização das diferenciais calculadas com 2, 3 ou 4 pontos. A onda utilizada para essas operações é a onda triangular resultante da  integral calculada com 4 pontos.

 

// Calculo das diferencias numéricas utilizando-se 2 pontos

// Fecha os gráficos

close(a0);  
close(a1);
close(a2);
close(a3);


Diff2p = zeros(1, size(Int4p,2));
Z1 = 0;
Delta = 1;

// Calcula a Diferencial com 2 pontos

for nIndice = 1:size(nvErro,2)
    Diff2p(nIndice) = ((Int4p(nIndice) - Z1)* 1/Delta);
    Z1 = Int4p(nIndice);
end;

// Apresenta a diferencial no gráfico

a0 = figure(0);
a0.background = -2;

plot(Diff2p, 'm');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Diferencial da forma de onda calculada com 2 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-1.5,1.5]); 
set(gca(), "grid", [1,1]);

//==========================================================================

// Calculo das diferencias numéricas utilizando-se 3 pontos

Diff3p = zeros(1, size(Int4p,2));
Z1 = 0;
Z2 = 0;
Delta = 1;

// Calcula a Diferencial com 3 pontos

for nIndice = 1:size(nvErro,2)
    Diff3p(nIndice) = ((3*Int4p(nIndice) - 4*Z1 + Z2)* 1/(2*Delta));
    Z2 = Z1;
    Z1 = Int4p(nIndice);
end;

// Apresenta a deferencial no gráfico

a1 = figure(1);
a1.background = -2;

plot(Diff3p, 'b');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Diferencial da forma de onda calculada com 3 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-2.5,2.5]); 
set(gca(), "grid", [1,1]);

//==========================================================================

// Calculo das diferencias numéricas utilizando-se 4 pontos

Diff4p = zeros(1, size(Int4p,2));
Z1 = 0;
Z2 = 0;
Z3 = 0;
Delta = 1;

// Calcula a Diferencial com 4 pontos

for nIndice = 1:size(nvErro,2)
    Diff4p(nIndice) = ((11*Int4p(nIndice) - 18*Z1 + 9*Z2 - 2*Z3)* 1/(6*Delta));
    Z3 = Z2;
    Z2 = Z1;
    Z1 = Int4p(nIndice);
end;

// Apresenta a deferencial no gráfico

a2 = figure(2);
a2.background = -2;

plot(Diff4p, 'r');

// Gera o grid e as legendas

set(gca(), "background", [-2]); 
xtitle('Diferencial da forma de onda calculada com 4 pontos', 'Indice das amostras', 'Amplitude'); 
set(gca(), "data_bounds", [0,400,-2.5,2.5]); 
set(gca(), "grid", [1,1]);

 

Os gráficos obtidos são semelhantes ao da Figura 7.

 Diferencial_1b

Figura 7: Diferencial da onda triangular calculada com 4 pontos

 

Na Figura 8 pode-se observar as três diferenciais sobrepostas. Observe que a diferencial com mais pontos tem um transitório maior do que as outras, o que está coerente. Aqui encerram-se as simulações para demonstrar o funcionamento dos métodos numéricos.

É recomendável que o leitor faça experimentos com o Scilab, crie outras formas de onda, utilize formas de onda reais, pois o Scilab permite que se carregue dados de arquivos, e se familiarize com os recursos do Scilab, se acaso ainda não os conhece. O Scilab é uma ferramenta poderosa, tem recursos para cálculos de problemas de controle, processamento digital de sinais entre muitos outros.

Diferencial_sobrep

Figura 8: Detalhe da sobreposição das diferenciais calculadas

Nesse artigo técnico foram desenvolvidos métodos numéricos para o cálculo de integrais e diferenciais, típicas para uso em controle digital por PID. Esses métodos foram simulados no Scilab e foi mostrado o funcionamento correto das diversas aproximações e uma melhor precisão à medida que se utiliza mais pontos para o cálculo dos resultados. As equações desenvolvidas são muito adequadas para a utilização em microprocessadores pela sua simplicidade. Experimente usá-las.

Licença Creative Commons

Esta obra, “ PID digital – Método de cálculo numérico“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-Não Comercial-CompartilhaIgual 3.0 Não Adaptada.

Caro(a) Colega,

a minha experiência profissional é baseada no desenvolvimento de software básico (firmware) para microprocessadores, microcontroladores de 8 ou 16 bits e DSPs (Digital Signal Processors). Qual o sistema operacional que costumo utilizar? Nenhum desses tradicionais. Na verdade, em geral desenvolvo os sistemas para os meus projetos. Para os tipos de processadores citados dificilmente tem algum sistema operacional que seja enxuto e eficiente.  Afinal, processadores de 8 ou 16  bits são relativamente lentos, possuem pouca memória interna, mas têm grandes vantagens, dependendo da aplicação em que são utilizados: são simples, baratos, diminutos no seu tamanho físico e extremamente eficientes para pequenas aplicações. Tem algumas versões de microcontroladores PIC, por exemplo,  com encapsulamento de 8 pinos.

Retornando ao assunto do sistema operacional, no meu caso, de certa forma, um loop infinito é um sistema operacional de alta eficiência se associado a outros recursos dos processadores, tais como temporizações e interrupções por hardware. É uma maneira de se unir as vantagens citadas dos microcontroladores e conseguir um desempenho em tempo real adequado para algumas aplicações.

Quando se fala de software de tempo real, deve-se lembrar que isso não implica na necessidade de se realizar as tarefas no menor tempo possível, mas sim em que a velocidade de processamento, monitoramento e controle do seu projeto deve ser suficientemente veloz  e compatível com a velocidade de resposta do sistema para o qual ele foi projetado. Existem processos, principalmente os térmicos,  que levam horas ou até dias para progredirem ou mudarem de estado. Neste caso, não é necessário que o processador execute todo o seu programa em frações de segundos. Poderia até levar horas para isso, pois não afetaria o desempenho do sistema como um todo e ainda assim seria um sistema de tempo real.

Para poder ilustrar o que foi dito até aqui com um resultado prático e real do uso dessas boas práticas, vou apresentar rapidamente algumas características de um projeto que desenvolvi. Trata-se de um equipamento que faz uma varredura periódica em até 32 detectores de vazamento de combustíveis e cuja principal função é a proteção ambiental na medida em que previne a contaminação do solo de postos de combustíveis.

Algumas características do equipamento:

  • Permite a  reconfiguração sempre que necessário;
  • É capaz de detectar curto-circuitos ou rompimento dos cabos dos sensores;
  • Sinaliza a varredura por meio de LEDs;
  • Sinaliza falhas por meio de códigos apresentados em displays de 7 segmentos;
  • Gera um registro em memória não volátil a cada evento anormal, gravando a data e hora dessa ocorrência e a data/hora de quando o a ocorrência foi solucionada;
  • Quando solicitado, gera um relatório formatado para uma  impressora;
  • Gerencia um teclado;
  • Gerencia um relógio de tempo real;
  • Conecta-se em rede a um computador ou à internet para permitir um monitoramento remoto.

Tudo isso  e algumas coisinhas a mais, sendo executado num microcontrolador de 8 bits da família MCS-51, com clock de 4 MHz, 12 kBytes de memória EEPROM, 256 Bytes de RAM e  que custa em torno de R$ 20,00 no varejo.

O software foi todo escrito em C. Seu código fonte tem em torno de 8.000 linhas de programa.  É incrível? Mágica? Nem tanto…

Vale ressaltar que até hoje, 10 anos depois da primeira versão, tive que realizar apenas uma pequena correção no software e alterações decorrentes do upgrade do microprocessador para versões mais atualizadas.

Mas voltemos ao tema. Essas práticas funcionam muito bem se aplicadas a microcontroladores.  Pode ser que não sirva para você, se acaso você trabalha com um software de alto nível, Visual C por exemplo. Desenvolvo meus projetos de software na forma estruturada, aplicando práticas de encapsulamento de entradas e saídas, essas típicas de software orientado a objetos.

O que é um software estruturado?

Para quem não conhece, discorrendo resumidamente sobre o assunto, um software estruturado é organizado em blocos, o fluxo é muito bem definido e tem regras rígidas  para a recursão. Em princípio cada bloco tem uma entrada e uma saída e não se utiliza o recurso do “GOTO” em hipótese alguma, pois ele destrói e corrompe qualquer organização que se tenha realizado no software. A linguagem C, por exemplo, é na sua essência uma linguagem computacional com características de software estruturado. Difícil, não é? A seguir vou explicar e fundamentar porque se deve dar preferência à programação estruturada no caso de microcontroladores e alguns DSPs.

Representação gráfica de um programa estruturado.

Fonte: DEVMEDIA

Porque não usar programação orientada a objeto?

O principal motivo para não usar programação orientada a objeto é o tamanho do código gerado. Outro motivo é o fato de se  perder um pouco o controle de como o código é gerado e de como a memória é utilizada. Isso complica muito quando é necessário otimizar o código principalmente quando a velocidade de processamento é crítica. Quando se utiliza a linguagem C, depois de algum tempo você aprende a escrever seu código de forma a favorecer a sua otimização. Na hora do aperto, dá até para inserir inline pequenos trechos de código em Assembly (Não é recomendado, mas às vezes não há alternativa…).  Isso te dá o controle quase total sobre o que vai ser gerado no final, o quanto de memória vai ser utilizado, como vai ser utilizada essa memória, etc.

Reconheço as qualidades do software orientado a objetos, tais como a portabilidade, velocidade de desenvolvimento de código e, facilidade de manutenção , até porque aproveitei o encapsulamento de dados, típico de programação orientada a objetos,  para melhorar o software estruturado. Apenas afirmo que para o uso em microprocessadores de 8 e 16 bits, frequentemente não é a melhor alternativa. Acredito também, que com o avanço das tecnologias dos compiladores de linguagens orientadas a objeto, pode ser apenas uma questão de tempo para que esses compiladores se tornem mais eficientes e produzam resultados melhores que os compiladores de linguagens estruturadas.

O que é encapsulamento de entradas e saídas?

É um método  de organização do software que determina regras rígidas para o acesso aos parâmetros ou recursos de um determinado periférico. O acesso tem que ser realizado sempre por meio de um mesmo conjunto de rotinas. Por exemplo: suponhamos que você tenha previsto a utilização de um canal de comunicação serial no seu projeto e que haja a necessidade de se utilizar uma rotina para transmitir dados e outra para receber dados. Se o canal de comunicação for organizado de forma encapsulada, qualquer acesso ao canal serial deverá obrigatoriamente se dar por meio dessas mesmas rotinas de qualquer ponto do seu programa. Assemelha-se muito ao conceito de objeto e métodos associados, conforme definido na programação orientada a objetos, não é mesmo? A diferença é que esse objeto e os métodos associados não são genéricos, mas feitos sob medida para essa aplicação. Por isso que ela tem todas as vantagens decorrentes dessa forma de organização aliada às vantagens de ser específica: enxuta, veloz entre outras.

Vale ressaltar que a aplicação desse método a um programa estruturado deve ser realizada por iniciativa e disciplina do desenvolvedor, uma vez que os compiladores de linguagens estruturadas não oferecem ferramentas ou facilidades para fazê-lo.

Qual a vantagem dessa forma de organização?

Uma vez depuradas as rotinas que administram o seu periférico, você não precisa mais se preocupar com elas ou com o funcionamento dele. Se acaso for detectada alguma falha nesse conjunto, você corrige essas rotinas e todo o seu programa volta a funcionar corretamente.

Para ilustrar o que foi dito até aqui, no final desse artigo, disponibilizei o código de duas rotinas que escrevi para acessar uma E2PROM serial. Essas rotinas têm outros elementos recomendados de boas práticas, que discutiremos nos próximos artigos.

Talvez o jovem profissional, já habituado a utilizar ferramentas de produção de software orientadas a objeto ou de alto nível, não perceba a diferença. Isso porque as ferramentas orientadas a objeto já encapsulam os dados naturalmente. É que é muito comum o programador de software básico ou firmware, por pressa ou preguiça, não organizar o programa desse jeito e acessar diretamente o seu periférico de diversos pontos do seu programa.  É uma grande tentação fazer isso e confesso, que se o programa é pequeno, talvez até seja uma solução rápida. Quando funciona bem, que maravilha!!!!! Mas quando dá “pau” …. É um inferno!!! Fica quase impossível encontrar o problema no código e evitar que a correção do problema eventualmente mal planejada se propague de forma negativa e gere  outros defeitos imprevistos em outras partes do código.

Nos próximos artigos são abordadas algumas sugestões de como proceder para dar nomes a rotinas, variáveis e constantes de forma a aumentar a sua eficiência na produção e manutenção do seu software. Vou comentar um pouco sobre a notação húngara. Parece grego?

Também é apresentada uma ferramenta de produtividade pouco conhecida, que porém, para mim, foi um divisor de águas. Não sei como eu conseguia programar antes de utilizar essa ferramenta. Minha velocidade de produção multiplicou-se.

Confira:

Abraço!

Henrique

consulte sempre um engenheiro eletrônico

 

Licença Creative Commons
Esta obra, “Boas práticas para o desenvolvimento de software – Algumas ideias de como organizar o seu software – I“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 3.0 Não Adaptada.

=================================================================================================

Rotina para escrever na E2PROM:

Rotina em C para escrita na E2PROM

Rotina em C para escrita na E2PROM – Parte 1

Rotina em C para escrita na E2PROM - segunda parte

Rotina em C para escrita na E2PROM – Parte 2

=============================================================================

Rotina para Leitura da E2PROM

Rotina em C para leitura de uma E2PROM - parte 1

Rotina em C para leitura de uma E2PROM – parte 1
Rotina em C para leitura de uma E2PROM - parte 2

Rotina em C para leitura de uma E2PROM – Parte 2

Rotina em C para leitura de uma E2PROM - parte 3

Rotina em C para leitura de uma E2PROM – Parte 3