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