PIC - Assembly - Criando um programa

COMENTÁRIOS

Para comentar basta usar o ponto-e-vírgula ;

Exemplo:

;Isto é um comentário.

INCLUDES

Este comando chama um arquivo que contém várias definições que iremos usar em nosso programa. Geralmente estes arquivos possuem a extensão .INC e contém definições de nomes e endereços dos registradores especiais (SFRs). Quando você estiver em um nível mais avançado também poderá criar seus próprios arquivos de definições.

Exemplo:

#INCLUDE <nome_arquivo.inc>

ou podemos indicar o local onde se encontra o arquivo: C:\diretorio\arquivo.inc (no Windows) ou /diretorio/arquivo.inc (no Linux)

REPRESENTAÇÃO DE NÚMERO:

DECIMAL (n representa o número neste exemplo)

D'nn' ou .nn

HEXADECIMAL

H'nn' ou 0Xnn

BINÁRIO

B'nnnnnnnn'

ASCII

A'n'

EQU

Usamos para definirmos constantes ou associarmos uma palavra a um endereço de memória que está nossa variável.

Sintaxe para usar EQU:

nome_da_variável EQU endereço_da_memória

ou

nome_da_constante EQU valor_da_constante

Exemplos usando a sintaxe EQU para associar uma palavra a um endereço de memória:

STATUS EQU H'003'

FSR EQU H'0004'

PORTA EQU H'0005'

PORTB EQU H'0006'

Assim, quando aparecer a palavra PORTB, será substituída pelo número 06 (em hexadecimal) que corresponde ao endereço de memória do PORTB.

#DEFINE

Permite substituir expressões por texto.

Exemplo:

#DEFINE LED PORTB,2

ORG ou CODE

ORG É usado para direcionar para posição de memória de programação. Usamos no vetor de reset, vetor de interrupção, e em alguns PICs para paginação da área de programa. Nos novos compiladores pode usar o CODE. (Exemplo: RES_VECT CODE 0x0000).

No PIC 16F628A, o vetor de reset encontra-se no endereço 0x00 então temos que usar esta diretriz ORG 0x00 antes da escrita da primeira instrução do programa.

END

Usada para encerrar o programa.

CBLOCK e ENDC

Usado para definirmos vários EQUs. Informamos o endereço apenas da primeira variável e as demais serão definidas na sequência.

Exemplo:

CBLOCK 0x20 ;Endereço inicial da memória de usuário

W_TEMP ;Variável

STATUS_TEMP ;Variável

ENDC

W

O registrador de trabalho W (work) é o mais utilizado durante o programa. É um registrador utilizado nas operações da ULA. Não faz parte da memória RAM do sistema. É um registrador temporário que através dele é possível ler ou escrever na memória.

Bancos de Memória

O PIC16F682A possui quatro bancos de memória onde ficam os registradores especiais (SFRs) e a memória de variáveis do sistema. Para acessar algum registrador que está no banco 1, por exemplo, temos que primeiramente dizer ao sistema que queremos mudar de banco. Assim, devemos alterar os bits RP0 e RP1 do registrador STATUS. Na tabela abaixo temos as combinações para acessar cada banco:

Banco RP1 RP0

0 0 0

1 0 1

2 1 0

3 1 1

Como iremos usar apenas os bancos 0 e banco 1, precisamos alterar apenas o RP0. Para facilitar podemos fazer a seguinte definição:

#DEFINE bank0 bcf STATUS,RP0 ;Muda para banco 0

#DEFINE bank1 bsf STATUS,RP0 ;Muda para banco 1

Lembrando que sempre que acessarmos o banco 1 devemos retornar para o banco 0.

Observação: Existe uma diretriz do compilador chamada BANKSEL. Com ela podemos fazer a mudança de banco em qualquer modelo de PIC mantendo um padrão. O único problema é que consome mais memória de programa em relação a proposta anterior porque ela sempre atualiza os valores de RP0 e RP1. Veja abaixo um exemplo para o PIC16F628A. Observe que ele associa a palavra BANK ao endereço inicial de memória respectivo de cada banco.

BANK0 EQU 0X00 ;Muda para o banco 0

BANK1 EQU 0X80 ;Muda para o banco 0

BANK2 EQU 0X100 ;Muda para o banco 0

BANK3 EQU 0X180 ;Muda para o banco 0

Obs.: Neste casa, para mudar de banco ao longo do código temos que usar o comando banksel. (Exemplo: banksel BANK0).

MOVLW

Este comando move um número (um literal) para o registrador word (W).

Sintaxe:

MOVLW k ;k é o número que será movido para W.

Exemplo:

MOVLW .10 ;Move o número decimal 10 para W.

MOVWF

Este comando move o valor que encontra-se no registrador W para outro registrador (f) que pode ser um nome pré-definido no arquivo include ou o endereço de memória do qual se encontra. Também move para uma variável.

Sintaxe:

MOVWF f ;Move o valor de W para f, onde f é um endereço de memória de um registrador ou uma variável

Exemplo:

MOVWF OPTION_REG ;Move o valor de W para o registrador OPTION_REG

MOVF

Este comando move o valor de um registrador (f) para o destino d (d pode ser o registrador W ou outro registrador)

Sintaxe:

MOVF f,d ;f é o registrador que será movido para d

Exemplo:

MOVF Tempo,w ;Move o valor da variável Tempo para o registrador W

CLRF

Limpa um registrador.

Sintaxe:

CLRF f ;f pode ser o nome do registrador ou o seu endereço de memória.

Exemplo:

CLRF TRISB ;Escreve zero no registrador TRISB (Define PORTB como saída).

GOTO

Executa um desvio do programa.

Sintaxe:

GOTO local ;Onde "local" é uma palavra que encontra-se no código para onde queremos desviar.

Neste caso, a palavra "local" pode ser substituída por outra que melhor desejar (como INICIO, BOTAO, etc). Ela servirá como uma identificação para onde o programa deve ser desviado. Utilize "_" no lugar de espaços.

Podemos usar o GOTO para dar saltos mais curtos utilizado o caracter $. Veja o exemplo:

GOTO $+2 ;Salta 2 linhas para baixo.

GOTO $-3 ;Salta 3 linhas para cima.

Dando nome a 1 bit de um byte

Podemos dar um nome a um bit de um byte, chamamos isso de Flags. Dessa forma podemos criar até oito flags em um byte. Para isso, criamos uma variável com qualquernome, pode chamar flag, depois damos nome para cada bit dessa variável. Veja o exemplo:

CBLOC 0x0C ;Endereço de memória onde será salvo nossa variável chamada flag.

FLAG ;Nome da nossa variável

ENDC ;Fim do bloco de memória

#DEFINE Primeiro FLAG,0 ;Associamos a palavra "Primeiro" ao bit zero da nossa variável FLAG.

#DEFINE Segundo FLAG,0 ;Associamos a palavra "Segundo" ao bit zero da nossa variável FLAG.

Também podemos definir nomes para cada pino do PIC. Exemplo:

#DEFINE LED PORTB,1 ;Associamos a palavra "LED" ao pino RB1.

#DEFINE Botao PORTA,0 ;Associamos a palavra "Botao" ao pino RA0.

BTFSC

Esta instrução testa um bit de uma porta, de uma variável ou de um flags. Para entender melhor a o comando podemos ler assim: Testa T o Bit B do registrador F e Salta S a próxima linha se a resporta for zero C.

Sintaxe:

BTFSC f,b ;f é o registrador ou variável e b é o bit deste a ser testado.

linhaA ;Passa por esta linha se a resposta for falsa.

linhaB ;Salta para esta linha se a resposta for verdadeira

Podemos definir um bit de um registrador ou uma variável para facilitar a programação.

Exemplo:

#DEFINE BOTAO PORTB,3 ;Palavra BOTAO agora está associada ao pino RB3. (1=Liberado; 0=pressionado)

BTFSC BOTAO ;Se o botão estiver pressionado...

GOTO Botao_Liberado ;Não, vai para Botao_Liberado

GOTO Botao_Pressionado ;Sim, vai para Botao_Pressionado

BTFSS

Esta instrução é o inverso da BTFSC. Pode ser lida da seguinta maneira: Testa T o Bit B do registrador F e Salta S a próxima linha se a resporta for 1 S.

Sintaxe:

BTFSS f,b ;f é o registrador ou variável e b é o bit deste a ser testado.

linhaA ;Passa por esta linha se a resposta for falsa.

linhaB ;Salta para esta linha se a resposta for verdadeira

Exemplo:

#DEFINE BOTAO PORTB,3 ;Palavra BOTAO agora está associada ao pino RB3. (0=Liberado; 1=pressionado)

BTFSS BOTAO ;Se o botão estiver pressionado...

GOTO Botao_Liberado ;Não, vai para Botao_Liberado

GOTO Botao_Pressionado ;Sim, vai para Botao_Pressionado

BSF

Esta instrução é usada para alterar um bit. O BSF seta o bit (muda para 1).

Sintexe:

BSF f,b ;f é o registrador ou variável e b é o bit que será setado

Exemplo:

#DEFINE LED PORTB,2 ;Palavra LED agora está associada ao pino RB2.

BSF LED ;Seta o LED com 1

BCF

Esta instrução é usada para alterar um bit. O BCF zera o bit (muda para 0).

Sintexe:

BCF f,b ;f é o registrador ou variável e b é o bit que será zerado

Exemplo:

BCF PORTB,2 ;Torna o RB2 como zero.

Constantes

Podemos substituir um número por uma palavra para facilitar alterações futuras em nosso código ou memo facilitar a leitura.

Exemplo:

MeiaDuzia EQU .6 ;Agora, quando referimos a palavra "MeiaDuzia" sera o mesmo que o número 6.

Vetor de Reset

O vetor de reset é um endereço na memória para qual o programa é desviado quando ocorre um reset. No PIC 16F628A esse endereço é 0x00. O reset ocorre quando o PIC é energizado. Também pode ocorrer pelo Master Clear externo (MCLR) ou pelo estouro de WDT.

Exemplo para compiladores antigos:

ORG 0x00 ;Endereço onde o reset é desviado

GOTO INICIO ;Desvia para as configurações iniciais (como as de entrada/saída, etc).

Exemplo para os novos compiladores:

RES_VECT CODE 0x0000 ;Endereço onde o reset é desviado

GOTO INICIO ;Desvia para as configurações iniciais (como as de entrada/saída, etc).

Início do Programa

No início, temos que fazer as configurações principais do nosso programa, como, definir as portas de entrada e saída (TRISA e TRISB), opções de operações (OPTION_REG), opções de interrupções (INTCON). Obs.: Dê uma olhada nos bits dos registradores OPTION_REG e do INTCON para ver mais informações.

Exemplo de um início de programa:

INICIO

BANK1 ;Muda para o Banco 1.

CLRF TRISB ;Escreve zero em TRISB (Então PORTB está definido como saída)

MOVLW B'00000001' ;Move o número 1 para W

MOVWF TRISA ;Move W para TRISA (Define o RA0 como entrada e o restante como saída)

MOVLW B'10000100' ;Move o número para W.

MOVWF OPTION_REG ;Configura Prescaler de 1:32 no TMR0 e pull-ups desabilitados.

BANK0 ;Volta para o banco 0.

;Inicialização das variáveis (Devemos iniciar as variáveis mesmo que o valor seja zero)

CLRF PORTA ;Desliga todas as saídas do PORTA

CLRF PORTB ;Desliga todas as saídas do PORTA

MOVLW .50 ;Move o número 50 para W.

MOVWF MinhaVariavel ;Move o número 50 MinhaVariavel.

Rotinas de chamada

A rotina pode ser usado como uma função que será chamada a qualquer momento no programa.

Sintaxe:

CALL MinhaRotina ;Este comando chama o trecho do codigo onde está definido a "MinhaRotina"

A rotina CALL parece com a instrução GOTO, porém, ela tem uma vantagem de retornar a linha seguinte do trecho do código que foi chamada. Quando a rotina CALL é chamada, é armazenado na pilha (Stack) o endereço seguinte ao ponto chamado. No final da rotina devemos inserir a instrução RETURN ou RETLW para o sistema voltar ao endereço armazenado na pilha.

Sintaxe para retornar:

RETURN ;Volta na linha seguinte onde foi chamado a rotina (último endereço da pilha)

RETLW k ;Volta na linha seguinte onde foi chamado a rotina com o valor do literal k em W.

Exemplo 1 - Pisca LED

Neste primeiro exemplo iremos escrever um programa que pisque um LED que está conectado ao pino RB1 sempre que o botão em RA2 for pressionado.

Figura 1 - Esquema elétrico do primeiro exemplo Pisca Led.

Código:

;PROGRAMA: PISCA-LED AO PRESSIONAR UM BOTÃO

;Definicoes:

#INCLUDE <p16f628a.inc>

__CONFIG _BODEN_ON & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_ON & _XT_OSC

;Definicoes dos banco de memoria

BANK0 EQU 0X00 ;Muda para o banco 0

BANK1 EQU 0X80 ;Muda para o banco 0

BANK2 EQU 0X100 ;Muda para o banco 0

BANK3 EQU 0X180 ;Muda para o banco 0

;Definições de variaveis, constantes ou flags:

CBLOCK 0x20 ;Endereço inicial da memória de usuário

d1 ;Variável para Delay

d2 ;Variável para Delay

d3 ;Variável para Delay

ENDC

;Definicoes de entradas

#DEFINE Botao PORTA,2 ;Botao: 1=Solto, 0=Pressionado.

;Definicoes de saida

#DEFINE LED PORTB,1 ;LED ligado ao pino RB1

;Vetor de Reset

ORG 0x00 ;Endereco que inicia o processamento.

GOTO INICIO ;Salta para as configuracoes de inicio do programa.

;Interrupções

;Nao utilizaremos interrupcoes neste programa

ORG 0x04 ;Endereco onde o programa eh desviado quando ha uma interrupcao.

RETFIE ;Retorna da interrupcao.

;Configuracoes de inicio do programa

INICIO

CLRF PORTA ;Limpa o PORTA

CLRF PORTB ;Limpa o PORTB

banksel BANK1 ;Muda para o banco1

MOVLW B'00000100' ;Move o numero para W

MOVWF TRISA ;Move w p/ TRISA que configura RA2 como entrada e o resto como saída.

MOVLW B'00000000' ;Move o numero para W

MOVWF TRISB ;Move w p/ TRISB que configura todos os pinos do PORTB como saida.

MOVLW B'10000000' ;Move o numero para W

MOVWF OPTION_REG ;Configura: Prescaler 1:2 no TMR0; PULL-UPS desabilitados.

MOVLW B'00000000' ;Move o numero para W

MOVWF INTCON ;Move w p/ INTCON onde desabilita todas as interrupcoes.

banksel BANK0 ;Volta para o banco 0.

MOVLW B'00000111' ;Move o numero para W

MOVWF CMCON ;Move w p/ CMCON onde define o modo de operacoes do comparador.

;Rotina principal

MAIN

BTFSC Botao ;Testa se o Botao esta pressionado.

GOTO Botao_solto ;Salta para o trecho que trata o botao solto.

GOTO Botao_pressionado ;Salta para o trecho que trata o botao pressionado.

Botao_solto

BCF LED ;Apaga o LED

GOTO MAIN ;Salta para MAIN

Botao_pressionado

BSF LED ;Acende o LED

Call Delay_500ms ;Aguarda 500ms

BCF LED ;Apaga o LED

Call Delay_500ms ;Aguarda 500ms

GOTO MAIN ;Salta para MAIN

Delay_500ms:

;Clock frequency = 4 MHz

;Fonte: http://www.piclist.com/techref/piclist/codegen/delay.htm

movlw 0x03

movwf d1

movlw 0x18

movwf d2

movlw 0x02

movwf d3

Delay_500ms_0

decfsz d1, f

goto $+2

decfsz d2, f

goto $+2

decfsz d3, f

goto Delay_500ms_0

;6 cycles

goto $+1

goto $+1

goto $+1

return

END ;Fim do programa