|
CAPÍTULO 4
Programação em Linguagem Assembly
Introdução
Exemplo de como se escreve um programa
Directivas de controle
4.1 define
4.2 include
4.3 constant
4.4 variable
4.5 set
4.6 equ
4.7 org
4.8 end
Instruções condicionais
4.9 if
4.10 else
4.11 endif
4.12 while
4.13 endw
4.14 ifdef
4.15 ifndef
Directivas de dados
4.16 cblock
4.17 endc
4.18 db
4.19 de
4.20 dt
Configurando uma directiva
4.21 _CONFIG
4.22 Processor
Operadores aritméticos de assembler
Ficheiros criados ao compilar um programa
Macros
Introdução
A capacidade de comunicar é da maior importância nesta área. Contudo, isso
só é possível se ambas as partes usarem a mesma linguagem, ou seja, se
seguirem as mesmas regras para comunicarem. Isto mesmo se aplica à
comunicação entre os microcontroladores e o homem. A linguagem que o
microcontrolador e o homem usam para comunicar entre si é designada por
“linguagem assembly”. O próprio título não tem um significado profundo,
trata-se de apenas um nome como por exemplo inglês ou francês. Mais
precisamente, “linguagem assembly” é apenas uma solução transitória. Os
programas escritos em linguagem assembly devem ser traduzidos para uma
“linguagem de zeros e uns” de modo a que um microcontrolador a possa
receber. “Linguagem assembly” e “assembler” são coisas diferentes. A
primeira, representa um conjunto de regras usadas para escrever um
programa para um microcontrolador e a outra, é um programa que corre num
computador pessoal que traduz a linguagem assembly para uma linguagem de
zeros e uns. Um programa escrito em “zeros” e “uns” diz-se que está
escrito em “linguagem máquina”.

O
processo de comunicação entre o homem e o microcontrolador
Fisicamente, “Programa” representa um ficheiro num disco de computador (ou
na memória se estivermos a ler de um microcontrolador) e é escrito de
acordo com as regras do assembly ou qualquer outra linguagem de
programação de microcontroladores. O homem pode entender a linguagem
assembly já que ela é constituída por símbolos alfabéticos e palavras. Ao
escrever um programa, certas regras devem ser seguidas para alcançar o
efeito desejado. Um Tradutor interpreta cada instrução escrita em
linguagem assembly como uma série de zeros e uns com significado para a
lógica interna do microcontrolador.
Consideremos, por exemplo, a instrução “RETURN” que um microcontrolador
utiliza para regressar de um subprograma.
Quando o assembler a traduz, nós obtemos uma série de uns e zeros
correspondentes a 14 bits que o microcontrolador sabe como interpretar.
Exemplo: RETURN 00 0000 0000 1000
Analogamente ao exemplo anterior, cada instrução assembly é interpretada
na série de zeros e uns correspondente.
O resultado desta tradução da linguagem assembly, é designado por um
ficheiro de “execução”. Muitas vezes encontramos o nome de ficheiro “HEX”.
Este nome provém de uma representação hexadecimal desse ficheiro, bem como
o sufixo “hex" no título, por exemplo “correr.hex". Uma vez produzido, o
ficheiro de execução é inserido no microcontrolador através de um
programador.
Um programa em Linguagem Assembly é escrito por intermédio de um
processador de texto (editor) e é capaz de produzir um ficheiro ASCII no
disco de um computador ou em ambientes próprios como o MPLAB – que vai ser
explicado no próximo capítulo.
Linguagem Assembly
Os elementos básicos da linguagem assembly são:
• Labels (rótulos)
• Instruções
• Operandos
• Directivas
• Comentários
Um Label (rótulo) é uma designação textual (geralmente de fácil leitura)
de uma linha num programa ou de uma secção de um programa para onde um
microcontrolador deve saltar ou, ainda, o início de um conjunto de linhas
de um programa. Também pode ser usado para executar uma ramificação de um
programa (tal como Goto....), o programa pode ainda conter uma condição
que deve ser satisfeita, para que uma instrução Goto seja executada. É
importante que um rótulo (label) seja iniciado com uma letra do alfabeto
ou com um traço baixo “_”. O comprimento de um rótulo pode ir até 32
caracteres. É também importante que o rótulo comece na primeira coluna.

Instruções
As instruções são específicas para cada microcontrolador, assim, se
quisermos utilizar a linguagem assembly temos que estudar as instruções
desse microcontrolador. O modo como se escreve uma instrução é designado
por "sintaxe". No exemplo que se segue, é possível reconhecer erros de
escrita, dado que as instruções movlp e gotto não existem no
microcontrolador PIC16F84.

Operandos
Operandos são os elementos da instrução necessários para que a instrução
possa ser executada. Normalmente são registos, variáveis e constantes. As
constantes são designadas por “literais”. A palavra literal significa
“número”.

Comentários
Comentário é um texto que o programador escreve no programa afim de tornar
este mais claro e legível. É colocado logo a seguir a uma instrução e deve
começar com uma semi-vírgula ";".
Directivas
Uma directiva é parecida com uma instrução mas, ao contrário desta, é
independente do tipo de microcontrolador e é uma característica inerente à
própria linguagem assembly. As directivas servem-se de variáveis ou
registos para satisfazer determinados propósitos. Por exemplo, NIVEL, pode
ser uma designação para uma variável localizada no endereço 0Dh da memória
RAM. Deste modo, a variável que reside nesse endereço, pode ser acedida
pela palavra NIVEL. É muito mais fácil a um programador recordar a palavra
NIVEL, que lembrar-se que o endereço 0Dh contém informação sobre o nível.

Exemplo de como se escreve um programa
O exemplo que se segue, mostra como um programa simples pode ser escrito
em linguagem assembly, respeitando regras básicas.
Quado se escreve um programa, além das regras fundamentais, existem
princípios que, embora não obrigatórios é conveniente, serem seguidos. Um
deles, é escrever no seu início, o nome do programa, aquilo que o programa
faz, a versão deste, a data em que foi escrito, tipo de microcontrolador
para o qual foi escrito e o nome do programador.

Uma vez
que estes dados não interessam ao tradutor de assembly, são escritos na
forma de comentários. Deve ter-se em atenção que um comentário começa
sempre com ponto e vírgula e pode ser colocado na linha seguinte ou logo a
seguir à instrução.
Depois deste comentário inicial ter sido escrito, devem incluir-se as
directivas. Isto mostra-se no exemplo de cima.
Para que o seu funcionamento seja correcto, é preciso definir vários
parâmetros para o microcontrolador, tais como:
- tipo de oscilador
- quando o temporizador do watchdog está ligado e
- quando o circuito interno de reset está habilitado.
Tudo isto é definido na directiva seguinte:
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
Logo que todos os elementos de que precisamos tenham sido definidos,
podemos começar a escrever o programa.
Primeiro, é necessário definir o endereço para que o microcontrolador deve
ir quando se liga a alimentação. É esta a finalidade de (org 0x00).
O endereço para onde um programa salta se ocorrer uma interrupção é (org
0x04).
Como este é um programa simples, é suficiente dirigir o microcontrolador
para o início de um programa com uma instrução "goto Main" (Main =
programa principal).
As
instruções encontradas em Main, seleccionam o banco 1 (BANK1) de modo a
poder aceder-se ao registo TRISB, afim de que o porto B seja definido como
uma saída (movlw 0x00, movwf TRISB).
O próximo passo é seleccionar o banco de memória 0 e colocar os bits do
porto B no estado lógico ‘1’ e, assim, o programa principal fica
terminado.
É preciso, no entanto, um outro ciclo (loop), onde o microcontrolador
possa permanecer sem que ocorram erros. Trata-se de um ‘loop’ infinito que
é executado continuamente, enquanto a alimentação não for desligada.
Finalmente, é necessário colocar a palavra “end" no fim de cada programa,
de modo a informar o tradutor de assembly de que o programa não contém
mais instruções.
Directivas de
controle
4.1 #DEFINE
Troca de uma porção de texto por outra
Sintaxe:
#define<nome> [< texto atribuído a nome > ]
Descrição:
De cada vez que a palavra <nome> aparece no programa, vai ser substituída
por <texto atribuído a nome>.
Exemplo:
#define ligado 1
#define desligado 0
Directivas similares: #UNDEFINE, IFDEF, IFNDEF
4.2
INCLUDE Incluir um ficheiro adicional num programa
Sintaxe:
include <<nome_do_ficheiro>>
include “<nome_do_ficheiro>”
Descrição:
A aplicação desta directiva faz com que um ficheiro completo seja copiado
para o local em que a directiva “include” se encontra. Se o nome do
ficheiro estiver entre aspas, estamos a lidar com um ficheiro do sistema,
se não estiver entre aspas, mas sim entre os sinais < >, trata-se de um
ficheiro do utilizador. A directiva “include”, contribui para uma melhor
apresentação do programa principal.
Exemplo:
include < regs.h >
include “subprog.asm”
4.3 CONSTANT Atribui um valor numérico constante a uma designação textual
Sintaxe:
constant < nome > = < valor >
Descrição:
Cada vez que < nome > aparece no programa, é substituído por < valor > .
Exemplo:
constant MAXIMO = 100
constant Comprimento = 30
Directivas similares: SET, VARIABLE
4.4 VARIABLE Atribui um valor numérico variável à designação textual
Sintaxe:
variable < nome > = < valor >
Descrição:
Ao utilizar esta directiva, a designação textual muda o seu valor.
Difere da directiva CONSTANT no facto de, depois de a directiva ser
aplicada, o valor da designação textual poder variar.
Exemplo:
variable nivel = 20
variable tempo = 13
Directivas similares: SET, CONSTANT
4.5 SET Definir uma
variável assembler
Sintaxe:
< nome_variavel > set <valor>
Descrição:
À variável < nome_variavel > é atribuída a expressão <valor> . A directiva
SET é semelhante a EQU, mas com a directiva SET é possível tornar a
definir a variável com outro valor.
Exemplo:
nivel set 0
comprimento set 12
nivel set 45
Directivas similares: EQU, VARIABLE
4.6 EQU
Definindo uma constante em assembler
Sintaxe:
< nome_da_constante > equ < valor >
Descrição:
Ao nome de uma constante < nome_de_constante > é atribuído um valor <
valor >
Exemplo:
cinco equ 5
seis equ 6
sete equ 7
Instruções similares: SET
4.7 ORG Define o endereço a partir do qual o programa é armazenado na
memória do microcontrolador
Sintaxe:
<rótulo> org <valor>
Descrição:
Esta é a directiva mais frequentemente usada. Com esta directiva nós
definimos em que sítio na memória de programa o programa vai começar.
Exemplo:
Inicio org 0x00
movlw 0xFF
movwf PORTB
Estas duas instruções a seguir à directiva 'org', são guardadas a partir
do endereço 00.
4.8 END Fim do programa
Sintaxe:
end
Descrição:
No fim do programa, é necessário colocar a directiva 'end', para que o
tradutor do assembly (assembler), saiba que não existem mais instruções no
programa.
Exemplo:
.
.
movlw 0xFF
movwf PORTB
end
Instruções condicionais
4.9 IF Ramificação
condicional do programa
Sintaxe:
if <termo_condicional>
Descrição:
Se a condição em <termo_condicional> estiver satisfeita, a parte do
programa que se segue à directiva IF, deverá ser executada. Se a condição
não for satisfeita, então é executada a parte que se segue às directivas
ELSE ou ENDIF.
Exemplo:
if nivel = 100
goto ENCHER
else
goto DESPEJAR
endif
Directivas similares: ELSE, ENDIF
4.10 ELSE Assinala um bloco alternativo se a condição termo_condicional
presente em 'IF' não se verificar
Sintaxe:
Else
Descrição:
Usado com a directiva IF como alternativa no caso de termo_condicional ser
falso.
Exemplo:
if tempo < 50
goto DEPRESSA
else goto DEVAGAR
endif
Instruções similares: ENDIF, IF
4.11
ENDIF Fim de uma secção condicional do programa
Sintaxe:
endif
Descrição:
Esta directiva é escrita no fim de um bloco condicional, para informar o
tradutor do assembly de que o bloco condicional terminou.
Exemplo:
if nivel = 100
goto METER
else
goto TIRAR
endif
Directivas similares: ELSE, IF
4.12 WHILE A execução da secção do programa prossegue, enquanto a condição
se verificar
Sintaxe:
while <condição>
.
endw
Descrição:
As linhas do programa situadas entre WHILE e ENDW devem ser executadas,
enquanto a condição for verdadeira. Se a condição deixar de se verificar,
o programa deverá executar as instruções a partir da linha que sucede a
ENDW. O número de instruções compreendidas entre WHILE e ENDW pode ir até
100 e podem ser executadas até 256 vezes.
Exemplo:
while i < 10
i = i + 1
endw
4.13 ENDW Fim
da parte condicional do programa
Sintaxe:
endw
Descrição:
Esta directiva é escrita no fim do bloco condicional correspondente a
WHILE, assim, o assembler fica a saber que o bloco condicional chegou ao
fim.
Exemplo:
while i < 10
i = i + 1
.
endw
Directivas similares: WHILE
4.14 IFDEF Executar uma parte do programa se um símbolo estiver definido
Sintaxe:
ifdef < designação >
Descrição:
Se a designação <designação> tiver sido previamente definida (normalmente
através da directiva #DEFINE), as instruções que se lhe sucedem serão
executadas até encontrarmos as directivas ELSE ou ENDIF.
Exemplo:
#define teste
.
ifdef teste ; como teste foi definido
...............; as instruções nestas linhas vão ser executadas
endif
Directivas similares: #DEFINE, ELSE, ENDIF, IFNDEF, #UNDEFINE
4.15 IFNDEF Execução de uma parte do programa se o símbolo não tiver sido
definido
Sintaxe:
ifndef <designação>
Descrição:
Se a designação <designação> não tiver sido previamente definida ou se
esta definição tiver sido mandada ignorar através da directiva #UNDEFINE,
as instruções que se seguem deverão ser executadas, até que as directivas
ELSE ou ENDIF, sejam alcançadas.
Exemplo:
#define teste
........
#undefine teste
.........
ifndef teste ; como teste não está definido
........ ; as instruções nestas linhas são executadas
endif
Directivas similares: #DEFINE, ELSE, ENDIF, IFDEF, #UNDEFINE
Directivas de Dados
4.16
CBLOCK Definir um bloco para as constantes nomeadas
Sintaxe:
Cblock [< termo >]
<rótulo> [:<incremente>], <rótulo> [:<incremente>]......
endc
Descrição:
Esta directiva é usada para atribuir valores às constantes a seguir
nomeadas. A cada termo seguinte, é atribuído um valor superior em uma
unidade ao anterior. No caso de <incremente> estar preenchido, então é o
valor de <incremente> que é adicionado à constante anterior.
O valor do parâmetro <termo>, é o valor inicial. Se não for dado, então,
por defeito, é considerado igual a zero.
Exemplo:
cblock 0x02
primeiro, segundo ; primeiro = 0x02, segundo = 0x03
terceiro ;terceiro = 0x04
endc
cblock 0x02
primeiro : 4, segundo : 2 ; primeiro = 0x06, segundo = 0x08
terceiro ; terceiro = 0x09
endc
Directivas similares: ENDC
4.17
ENDC Fim da definição de um bloco de constantes
Sintaxe:
endc
Descrição:
Esta directiva é utilizada no fim da definição de um bloco de constantes,
para que o tradutor de assembly saiba que não há mais constantes.
Directivas similares: CBLOCK
4.18 DB
Definir um byte de dados
Sintaxe:
[<termo>] db <termo> [, <termo>,......,<termo>]
Descrição:
Esta directiva reserva um byte na memória de programa. Quando há mais
termos a quem é preciso atribuir bytes, eles serão atribuídos um após
outro.
Exemplo:
db ‘t’, 0x0f, ‘e’, ‘s', 0x12
Instruções similares: DE, DT
4.19 DE – Definir
byte na memória EEPROM
Sintaxe:
[<termo>] de <termo> [, <termo>,......,<termo>]
Descrição:
Esta directiva reserva um byte na memória EEPROM. Apesar de ser destinada
em primeiro lugar para a memória EEPROM, também pode ser usada em qualquer
outro local de memória.
Exemplo:
org H’2100’
de “Versão 1.0”, 0
Directivas similares: DB, DT
4.20 DT Definindo uma
tabela de dados
Sintaxe:
[<termo>] dt <termo> [, <termo>,......,<termo>]
Descrição:
Esta directiva vai gerar uma série de instruções RETLW, uma instrução para
cada termo.
dt “Mensagem” , 0
dt primeiro, segundo, terceiro
Directivas similares: DB, DE
Configurando uma directiva
4.21
__CONFIG Estabelecer os bits de configuração
Sintaxe:
__config<termo> ou __config <endereço>, <termo>
Descrição:
São definidos o tipo de oscilador, e a utilização do watchdog e do
circuito de reset interno. Antes de usar esta directiva, tem que
declarar-se o processador através da directiva PROCESSOR.
Exemplo:
__CONFIG _CP_OFF & _WDT_OFF & PWRTE_ON & _XT_OSC
Directivas similares: __IDLOCS, PROCESSOR
4.22
PROCESSOR Definindo o modelo de microcontrolador
Sintaxe:
processor <tipo_de_microcontrolador>
Descrição:
Esta directiva, estabelece o tipo de microcontrolador em que o programa
vai correr.
Exemplo:
processor 16f84
Operadores aritméticos de
assembler

Ficheiros criados ao compilar um programa
Os ficheiros resultantes da tradução de um programa escrito em linguagem
assembly são os seguintes:
• Ficheiro de execução (nome_do_programa.hex)
• Ficheiro de erros no programa (nome_do_programa.err)
• Ficheiro de listagem (nome_do_programa.lst)
O primeiro ficheiro contém o programa traduzido e que vai ser introduzido
no microcontrolador quando este é programado. O conteúdo deste ficheiro
não dá grande informação ao programador, por isso, não o iremos mais
abordar.
O segundo ficheiro contém erros possíveis que foram cometidos no processo
de escrita e que foram notificados pelo assembler durante a tradução.
Estes erros também são mencionados no ficheiro de listagem “list”. No
entanto é preferível utilizar este ficheiro de erros “err”, em casos em
que o ficheiro “lst” é muito grande e, portanto, difícil de consultar.
O terceiro ficheiro é o mais útil para o programador. Contém muita
informação tal como o posicionamento das instruções e variáveis na memória
e a sinalização dos erros.
A seguir, apresenta-se o ficheiro ‘list’ do programa deste capítulo. No
início de cada página, encontra-se informação acerca do nome do ficheiro,
data em que foi criado e número de página. A primeira coluna, contém o
endereço da memória de programa, onde a instrução mencionada nessa linha,
é colocada. A segunda coluna, contém os valores de quaisquer símbolos
definidos com as directivas: SET, EQU, VARIABLE, CONSTANT ou CBLOCK. A
terceira coluna, tem, o código da instrução que o PIC irá executar. A
quarta coluna contém instruções assembler e comentários do programador.
Possíveis erros são mencionados entre as linhas, a seguir à linha em que o
erro ocorreu.

No fim do
ficheiro de listagem, é apresentada uma tabela dos símbolos usados no
programa. Uma característica útil do ficheiro ‘list’ é a apresentação de
um mapa da memória utilizada. Mesmo no fim, existe uma estatística dos
erros, bem como a indicação da memória de programa utilizada e da
disponível.
Macros
As macros são elementos muito úteis em linguagem assembly. Uma macro pode
ser descrita em poucas palavras como “um grupo de instruções definido pelo
utilizador que é acrescentado ao programa pelo assembler, sempre que a
macro for invocada”. É possível escrever um programa sem usar macros. Mas,
se as utilizarmos, o programa torna-se muito mais legível, especialmente
se estiverem vários programadores a trabalhar no mesmo programa. As macros
têm afinidades com as funções nas linguagens de alto nível.
Como as escrever:
<rótulo> macro
[<argumento1>,<argumento2>,.....,<argumentoN>]
.........
.........
endm
Pelo modo como são escritas, vemos que as macros podem aceitar argumentos,
o que também é muito útil em programação.
Quando o argumento é invocado no interior de uma macro, ele vai ser
substituído pelo valor <argumentoN>.
Exemplo:

O exemplo
de cima, mostra uma macro cujo propósito é enviar para o porto B, o
argumento ARG1, definido quando a macro foi invocada. Para a utilizarmos
num programa, basta escrever uma única linha: ON_PORTB 0xFF e, assim,
colocamos o valor 0xFF no porto B. Para utilizar uma macro no programa, é
necessário incluir o ficheiro macro no programa principal, por intermédio
da instrução #include “nome_da_macro.inc”. O conteúdo da macro é
automaticamente copiado para o local em que esta macro está escrita. Isto
pode ver-se melhor no ficheiro ‘lst’ visto atrás, onde a macro é copiada
por baixo da linha #include “bank.inc”.
|