Você está na página 1de 24

MICROPROCESSADORES

Fernando Esquírio Torres


Programação de
microcontroladores III
Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

„„ Caracterizar as linguagens de baixo nível.


„„ Descrever as linguagens de alto nível.
„„ Diferenciar linguagens de baixo e de alto nível.

Introdução
Para se comandar um sistema computacional que executa determinada
tarefa ou aplicação, utiliza-se um programa em linguagem de máquina,
a qual é constituída de 0 (zeros) e 1 (uns). No entanto, os programadores,
ao desenvolver os programas para comandar esses sistemas, não utilizam
diretamente uma linguagem de máquina. A partir deste contexto surgiu
a necessidade de criar linguagens de programação para dispositivos
computacionais, classificadas em baixo e alto nível.
Os microcontroladores são dispositivos eletrônicos dotados de uma
inteligência programável e possuem processador, memória e perifé-
ricos acoplados em um único circuito integrado, denominado chip.
A inteligência programável é possível por meio de uma linguagem de
programação. Desde sua criação, os microcontroladores são programados
com linguagem de baixo nível, consideradas mais próximas ao hardware,
e devido à evolução da tecnologia de fabricação, estes passaram a ser
programados por linguagem de alto nível, consideradas mais próximas
da linguagem humana.
Neste capítulo, caracterizaremos as linguagens de baixo e alto nível,
a partir de exemplos de linguagens para cada uma destas classificações.
Abordaremos, também, as linguagens utilizadas em microcontroladores,
como Assembly (linguagem de baixo nível) e a linguagem C (linguagem
de alto nível). Em seguida, você aprenderá a diferenciar esses dois tipos
de linguagem.
2 Programação de microcontroladores III

Caracterizar as linguagens de baixo nível


Antes do surgimento das linguagens de programação, os dispositivos com-
putacionais (calculadoras, relógios digitais, computadores, microcontrola-
dores etc.) eram programados por sinais elétricos (códigos de máquina) que
comandavam o fluxo de dados na CPU. Esse tipo de programação restringia
bastante a complexidade dos programas desenvolvidos e fazia parte da primeira
geração de linguagem de programação. Portanto, havia uma necessidade de
que as linguagens de programação evoluíssem, possibilitando diversificar as
aplicações e melhorar a complexidade dos programas desenvolvidos.
Segundo Pereira (2010), os primeiros microcontroladores eram progra-
mados com linguagem de programação de baixo nível. Uma linguagem de
programação é conhecida como linguagem de baixo nível por possuir pouco
ou nenhum nível de abstração do conjunto de instruções de uma arquitetura de
computador. O conjunto de comandos e funções desta linguagem está próximo
às instruções do processador. Este tipo de linguagem pode ser convertido em
código de máquina, sem a necessidade de um compilador ou interpretador,
como acontece nas linguagens de programação de alto nível. A linguagem de
programação de baixo nível mais utilizada na família de microcontroladores
PIC da Microchip é Assembly (PEREIRA, 2010).
As linguagens de programação de baixo nível são geralmente simples e
possuem um conjunto de instruções com dezenas e/ou centenas de comandos
e funções. No entanto, o desenvolvimento de programas nessas linguagens
é considerado bastante complexo, devido a diversas técnicas com as quais
o programador deve ter familiaridade. A linguagem de baixo nível é muito
útil nos dispositivos de pouca memória, pois os seus programas, por estarem
mais próximos dos códigos de máquina, ocupam menos espaço na memória
de programa do microcontrolador (SOUZA, 2003).

Linguagem de máquina
Segundo Souza (2003), o código de máquina é uma linguagem de baixo nível
cujas instruções são compostas por números binários (0 e 1) e podem ser
executadas diretamente na unidade central de processamento do computador.
A linguagem de máquina é estritamente numérica, o que torna sua execução
mais rápida, porém dificulta a construção de programas nesta linguagem.
A arquitetura dos microprocessadores MIPS, por exemplo, utiliza uma
linguagem de máquina com instruções de 32 bits, dividida em campos que
representam operações como adição, subtração, operandos, ou a localização
Programação de microcontroladores III 3

da próxima instrução (WEBER, 2012). A Figura 1 mostra um exemplo das


instruções LOAD e JUMP para essa arquitetura.

Figura 1. Instrução (a) LOAD e (b) JUMP para arquitetura MIPS.


Fonte: Adaptada de Weber (2012).

A Figura 1a mostra a instrução LOAD dividida nos campos op (operação,


6 bits); rs (operando registrador, 5 bits); rt (operando registrador, 5 bits) e
endereço ou valor imediato (16 bits). Essa instrução carrega (op) no registrador
8 (rt) o valor que está gravado 68 (endereço/valor imediato) posições de memó-
ria depois do endereço indicado pelo registrador 3 (rs). A Figura 1b mostra a
instrução JUMP dividida nos campos op (operação, 6 bits) e endereço-alvo (26
bits). Essa instrução salta para o endereço de memória 1024 (WEBER, 2012).

Assembly
Segundo Souza (2003), a linguagem Assembly faz parte da segunda geração
de linguagem de programação. Foi criada no final da década de 1940 e início
da década de 1950, possuindo forte relação entre seu conjunto de instruções
e os códigos de máquina de uma determinada arquitetura. Sendo assim, é
muito comum existirem pequenas diferenças entre a linguagem Assembly
de diferentes tipos de microcontroladores. Portanto, Assembly não é uma
linguagem de programação portátil.
Os nomes das instruções na linguagem Assembly são construídos por
mnemônicos, que são palavras (rótulos simbólicos) curtas(os) de fácil me-
morização e autoexplicativas na língua inglesa. Por exemplo, NOPE significa
sem operação (No OPEration), MOV significa mover (MOVe), ADD significa
somar (ADD), entre outras (PEREIRA, 2007). Antes de gravar na memória do
microcontrolador, esses códigos mnemônicos são convertidos em linguagem
de máquina por um programa utilitário denominado Assembler (montador) e
o código convertido executa diretamente no processador, como podemos ver
na Figura 2. A execução de um programa escrito na linguagem Assembly no
4 Programação de microcontroladores III

microcontrolador é geralmente rápida e ocupa menos espaço de memória, se


comparada com as linguagens de alto nível.

IDE de programação

Código em
Assembly
Conversão

Assembler
Gravação

Código de
máquina

Microcontrolador

Figura 2. Processo de conversão e gravação de


um código em Assembly no microcontrolador.
Fonte: Adaptada de Souza (2003).

Em muitos casos, o desenvolvimento de programas na linguagem Assembly


necessita de programadores experientes e consome, relativamente, mais tempo
para desenvolver programas mais complexos. Mesmo assim é importante
conhecer o conjunto de instruções do microcontrolador que você utilizará em
seus projetos, como os microcontroladores da família PIC18F. Dependendo
do nível de programação do desenvolvedor, será necessário mesclar uma
linguagem de alto nível com uma linguagem de baixo nível.
Segundo Pereira (2010), o microcontrolador PIC18 tem 75 instruções em
Assembly e possui arquitetura RISC (reduced instruction set computer, ou
computador com um conjunto reduzido de instruções). A arquitetura RISC
se diferencia da CISC (complex instruction set computer) na construção da
pilha de instruções. A RISC tem uma quantidade reduzida de instruções
e, em geral, os acessos à pilha de memória de instruções são atômicos.
A CISC permite um número maior de instruções mais complexas, mas precisa
Programação de microcontroladores III 5

de mais acessos à pilha de memória de instruções. Desse modo, a execução


das instruções em um sistema computacional RISC é mais rápida e acontece
diretamente no hardware. Além disso, dispositivos RISCs são mais simples
e mais baratos (TOKHEIM, 2013).
As instruções em Assembly são destinadas à movimentação de dados entre
os registradores e a memória do microcontrolador, podendo ser aritméticas,
lógicas, de teste e desvio etc. O Quadro 1 mostra as principais instruções de
movimentação de dados na linguagem Assembly para microcontroladores da
família PIC18 da Microchip.

Quadro 1. Instruções para movimentação de dados da linguagem Assembly

Instrução Operando Descrição Flags afetados

MOVLW k Carrega o registrador W nenhum


com o valor de k imediato.

MOVWF f, a Carrega o conteúdo de W nenhum


no registrador f indicado.

MOVF f, d, a Armazena o conteúdo do ZeN


registrador f no destino.

MOVFF f f, fd Carrega o registrador fd com nenhum


o conteúdo do registrador f f.

MOVLB k Carrega a constante k nenhum


imediata no registrador BSR.

LFSR f, k Carrega a constante k nenhum


imediata no registrador
FSRx especificado por f.

CLRF f, a Apaga (preenche com Z


zero) o registrador f
especificado ((f)=0).

SETF f, a “Seta” (preenche com nenhum


0xFF) o registrador f
especificado ((f)=0xFF).

BCF f, b, a Apaga o bit b do nenhum


registrador f.

(Continua)
6 Programação de microcontroladores III

(Continuação)

Quadro 1. Instruções para movimentação de dados da linguagem Assembly

Instrução Operando Descrição Flags afetados

BSF f, b, a “Seta” o bit b do nenhum


registrador f.

BTG f, b, a Inverte o estado do bit nenhum


b do registrador f.

SWAPF f, d, a Troca os nibbles do nenhum


registrador f e armazena
o resultado no destino
especificado por d.

Fonte: Adaptado de Pereira (2010).

Ao observarmos o Quadro 1, podemos notar que a maioria das instruções


em Assembly tem o operando a, que representa o banco de memória que
contém o registrador f. Por exemplo, a = 0 ou o símbolo ACCESS, indica para
se utilizar o banco de memória de acesso; e a = 1 ou o símbolo BANKED,
acessa o banco indicado pelo registrador BSR (Bank Select Register, seleção
do banco de registradores) do microcontrolador PIC18. Quando o operando
a não for indicado, o microcontrolador entende que deverá acessar o banco
de acesso (PEREIRA, 2010). A Figura 3 mostra um exemplo da linguagem
Assembly com instruções de movimentação de dados.

Figura 3. Exemplo de código com instruções de movimentação de dados em Assembly


no PIC18.
Fonte: Adaptada de Pereira (2010).
Programação de microcontroladores III 7

Na Figura 3, a instrução MOVWF copia o conteúdo do registrador de tra-


balho W para o endereço (primeiro operando) do banco de memória indicado
no segundo operando da instrução. A instrução CLRF apaga o conteúdo do
endereço de memória indicado por VA. A instrução SETF apaga o conteúdo do
endereço de memória indicado por VB. Na linguagem Assembly, o caractere
ponto-e-vírgula (;) indica o início de um comentário de linha. Os comentários
são interpretados como espaço em branco pelo montador, ao converter o código
Assembly para o código de máquina.
As instruções aritméticas realizam operações na unidade lógica aritmé-
tica (ULA) (PEREIRA, 2010). O Quadro 2 mostra as principais instruções
aritméticas na linguagem Assembly para microcontroladores da família PIC18
da Microchip.

Quadro 2. Instruções aritméticas da linguagem Assembly

Instrução Operando Descrição Flags afetados

ADDLW k Adição de W com a C, DC, Z, OV, N


constante imediata (W=W+k).

ADDWF f,d,a Adição de W com o conteúdo C, DC, Z, OV, N


do registrador f. O resultado
é armazenado no destino
indicado por d (d = W +(f)).

INCF f,d,a Incrementa (adiciona 1) o C, DC, Z, OV, N


conteúdo do registrador f
especificado e armazena
o resultado no destino
indicado (W ou o
próprio registrador f).

SUBLW k Subtração de W da constante C, DC, Z, OV, N


imediata k (W=k-W).

SUBWF f,d,a Subtração de W do conteúdo C, DC, Z, OV, N


do registrador f indicado.

DECF f,d,a Decrementa (subtrai 1) C, DC, Z, OV, N


o conteúdo.
(Continua)
8 Programação de microcontroladores III

(Continuação)

Quadro 2. Instruções aritméticas da linguagem Assembly

Instrução Operando Descrição Flags afetados

MULLW k Multiplica o conteúdo nenhum


de W pela constante
imediata k e armazena o
resultado nos registradores
PRODH e PRODL.

MULWF f,a Multiplica o conteúdo nenhum


de W pelo conteúdo do
registrador indicado por f.
O resultado é armazenado
nos registradores
PRODH e PRODL.

NEGF f,a Negação aritmética do C, DC, Z, OV, N


conteúdo do registrador f.

Fonte: Adaptado de Pereira (2010).

A Figura 4 mostra um exemplo na linguagem Assembly com instruções


aritméticas.

Figura 4. Exemplo de código com instruções aritméticas em Assembly


no PIC18.
Fonte: Adaptada de Pereira (2010).

Na Figura 4, a instrução MOVLW copia o valor 0x0A para o registrador W;


a instrução ADDLW soma o valor do operando ao registrador W e o resultado
é armazenado em W; e a instrução SUBLW subtrai o conteúdo de W do valor
indicado pelo operando (PEREIRA, 2010).
Programação de microcontroladores III 9

As instruções lógicas realizam operações lógicas booleanas (and, or, xor e


not) (PEREIRA, 2010). O Quadro 3 mostra as principais instruções lógicas na
linguagem Assembly para microcontroladores da família PIC18 da Microchip.

Quadro 3. Instruções lógicas da linguagem Assembly

Instrução Operando Descrição Flags afetados

ANDLW k Operação lógica E entre o ZeN


conteúdo do registrador
W e a constante imediata
k (W = W E k).

ANDWF f,d,a Operação lógica E entre o ZeN


conteúdo do registrador
W e o conteúdo do
registrador f. O resultado é
armazenado no registrador
de destino d (d = W E f).

IORLW k Operação lógica OU ZeN


entre o conteúdo do
registrador W e a constante
imediata k (W = W E k).

IORWF f,d,a Operação lógica OU entre ZeN


o conteúdo do registrador
W e o conteúdo do
registrador f. O resultado é
armazenado no registrador
de destino d (d = W OU f).

XORLW k Operação lógica OU exclusivo ZeN


entre o conteúdo do
registrador W e a constante
imediata k (W = W XOR k).

XORWF f,d,a Operação lógica OU exclusivo ZeN


entre o conteúdo do
registrador W e o conteúdo
do registrador f. O resultado
é armazenado no registrador
de destino d (d = W XOR f).
(Continua)
10 Programação de microcontroladores III

(Continuação)

Quadro 3. Instruções lógicas da linguagem Assembly

Instrução Operando Descrição Flags afetados

COMF f,d,a Operação lógica NÃO ZeN


com o conteúdo do
registrador f. O resultado é
armazenado no registrador
de destino d (d = NÃO f).

RLCF f,d,a Desloca o conteúdo do ZeN


registrador f um bit para a
esquerda (pela flag carry). O
resultado é armazenado no
registrador de destino d.

RRCF f,d,a Desloca o conteúdo do ZeN


registrador f um bit para a
direita (pela flag carry). O
resultado é armazenado no
registrador de destino d.

Fonte: Adaptado de Pereira (2010).

A Figura 5 mostra um exemplo de sequência de instruções lógicas na


linguagem Assembly. A instrução ANDLW 0x1C realiza a operação lógica
booleana E entre o registrador W e a máscara 0x1C, e o resultado é arma-
zenado no registrador W. A instrução ANDLW PORTB realiza a operação
lógica booleana E entre o registrador W e o registrador PORTB, e o resultado
é armazenado no registrador W (SOUZA, 2003).

Figura 5. Exemplo de código com instruções lógicas em Assembly no PIC18.


Fonte: Adaptada de Pereira (2010).
Programação de microcontroladores III 11

As instruções de teste e desvio realizam desvio incondicionais, condi-


cionais, com endereçamento absoluto e com endereçamento relativo. Essas
instruções permitem fazer desvios, comparação, teste de bit, incremento e
desvio, decremento e desvio, chamada e retorno de sub-rotina, entre outras
(PEREIRA, 2010). O Quadro 4 mostra as principais instruções de teste e
desvio na linguagem Assembly para microcontroladores da família PIC18 da
Microchip.

Quadro 4. Instruções de teste e desvio da linguagem Assembly

Instrução Operando Descrição Flags afetados

GOTO end Desvio absoluto incondicional nenhum


para o endereço indicado
pelo operando end.

BRA end Desvio relativo incondicional nenhum


para o endereço indicado
pelo operando end.

BZ end Desvia para o endereço nenhum


especificado indicado pelo
operando end, se o flag
Z do registrador STATUS
estiver “setado” (Z=1).

BNZ end Desvia para o endereço nenhum


especificado indicado por
pelo operando end, se o
flag Z do registrador STATUS
estiver zerado (Z=0).

BC end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag C do registrador
STATUS estiver “setado” (C=0).

BNC end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag C do registrador
STATUS estiver zerado (C=1).

(Continua)
12 Programação de microcontroladores III

(Continuação)

Quadro 4. Instruções de teste e desvio da linguagem Assembly

Instrução Operando Descrição Flags afetados

BN end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag N do registrador
STATUS estiver “setado” (N=1).

BNN end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag N do registrador
STATUS estiver zerado (N=0).

BOV end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag OV do registrador
STATUS estiver “setado” (OV=1).

BNOV end Desvia para o endereço nenhum


indicado pelo operando end,
se o flag OV do registrador
STATUS estiver zerado (OV=0).

CPFSEQ f,a Compara o registrador nenhum


W com o conteúdo do
registrador f e salta a
próxima instrução, se f=W.

CPFSGT f,a Compara o registrador nenhum


W com o conteúdo do
registrador f e salta a próxima
instrução, se f > W.

CPFSLT f,a Compara o registrador nenhum


W com o conteúdo do
registrador f e salta a próxima
instrução, se f < W.

TSTFSZ f,a Testa o registrado f e salta nenhum


a próxima instrução, se
seu conteúdo for zero.

DECFSZ f,a Decrementa o conteúdo nenhum


do registrador f e salta
a próxima instrução, se
o conteúdo for zero.

(Continua)
Programação de microcontroladores III 13

(Continuação)

Quadro 4. Instruções de teste e desvio da linguagem Assembly

Instrução Operando Descrição Flags afetados

DCFSNZ f,a Decrementa o conteúdo do nenhum


registrador f e salta a próxima
instrução, se o conteúdo
for diferente de zero.

INCFSZ f,a Incrementa o conteúdo nenhum


do registrador f e salta
a próxima instrução se
o conteúdo for zero.

INFSNZ f,a Incrementa o conteúdo do nenhum


registrador f e salta a próxima
instrução, se o conteúdo
for diferente de zero.

BTFSC f,b,a Testa o bit indicado pelo nenhum


operando b e salta a próxima
instrução, se ele estiver zerado.

BTFSS f,b,a Testa o bit indicado nenhum


pelo operando b e salta
a próxima instrução, se
ele estiver “setado”.

CALL end,s Chamada de sub-rotina no nenhum


endereço indicado pelo
operando end. Opcionalmente
(se s=1) os registradores W,
STATUS e BSR são salvos em
registradores especiais.

RCALL end Chamada de sub-rotina nenhum


no endereço indicado
pelo operando end.

RETLW k Retorno de sub-rotina e a nenhum


constante k é armazenada
no registrador W.
(Continua)
14 Programação de microcontroladores III

(Continuação)

Quadro 4. Instruções de teste e desvio da linguagem Assembly

Instrução Operando Descrição Flags afetados

RETURN s Retorno de sub-rotina. nenhum


Opcionalmente (se s=1) os
registradores W, STATUS
e BSR são restaurados
com o valor salvo em
registradores especiais.

RETFIE s Retorno de interrupção (o nenhum


flag GIE/GIEH/GIEL deve
estar “setado”, habilitando as
interrupções). Opcionalmente
(se s=1) os registradores W,
STATUS e BSR são salvos em
registradores “sombra”.

POP - O conteúdo do apontador nenhum


do topo da pilha (STKPTR)
é decrementado em um,
descartando o último
endereço no topo da pilha.

PUSH - Endereço da próxima nenhum


instrução (PC+2) é salvo
na pilha e o apontador do
topo da pilha (STKPTR) é
incrementado em um.

Fonte: Adaptado de Pereira (2010).

A Figura 6 mostra um exemplo de sequência de instruções de teste e


desvio na linguagem Assembly na construção de laços de repetição e desvio
condicionais (PEREIRA, 2010).
Programação de microcontroladores III 15

Figura 6. Exemplo de código com instruções de teste e desvio em Assembly no PIC18.


Fonte: Adaptada de Pereira (2010).

Os exemplos da Figura 6 mostram como fazer laços de repetição e testes


lógicos condicionais. O primeiro laço com o rótulo repete, na linha 1,
executa a instrução de teste lógico condicional incfsz REG,f várias
vezes até que conteúdo do registrado f seja igual a zero. O segundo laço com
o rótulo repete2, na linha 6, é uma outra maneira de fazer o mesmo laço
de repetição, porém com a instrução do teste lógico condicional diferente.

Descrever as linguagens de alto nível


Devido à evolução dos processos de fabricação de dispositivos microcon-
trolados e a redução do custo de manufatura e de componentes eletrônicos,
tornou-se possível produzir microcontroladores com maior quantidade de
memória, reduzindo, assim, a limitação de hardware físico. Portanto, os
programas passaram a poder ocupar mais espaço de memória. Isso possibi-
litou que os microcontroladores pudessem ser programados com linguagens
de alto nível, como as linguagens C, C++, Java, Python, PHP, entre outras.
Como o foco deste capítulo é a programação de microcontroladores, será
detalhada apenas a linguagem C, que é a linguagem de alto nível utilizada
para programar microcontroladores (PEREIRA, 2007). As outras linguagens
citadas são utilizadas para o desenvolvimento de programas para desktops,
computadores pessoais etc.
Além disso, devido ao desenvolvimento de linguagem de programação de
alto nível com a eficiência das de baixo nível e a melhoria dos compiladores
de linguagem de alto nível, foi possível otimizar o desenvolvimento da lógica
de programação para microcontroladores e o processo de tradução do código
em alto nível para o código de máquina.
16 Programação de microcontroladores III

Segundo Pinheiro (2012), a linguagem de alto nível possui um grande nível


de abstração do conjunto de instruções de uma arquitetura de computador e
está muito próxima da linguagem humana. Ela usa elementos de linguagem
natural e, desse modo, torna-se mais familiar para o programador. A primeira
linguagem de programação de alto nível desenvolvida para computadores foi a
Plankalkül, mas esta não foi utilizada em microcontroladores. Nos dispositivos
microcontrolados, atualmente, a linguagem de programação de alto nível
mais popular é a linguagem C, que está entre as cinco maiores linguagens de
programação do mundo, de acordo com o Spectrum Ranking do IEEE.
As linguagens de programação de alto nível têm uma etapa a mais no pro-
cesso de conversão de um código programado em alto nível para o código de
máquina, como vemos na Figura 7. Na primeira etapa, o código desenvolvido
por um programador em linguagem de alto nível é traduzido por um compilador
ou interpretador para uma linguagem de baixo nível intermediária, como a
linguagem Assembly. Em seguida, o código na linguagem Assembly é con-
vertido em linguagem de máquina, gravado na memória do microcontrolador
e executa diretamente no processador (WEBER, 2012).

IDE de programação

Código em linguagem
de alto nível
Tradução

Compilador ou
interpretador

Conversão

Assembler
Gravação

Código de
máquina

Microcontrolador

Figura 7. Processo de tradução e gravação de um código em


linguagem de alto nível no microcontrolador.
Fonte: Adaptada de Pereira (2010).
Programação de microcontroladores III 17

Compiladores e interpretadores são programas auxiliares que verificam a


sintaxe e a semântica do código programado. A diferença principal entre eles,
em computadores pessoais e notebooks, é que o compilador traduz o código
completo para então executá-lo, enquanto o interpretador traduz o código
em tempo de execução linha por linha, conforme o código roda (PINHEIRO,
2012). Em microcontroladores, os ambientes de programação (IDE, integra-
ted development environment), em sua maioria, utilizam compiladores para
traduzir o código em linguagem de alto nível para instruções em Assembler.

Linguagem de programação C e C++


A linguagem C, apesar de ser uma das mais antigas, é considerada uma lingua-
gem de alto nível robusta e eficiente. Além disso, a linguagem C é, atualmente,
a linguagem de programação de alto nível mais utilizada no desenvolvimento de
códigos para microcontroladores e, mesmo não sendo uma linguagem próxima
das instruções de uma arquitetura computacional, permite acessar e configurar
facilmente o hardware desses dispositivos microcontrolados programáveis.
A popularização da linguagem C na programação dos microcontroladores
permitiu diversificar o desenvolvimento de aplicações, diminuir o tempo
gasto na implementação de programas mais complexos, facilitou a leitura e o
entendimento do código programado, entre outras vantagens. Por outro lado,
um código em linguagem C ocupa mais espaço de memória e, no processo de
tradução e conversão, podem não ser tão otimizados, gerando códigos mais
lentos de serem executados.
Segundo Pereira (2007), a tendência entre programadores de escolher a
linguagem C para o desenvolvimento de seus códigos é natural, visto que na
linguagem C eles se preocupam mais com a programação da aplicação desejada
do que com as tarefas, como o controle e a localização das variáveis, opera-
ções matemáticas e lógicas, a verificação com bancos de memória e outras,
como acontece na linguagem Assembly. Isso se dá pelo fato de as instruções
da linguagem C serem baseada na língua inglesa e possuírem comandos
e/ou funções como if (se), for (para), while (enquanto), void (vazio),
int (inteiro), switch-case (troca-caso), entre outras.
O C++ é uma evolução da linguagem C que possibilita utilizar conceitos
de programação orientada a objetos como herança múltipla, classes abstratas,
objetos estáticos, métodos constantes, entre outros. É uma linguagem utili-
zada principalmente no desenvolvimento de soluções computacionais para
desktops e computadores pessoais, não sendo utilizada para a programação
de microcontroladores (PINHEIRO, 2012).
18 Programação de microcontroladores III

Os microcontroladores da família PIC possuem diversos compiladores que


permitem programa-los utilizando a linguagem C, como, por exemplo, o XC
da Microchip, o CCS da Custom Computer Services, o mikroC da MikroE-
lektronika, entre outros. Uma dica muito útil para quem está iniciando em
programação de microcontroladores utilizando a linguagem C é escolher o
compilador mais familiar e com suporte técnico mais acessível, assim como
documentação com exemplos práticos. Neste capítulo, recomendamos utilizar
o compilador oficial do fabricante Microchip, o XC, pois a empresa tem uma
vasta documentação e application notes com diversos assuntos teóricos e
práticos de seus produtos. Além disso, a Microchip administra um fórum para
tirar dúvidas dos usuários de seus produtos oficiais (Microcontroladores PIC,
IDE MPLAB, compiladores XC, etc.).
A Figura 8 mostra um código na linguagem C para receber um número
digitado no teclado pelo usuário e exibir o valor digitado na tela novamente.

Figura 8. (a) Exemplo de um código em C e (b) saída produzida na execução do código.


Fonte: Adaptada de Pereira (2010).

A linha 1 do código mostrado na Figura 8a possui o comando #include


<stdio.h>, que adiciona os códigos da biblioteca padrão stdio.h ao seu
programa. Esta biblioteca é necessária para utilizar os comandos scanf e
printf. A função de entrada de dados scanf("%d", &x), na linha 6
da Figura 4a, lê um dado inteiro (indicado pelo comando de formatação %d),
digitado no teclado e armazenado na variável inteira x. A função de saída de
dados printf imprime na tela do computador a mensagem desejada. Na
linha 5 da Figura 8a, o comando printf("Digite um número: ")
imprime a mensagem de interação com o usuário e solicita que ele digite um
número inteiro (Figura 8b). O comando printf("O número digitado
Programação de microcontroladores III 19

é: %d\n", x), na linha 7 da Figura 8a, imprime a mensagem final com


o valor digitado (Figura 8b). O código de formatação \n indica a quebra de
linha e posiciona o cursor no início dessa nova linha (PINHEIRO, 2012).
O código mostrado na Figura 8a foi desenvolvido para ser executado em
computadores pessoais. Nos microcontroladores, esses comandos de entrada
e saída de dados não são muito utilizados, pois a maioria dos projetos micro-
controlados não utilizam teclado e tela.

Diferenciar linguagens de baixo e de alto nível


As linguagens de baixo e alto nível são importantes dentro do universo de
programação de microcontroladores. Cada uma possui vantagens e desvan-
tagens para os programadores no desenvolvimento de seus programas. Nesta
seção, você verá como pode diferenciar uma linguagem de alto nível de uma
linguagem de baixo nível, apontando as vantagens e desvantagens dessas
linguagens.
A principal característica para se diferenciar uma linguagem de baixo nível
de uma linguagem de alto nível é o fato de que as instruções da primeira são
formadas por mnemônicos curtos (ADD, SUB, MOV, CLR etc.), que repre-
sentam a ação e/ou comando a ser executado; enquanto, as instruções de uma
linguagem de alto nível possuem palavras semelhantes ou iguais à linguagem
humana, como a linguagem C, que como já vimos, é baseada na língua inglesa
e possui diversos comandos e funções (if, else, for, while, entre outros)
que representam palavras dessa língua (PEREIRA, 2010).
Entre as vantagens e as desvantagens destes tipos de linguagem de progra-
mação, pode-se citar a otimização e a velocidade de execução dos códigos e o
espaço ocupado na memória por eles. As linguagens de baixo nível permitem
que o programador desenvolva códigos mais otimizados (enxutos), porque suas
instruções têm pouca ou nenhuma abstração e, assim, estão mais próximas
da linguagem de máquina. Além disso, códigos mais otimizados ocupam
menos espaço de memória e são executados mais rapidamente pela CPU do
microcontrolador. Em contrapartida, a otimização das linguagens de alto nível
depende da qualidade e da eficiência do compilador. Desse modo, a tradução
do código em alto nível para a linguagem de baixo nível pode não ser bem
otimizada e, então, o código convertido para a linguagem de máquina pode
ocupar mais espaço de memória e ser executado de forma mais lenta pela CPU
do microcontrolador (PEREIRA, 2007).
20 Programação de microcontroladores III

Um segundo ponto a ser destacado é a possibilidade de controle do har-


dware programado. As linguagens de programação de baixo nível viabilizam
o controle de grande parte do hardware do microcontrolador, sendo possível
acessar e configurar a grande maioria dos registradores de função especial
do dispositivo, enquanto na linguagem de programação de alto nível existe
restrição de acesso e configuração de um conjunto de registradores de função
especial.
A linguagem de alto nível é mais amigável aos programadores e permite o
desenvolvimento mais rápido de programas mais complexos do que a linguagem
de baixo nível. Além disso, a linguagem de alto nível facilita a manutenção
de um código já implementado.
Por fim, a linguagem de alto nível C tem uma última vantagem em relação
à linguagem de baixo nível Assembly: a linguagem C é muito mais difundida
do que a Assembly, devido a sua grande popularidade entre programadores.
Sendo assim, torna-se mais fácil encontrar soluções e programas com exemplos
na linguagem C do que em Assembly.

Importância da linguagem de baixo nível no


remapeamento de periféricos nos
microcontroladores PIC
Apesar de os programadores atuais escolherem a linguagem de programação
C para desenvolver seus códigos e quase nunca precisarem trabalhar com
linguagens de baixo nível, não se deve descartar totalmente o aprendizado
da linguagem Assembly. Em programas mais complexos, que necessitam de
acesso ao hardware durante a execução do programa, muitas vezes é necessário
combinar parte do código em linguagem C com Assembly.
Alguns microcontroladores PIC possuem a funcionalidade particular que
possibilita o remapeamento de periféricos, permitindo a liberdade de asso-
ciar pinos de entrada e saída a múltiplos periféricos, flexibilizando, assim, a
construção do hardware. Desse modo, periféricos internos como UART, I2C,
SPI, interrupções externas, entre outros, podem ser associados (remapeados)
a qualquer pino do microcontrolador (PEREIRA, 2010). O remapeamento
pode ser feito de duas maneiras: uma única vez, no início do seu código, ou
diversas vezes, durante a execução do código. No primeiro caso, o remape-
amento pode ser feito utilizando apenas a linguagem de alto nível C. Já no
segundo caso, de remapeamentos múltiplos durante a execução do programa,
você precisará mesclar códigos em linguagem de baixo nível para permitir um
novo remapeamento dos periféricos com códigos em linguagem de alto nível.
Programação de microcontroladores III 21

PEREIRA, F. Microcontrolador PIC 18 detalhado: hardware e software. São Paulo: Érica,


2010. 304 p.
PEREIRA, F. Microcontroladores PIC: técnicas avançadas. 6. ed. São Paulo: Érica, 2007. 368 p.
PINHEIRO, F. A. C. Elementos de programação em C: em conformidade com o padrão
ISO/IEC 9899. Porto Alegre: Bookman, 2012. 548 p.
SOUZA, D. J. Desbravando o PIC: ampliado e atualizado para PIC16F628A. 6. ed. São
Paulo: Érica, 2003. 268 p.
TOKHEIM, R. Fundamentos de eletrônica digital: sistemas sequenciais. 7. ed. Porto Alegre:
AMGH; Bookman, 2013. v. 2. 274 p. (Série Tekne).
WEBER, R. F. Fundamentos de arquitetura de computadores. 4. ed. Porto Alegre: Bookman,
2012. 424 p. (Série Livros Didáticos Informática UFRGS).

Leituras recomendadas
GONÇALVES, L. S. Utilização de coordenadas georreferenciadas aplicada a máquinas agrí-
colas. Orientador: André Sanches Fonseca Sobrinho. 2017. 46 f. Trabalho de Conclusão
de Curso (Bacharelado em Engenharia de Controle e Automação) — Universidade
Tecnológica Federal do Paraná, Cornélio Procópio, 2017. Disponível em: http://reposi-
torio.roca.utfpr.edu.br/jspui/handle/1/11310. Acesso em: 20 jul. 2019.
PEREIRA, F. Instruções. In: PEREIRA, F. Microcontroladores PIC: técnicas avançadas. 6. ed.
São Paulo: Érica, 2007. cap. 4.
PEREIRA, F. Instruções Assembly. In: PEREIRA, F. Microcontrolador PIC 18 detalhado:
hardware e software. São Paulo: Érica, 2010. cap. 2. seção 2.1.6.
SCUDERO, E. Linguagens de Alto Nível vs. Baixo Nível: qual é melhor? BeCode, Porto
Alegre, 18 abr. 2017. Disponível em: https://becode.com.br/linguagens-alto-nivel-x-
-baixo-nivel/. Acesso em: 20 jul. 2019.
SOUZA, D. J. Conhecendo um pouco o set de instruções. In: SOUZA, D. J. Desbravando
o PIC: ampliado e atualizado para PIC16F628A. 6. ed. São Paulo: Érica, 2003. cap 7.

Você também pode gostar