Posts Tagged “sistemas embarcados”
Este artigo pretende conversar diretamente com o programador, revelando algumas boas práticas que podem auxiliá-los no desenvolvimento e manutenção do código. Apesar de genérico à linguagem C, os tópicos abordados são frutos da experiência como desenvolvedor de sistemas embarcados, sendo estes o nosso foco principal.
Mantendo Bonito
A linguagem C, por definição, não exige que você escreva o programa seguindo regras que o tornem esteticamente agradável de ver (e ler). Nada impede você de escrever algo como:
/*#define ppp xp
* /## define */#define x = #define zim void /*\**\*\***//*/ #denife $/*/ #define p () #define iu for( /*\**\*\***//*/ #defie $##def x^3printdf/*/ #define xyz < /*/* 8/ *******/ #define o ;} #define v "\na l o m u n d o " int s (zim) { char b x 1; iu b x 9;\ b xyz 21; b++){ printf( v ) o /*}}}*/} zim main( zim ) { s p o
Exceto, claro, o bom senso. De uma maneira geral, o código bonito e organizado é sempre mais fácil de ler.
Indentação & Espaços
Utilizar indentação no código é algo essencial para a legibilidade. O tamanho do espaçamento pode variar, mas o importante é sempre manter blocos aninhados respeitando os níveis de indentação das estruturas condicionais e laços de repetição. De uma forma geral, o nível de indentação muda sempre após o início de uma função, estrutura condicional ou laço:
void exemplo ( void ) { if ( a > 5 ) { b += 3; for ( i=0; i<5; i++ ) { z++; x--; } } }
No exemplo acima foram utilizados quatro espaços entres os blocos. Você pode configurar o seu editor de texto preferido para que a tecla TAB substitua o caracter invisível de tabulação por estes espaços, é bastante útil. Evite espaçamentos muito curtos, como apenas um espaço, ou muito longos.
Além da indentação, que você já deve estar habituado, outro recurso que facilita a legibilidade é a utilização de espaços horizontais e verticais. Aumentar o número de linhas e espaços não vai, obviamente, aumentar o tamanho do binário compilado. Ao invés de escrever uma sentença condicional como:
if (a<20 &&(c==5||d==6)) { }
prefira algo assim:
if ( (a < 20) && ( (c==5) || (d==6) ) ) { }
que é visivelmente mais agradável de avaliar. Separar as sentenças por parênteses também evita algum erro de precedência que você possa cometer ao digitar as expressões, reduzindo o tempo de depuração no futuro.
Laços complexos também podem ser quebrados em várias linhas, com o mesmo objetivo:
for ( cont = 0, aux = 3; cont < 100; cont++, aux+=2 ) {
a = c + b; d = e - f; }
Quando falo em legibilidade do código, lembro-me que existe um operador na linguagem C, o ternário, que utilizado em excesso pode tornar as expressões pouco legíveis aos olhos menos treinados. De uma forma geral eu evito utilizar o operador ternário, mesmo em sentenças simples. A operação
aux = ( cont < aux ) ? cont : cont * -1;
poderia ser escrita, sem nenhum prejuízo, como:
if ( cont < aux ) aux = cont; else aux = cont * -1;
Mas se você gosta do operador ternário, uma opção para melhorar a legibilidade é separar as sentenças por linhas indentadas. A mesma expressão poderia ser escrita assim:
aux = ( cont < aux ) ? cont : cont * -1;
Isto será especialmente útil caso você utilize o operador ternário de forma encadeada. Este código:
a = ( b < z ) ? x : ( i > x ) ? i : ++i;
é certamente mais legível que este:
a = ( b < z ) ? x : ( i > x ) ? i : ++i;
– ++ e —
Evite agregar mais de um ++ ou — na mesma sentença. Com o mesmo intuito, evite atribuir ao resultado da operação operadores que utilizaram o incremento ou decremento na expressão.
Portando, expressões como:
z = a++ + ++b;
ou
a[b] = b++;
devem ser evitadas e substituidas por cláusulas que inibam, ou pelo menos minimizem, interpretações errôneas.
Números Mágicos
As constantes são suas amigas, e os “#define” uma das mais ricas formas de melhorar a legibilidade do código. “Números Mágicos” são valores, inteiros ou não, que aparecem no código e que são constantes, mas não foram declarados como tais. Fazer isso prejudica a organização e dificulta a manutenção.
Ao invés de ter condições como:
while ( tensao_bateria < 30 ) { if ( potencia_transmissor > 50 ) diminua_potencia(); else { desliga_radio(); while ( tensao_bateria < 30 ) { /* espera bateria carregar */ } liga_radio(); } }
substitua os inteiros por constantes com nomes adequados, como LIMITE_BATERIA_CRITICA e POTENCIA_MINIMA_TRANSMISSOR. Além de melhorar a organização facilita a manutenção, em caso de alterações nestas constantes.
Loops “Parados”
Utilizando o exemplo anterior, observe que escrevemos
while ( tensao_bateria < 30 ) { /* espera bateria carregar */ }
ao invés de simplesmente
while ( tensao_bateria < 30 );
A primeira forma deixa explícita a nossa intenção, ao contrário da segunda, que poderia ser confundida com um erro do programador ou causar problemas posteriormente, caso o “;” fosse erroneamente removido (possivelmente sem erro na compilação).
Convenções
Não importa exatamente quais convenções você utiliza, o importante é que você defina uma (própria ou não) e siga-a da forma mais rigorosa possível. Preferencialmente estas convenções devem ser descritas em um documento simples, que permita consultas rápidas sempre que necessário. Exemplificarei algumas abaixo que são bastante populares, mas você deve adaptá-las às suas necessidades.
- Constantes: para as constantes utilize sempre letras maiúsculas. Desta forma será fácil distingui-la entre as variáveis. Ex.: #define LIMITE_TEMPERATURA 40 #define BATERIA_BAIXA 30
– Variáveis: mais importante que as convenções, uma regra básica: utilize nomes claros para as variáveis, abreviando apenas o que é bastante conhecido ou óbvio. Programadores são, em sua maioria, ágeis no teclado. Portanto, abreviar pressaoMotorEsquerdo para preMotE provavemente não vai economizar muito do seu tempo durante o desenvolvimento e certamente dificultará a leitura do código.
Existem algumas convenções mais antigas como a Notação Húngara ou mais modernas, como a Notação Camelo, muito utilizada na programação orientada a objetos. Usualmente, em C, é bastante comum todas as variáveis serem escritas com letras minúsculas e/ou com o “_” como separador de palavras. Sendo assim, variáveis como velocidademaxima ou velocidade_maxima são bastante comuns, sendo esta última forma mais freqüente.
– Tipos de Variáveis: uma das grandes vantagens da linguagem C é a portabilidade entre arquiteturas. No entanto, alguns tipos de variáveis possuem comprimento variável dependendo da arquitetura e compilador, o que pode ocasionar problemas no software, como overflow ou erros de conversões. Por exemplo, o tipo inteiro (int) normalmente representa o tamanho da palavra do processador, nos processadores modernos de 32 e 64 bit e compiladores como o GCC. Mas isso não é necessariamente uma regra; no compilador HITECH para microcontroladores PIC de 8 bit, por exemplo, o inteiro possui 16 bit.
Sendo assim, defina tipos claros e utilize-os, como uint8 para inteiros não sinalizados de 8 bit ou int16 para inteiros sinalizados de 16 bit.
Também seja atencioso ao declarar ponteiros. Uma declaração como:
char* s, t, u;
não está errada, mas provavelmente não é o que você deseja, já que t e u não serão declarados como ponteiros. Sendo assim, prefira esta forma para declarar os ponteiros sem margem para erros:
char *s, *t, *u;
Conclusão
Nossa intenção neste artigo foi abordar algumas técnicas que podem ajudá-lo a melhorar a legibilidade do seu código. Apesar de existirem vários outros pontos que podem ser abordados neste tópico, de uma forma geral, escrevendo um código organizado, bonito e bem comentado existe uma grande probabilidade do seu código tornar-se bastante legível, quesito que traduz-se em agilidade e produtividade em todas as fases do ciclo de vida do software.
Roberto Alcântara
roberto@eletronica.org
Recentemente recebi gratuitamente uma encomenda com 4 livros da editora O’Reilly para que eu fizesse as resenhas desses livros.
Antes de tudo eu devo avisar que essa resenha não pertence à série de resenhas que eu vinha fazendo, e que devo continuar em breve, à qual eu dei o nome de “Leitura Obrigatória”.
O livro de hoje é o Programming Embedded Systems, Second Edition. Eu já estou quase terminando a leitura deste livro e já me sinto à vontade para recomendá-lo por aqui porque eu realmente me empolguei com o material.
Como muitos já sabem eu voltei a praticar o antigo hobby de montar dispositivos eletrônicos, e desde que eu havia parado de brincar com essas coisas muita coisa mudou. Hoje em dia é muito comum encontrar microprocessadores e microcontroladores em vários projetos, e trabalhar com esses componentes exige um conhecimento que mora entre a eletrônica “pura” e a informática.
![](https://images-na.ssl-images-amazon.com/images/I/51-VfiRCWrL._SX372_BO1,204,203,200_.jpg)
Programming Embedded Systems
Como eu já tenho bons conhecimentos de informática e meus conhecimentos de eletrônica “pura” estavam evoluindo com a prática do meu antigo hobby, estava faltando construir a ponte que iria unir essas duas áreas do conhecimento.
Na mesma época recebi uma proposta da O’Reilly para fazer resenhas dos livros de Python deles e aproveitei para pedir alguns títulos que tratavam de dispositivos embarcados. Recebi este livro juntamente com outros 3 de Python (aguardem resenhas) e comecei a lê-lo.
O livro tem foco prático como em quase todos os títulos da editora O’Reilly. Os autores realmente irão desenvolver o assunto em cima de uma plataforma real de desenvolvimento que usa um processador ARM XScale e irão conduzir o leitor desde o ponto onde a gente faz um LED piscar até o momento onde desenvolvemos aplicações reais com RTOS e Linux.
O livro fala sobre device drivers, interrupções, registradores, memória e sobre como gerenciar e desenvolver software em C (gcc) para usar todas essas funcionalidades.
Vale destacar que esse livro fica exatamente na fronteira entre um livro de nível básico e um livro avançado, ou seja, se você não entende nada de eletrônica e muito pouco de informática esse livro não irá lhe servir. Se você também já é um especialista no assunto pode achar o livro massante demais na primeira parte que trata de assuntos mais básicos.
O próximo passo agora é adquirir um kit de desenvolvimento parecido com esse que foi proposto no livro e começar a brincar. Eu tenho certeza que eu vou me divertir muito com esse tipo de coisa depois de ler este livro.
Para comprar: Programming Embedded Systems, Second Edition
Por Osvaldo Santana
Veja esta resenha também em www.pythonologia.org
Com foco exclusivo no hardware, John Catsoulis inicia o seu livro com conceitos básicos dos elementos da arquitetura de computadores como memórias, I/O, DMA, etc., antes de falar um pouco sobre software. A sua abordagem do tema é bastante simplória e antecede uma revisão sobre os conceitos básicos da eletricidade, como tensão e corrente, para posteriormente fazer uma breve passagem sobre os componentes básicos dos circuitos eletrônicos, como diodos, cristais, capacitores, circuitos RC, indutores, etc. Esta seção, sobre eletrônica básica, é perfeitamente descartável para usuários com um pouco de experiência no assunto.
Em seguida o autor dedica capítulos específicos que abordam áreas importantes dos projetos de sistemas embarcados, iniciando com as fontes de alimentação. Baseado na sua própria experiência, algumas dicas básicas sobre redução de ruídos e interferências são mostradas após descrever e exemplificar, através de circuitos, meia dúzia de componentes específicos para a regulação da alimentação, em 5Vcc e em 3.3Vcc.
No sexto capítulo nós temos uma série de dicas sobre ferramentas, soldagem e prototipagem de circuitos impressos para em seguida, no sétimo capítulo, iniciar uma abordagem mais detalhada sobre alguns protocolos de comunicação utilizados como SPI, I2C, portas seriais, IRDA, USB, CAN e Ethernet. Algumas dessas abordagens são mais resumidas que outras, mantendo o foco do autor principalmente nos protocolos que ele posteriormente vem a utilizar quando trata, no capítulo “Analógico”, sobre diversos sensores e circuitos de conversores analógicos digitais. Neste ponto vê-se mais uma vez o uso da experiência do autor ao selecionar sensores que estão presente de forma bastante ativa nos projetos de sistemas embarcados tradicionais.
Os últimos seis capítulos do livro são dedicados aos microcontroladores. Nestas mais de 100 páginas o autor não foca exclusivamente em um fabricante ou arquitetura. Ele prefere abordar algumas arquiteturas mais utilizadas no mercado para que o estudante possa adquirir uma bagagem de conhecimento que lhe seja útil para escolher o componente que melhor se adequa ao seu projeto. Os microcontroladores citados são os PIC e AVR, contando em seguida com textos sobre o 68HC11, MAXQ, 68k e DSPs. Neste espaço o autor detalha diversos parâmetros envolvidos nos projetos, como temporizações de clock, conexões de barramentos, lógica de decodificação de memórias, entre outros, sempre com a utilização de exemplo de circuitos reais que facilitam a absorção do conteúdo.
Muito dos conceitos descritos no decorrer do livro podem frustrar os mais experientes pela simplicidade, mas a abordagem é ideal para quem está tendo o primeiro contato com este mundo. Vale ressaltar também que, por não ser o foco do livro, muito pouco sobre software é abordado, obrigando os estudantes a procurarem outra referência sobre o tema. Enfim, Designing Embedded Hardware é um livro ideal para quem está começando no mundo dos projetos de sistemas embarcados, mas não recomendado para usuários que já desenvolveram projetos de médio porte.
Para comprar (30% de desconto para os membros Eletronica.org): Loja Internacional da O’Reilly. Para comprar no Brasil: Livraria Cultura.
Não existe, até o momento, edição em português deste livro.
Jack W. Crenshaw, especialista em desenvolvimento de sistemas industriais e aeroespaciais, consegue em seu livro Math Toolkit for Real-Time Programming, de forma muito clara e objetiva, apresentar alguns dos fundamentos matemáticos essenciais para qualquer desenvolvedor de sistemas, em especial aqueles que trabalham com sistemas embarcados em tempo real. Eu iria além: se os seus processadores possuem recursos limitados, leia este livro.
Elementos matemáticos fundamentais, como raiz quadrada, exponenciais, logarítmos, seno, cosseno, tangente e suas variantes, e os fundamentos do cálculo numérico são revisados teoricamente e analisados através de uma abordagem prática, com exemplos de algorítmos com diferentes estratégias de cálculos, priorizando precisão e velocidade.
Outros temas, como ponto flutuante, constantes, erros, série de Taylor, transformada Z, são tratados em capítulos dedicados ou como subtema em um capítulo maior.
No final do livro, uma pequena biblioteca em C++ com funções estudadas no livro e um CD-ROM contendo as bibliotecas e todos os exemplos utilizados ajudam ainda mais o desenvolvedor em seus estudos.
Enfim, leitura fortemente recomendada se você se encaixa no perfil descrito no início ou se é um entusiasta da área. Como diz o autor, “Se você está procurando um livro sobre os últimos métodos para escrever Applets Java ou aprender como criar seus próprios controles VBx, devolva o livro e pegue o seu dinheiro de volta”.
Infelismente não existe uma versão em português do livro. Dois locais onde você pode encontrá-lo: Livraria Cultura e Amazon.
Por Roberto Alcântara
Não sendo um livro introdutório sobre Linux ou sistemas embarcados, Building Embedded Linux Systems é voltado para desenvolvedores que já possuem alguma familiaridade com sistemas Linux, mas que desejam se aprofundar nos detalhes necessários para o desenvolvimento de aplicações embarcadas ou distribuições extremamente personalizadas. Os tópicos abordados vão desde conceitos básicos sobre os tipos de hosts e arquiteturas suportadas até o ajuste do bootloader, rede e ferramentas de debug.
Os capítulos que tratam da preparação do kernel, das bibliotecas, dos utilitários e dos compiladores são bastante práticos, com uma vasta lista de comandos necessários em cada etapa para construir os binários, o que facilita bastante para os desenvolvedores que não estão habituados com estes procedimentos de compilação. São estes tópicos os mais numerosos, mas sempre que algum detalhe da estrutura do kernel é necessária para o entendimento do texto este é devidamente tratado como, por exemplo, o capítulo sobre dispositivos de armazenamento precedendo a configuração e ajuste do sistema de arquivos.
Em suma, este livro é voltado para o desenvolvedor que pretende conhecer como selecionar, configurar e empacotar um sistema Linux para uma plataforma específica, criando um sistema de arquivos completo voltado para as suas necessidades, fazendo-o iniciar corretamente e depurá-lo. Porém, não é intenção do autor abordar detalhes da estrutura do kernel, teóricas ou práticas, que permitam ao desenvolvedor intervir nas estruturas de baixo nível do sistema para, por exemplo, portar o sistema para uma nova arquitetura. Se este é o seu foco, esta não é a literatura correta, mas se o seu objetivo é condizente com o do livro esta é uma obra bastante recomendada pela riqueza de detalhes e qualidade do texto.
![]() |
Building Embedded Linux SystemsKarim Yaghmour
ISBN 0-596-00222-X 416 Páginas – Editora O’Reilly Você pode encontrá-lo na Loja Internacional da O’Reilly (com desconto¹ de 35% para membros do Eletronica.org) e também na Livraria Tempo Real eLivraria Cultura. ¹ Para verificar como proceder clique aqui. |
Roberto Alcântara
roberto@eletronica.org