Você está na página 1de 166

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Introduo
Este tutorial foi feito para as pessoas que tm a eletrnica como diverso e
desejam aprender a utilizar microcontroladores em seus projetos.
Tambm sou um entusiasta da eletrnica e gosto de entender como as coisas
funcionam. Por isso, escrevo os programas para os microcontroladores em linguagem Assembly.
Se voc como eu, creio que gostar deste tutorial.
Boa leitura!

Mulder_Fox
Membro do frum de Eletrnica do Clube do Hardware
http://forum.clubedohardware.com.br/eletronica/f39

Parte 1
Pisca LED
Nesta primeira parte, vamos montar um circuito para fazer um LED piscar
numa frequncia de aproximadamente um Hz.
Vamos utilizar o microcontrolador PIC16F628A, um dos modelos mais
usados hoje em dia.

Figura 1

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Os microcontroladores precisam de um sinal de clock para funcionar, mas


muitos modelos possuem a alternativa de usar um circuito oscilador interno para gerar esse sinal.
Este o caso do PIC16F628A, onde podemos escolher a frequncia de 48 KHz ou a de 4 MHz.
A configurao do oscilador interno como fonte do sinal de clock e a sua
frequncia so feitos no programa que gravado no PIC.
Antes de escrevermos o programa para o microcontrolador, vamos desenhar
o esquema do circuito.
Segundo consta no datasheet do PIC16F628A, a sua tenso de alimentao
pode ser de 3 v at 5,5V, sendo que com 3 v, a frequncia mxima do sinal de clock de 10 MHz
enquanto que a partir de 4,5V de 20Mhz.
Vamos utilizar um regulador de tenso LM7805 para fornecer uma tenso de
5 v a partir de 9 v.
Alm do LM7805 e do PIC16F628A iremos utilizar um LED e um resistor
para limitar sua corrente, que sero ligados diretamente no pino do PIC, j que ele tem a capacidade
de fornecer a corrente necessria para o LED.
Mas, em qual pino do PIC iremos ligar o LED?
O PIC16F628A possui 15 pinos que podem ser usados como entrada ou
sada: RA0, RA1, RA2, RA3, RA4, RA6, RA7, RB0, RB1, RB2, RB3, RB4, RB5, RB6 e RB7 e 1
pino que s pode ser usado como entrada: RA5.
O pino RA4 o nico que, quando configurado como sada, do tipo open
drain, ou seja, a carga conectada a este pino deve estar ligada ao positivo da alimentao.
possvel fazer com que resistores de pull-up integrados no PIC sejam
conectados nos pinos RB0, RB1, RB2, RB3, RB4, RB5, RB6 e RB7, individualmente, para o caso
de um ou mais destes pinos estarem sendo usados como entrada, economizando, desta forma, o uso
de resistores externos. Veremos como fazer isto em outra parte deste tutorial.
Antes de definirmos qual pino iremos utilizar, precisamos saber se as
caractersticas do pino atendem s nossas necessidades.
No nosso circuito precisaremos de um pino que possa ser usado como sada
e, portando, temos 15 nossa disposio. Podemos escolher qualquer um deles, por exemplo, o
RA0.
Portanto, o esquema do circuito ficou assim:

Figura 2

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Definido o esquema do circuito, vamos elaborar o fluxograma do programa


que iremos gravar no PIC.
O fluxograma uma representao grfica de como o programa se comporta
conforme as possveis situaes.
Com o fluxograma, fica mais fcil escrever o programa.
Eis o fluxograma do nosso programa:
Incio

Configurao
dos registradores

Inicializao das
variveis

Passou 0,5
segundo?

no

sim

Acende LED

Apaga LED

LED est aceso?


no

sim

Indica o incio

Indica uma subrotina

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Indica uma deciso

Indica acesso a um dispositivo de I/O

Agora podemos comear a escrever o programa utilizando o software


MPLAB IDE da Microchip.
Faa o download do MPLAB IDE do site da Microchip e instale em seu
computador. A ltima verso disponvel na data que foi escrito este tutorial a 8.63.00.00.
A tela inicial do MPLAB IDE pode ser vista na figura 3.
No menu File, clique em New.
Novamente, no menu File, clique em Save As... e escolha um nome para
o arquivo, com a extenso .asm. Por exemplo: Pisca LED .asm.

Figura 3

Primeiramente vamos criar um cabealho onde ir constar o nome do


programa, sua verso, o nome do autor e a data de concluso, ficando assim:

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

;***********************************************************************************************
;
PROGRAMA: PISCA LED
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /2011
;***********************************************************************************************

Tudo o que for digitado na linha aps ponto e vrgula ser ignorado pelo
MPLAB na hora da montagem do cdigo, portanto, todas as anotaes e comentrios tm de virem
precedidos de ponto e vrgula.
Repare no ponto e vrgula no incio de cada linha que faz com que o
MPLAB ignore o que est escrito aps.
Em seguida vamos incluir no nosso programa o arquivo padro de
definies do PIC16F628A, usando a diretiva #INCLUDE:
;***********************************************************************************************
#INCLUDE <P16F628A.INC>
;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A
;***********************************************************************************************

Repare que antes de #INCLUDE <P16F628A.INC> no h ponto e vrgula


e portanto o MPLAB ir executar esse comando.
Observe que foi deixado um espao a partir da margem esquerda. Isso
porque se o MPLAB encontra uma diretiva na margem esquerda, ele envia uma mensagem de alerta
na hora de criar o arquivo a ser gravado no microcontrolador.
Observe que na mesma linha, antes do comentrio ARQUIVO PADRAO
MICROCHIP PARA O PIC16F628A h ponto e vrgula, pois, no queremos que o MPLAB leve
em considerao o que est escrito, pois se trata de um comentrio (no faz parte do programa).
Repare que aps digitar #INCLUDE a cor da letra ficou azul, O MPLAB faz
isso sempre que reconhece o termo como uma diretiva. Isso ajuda a perceber quando escrevemos a
diretiva de forma errada, pois, a ela no ficar azul.
No arquivo P16F628A.INC onde constam, alm do modelo do
microcontrolador, as correspondncias entre os nomes dos registradores e as respectivas posies
que eles ocupam na memria de dados, bem como, entre os nomes de cada bit e sua posio no
registrador, entre outras informaes, como tamanho e endereos vlidos da memria e bits de
configurao.
O que ocorre que, para facilitar a vida do programador, as localidades da
memria de dados, ou seja, os registradores, recebem nomes.
Quando o MPLAB vai traduzir o programa para a linguagem de mquina ele
usa essas correspondncias.
Se voc quiser ver o arquivo P16F628A.INC, localize-o na pasta MPASM
Suite que uma subpasta da pasta Microchip, criada no diretrio onde foi instalado o MPLAB IDE.
O prximo passo ajustar os Bits de Configurao, tambm conhecidos por
fusveis ou fuses. Isso feito com a diretiva __CONFIG.
;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

So 2 underlines antes do CONFIG, seguido de espao e aps as


expresses antecedidas de 1 underline separadas pelo smbolo & entre espaos.
Nos Bits de Configurao selecionamos o tipo de oscilador que ser usado e
se os seguintes recursos sero ativados: WDT (Watch Dog Timer), PWRTE (Power-up Timer),
MCLRE (Master Clear Enable), BOREN (Brown-out Reset), LVP (Low Voltage Program),
DATA_CP (proteo da memria de dados), CP (proteo da memria de programa).
As opes para seleo do oscilador so:
_LP_OSC : Cristal de frequncia at cerca de 1MHz ligado entre os pinos
OSI e OSO.
_XT_OSC : Cristal de frequncia de cerca de 1MHz a 4 MHz ligado entre
os pinos OSI e OSO.
_HS_OSC : Cristal de frequncia superior a 4 MHz ligado entre os pinos
OSI e OSO.
_EXTCLK_OSC : Sinal de clock externo aplicado no pino CLKIN.
_INTOSC_OSC_NOCLKOUT : Oscilador interno.
_INTOSC_OSC_CLKOUT : O mesmo que o anterior, porm com sada do
sinal de clock no pino CLKOUT ( da frequncia) para fins de sincronizao de hardware externo.
_RC_OSC_NOCLKOUT : Oscilador a base de resistor e capacitor ligados
no pino CLKIN.
_RC_OSC_CLKOUT : O mesmo que o anterior, porm com sada do sinal
de clock no pino CLKOUT ( da frequncia) para fins de sincronizao de hardware externo.
No nosso caso, escolhemos a opo _INTOSC_OSC_NOCLKOUT, ou seja,
oscilador interno sem sada do sinal.
O WDT (Watch Dog Timer) um recurso que reinicia o microcontrolador,
caso o programa travar.
Vamos habilitar esse recuso escrevendo _WDT_ON.
Se no quisssemos ativar o recurso escreveramos _WDT_OFF.
O PWRTE (Power-up Timer) um circuito que mantm o microcontrolador
em reset por 72 ms aps a alimentao ser ligada para que d tempo do oscilador estabilizar.
Vamos habilitar tambm este recurso escrevendo _PWRTE_ON.
O MCLRE (Master Clear Enable), se estiver ativado, reserva o pino MCLR
para a funo de reset do microcontrolador.
Este recurso no nos interessa e, por isso, o deixamos desligado, escrevendo
_MCLRE_OFF.
O BOREN (Brown-out reset) um recurso que monitora a tenso de
alimentao e quando ela cai abaixo de 4,5V provoca o reset.
Este recurso tambm no nos interessa e, por isso, escrevemos
_BOREN_OFF.
O LVP (Low Voltage Program) um recurso que permite que o
microcontrolador seja gravado sem a necessidade de aplicar uma tenso de cerca de 13V no pino
VPP (veremos sobre gravao do PIC no momento oportuno).
Esta funo no nos interessa e, por isso, escrevemos _LVP_OFF.
DATA_CP um recurso para proteger a memria de dados contra cpia.
6

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

CP um recurso para proteger a memria de programa contra cpias.


Estes recursos interessam a quem fabrica aparelhos eletrnicos e quer evitar
engenharia reversa.
Estes recursos no nos interessam, e, por isso, escrevemos _CP_OFF &
DATA_CP_OFF.
O prximo passo definir as labels para a comutao dos bancos de
memria de dados.
Fazemos isto utilizando a diretiva #DEFINE desta forma:
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0
#DEFINE BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************

A memria de dados est dividida em quatro bancos (figura 4).


Para ter acesso a qualquer registrador a fim de ler ou alterar o seu valor,
precisamos ajustar os valores dos bits RP0 e RP1 do registrador STATUS, para selecionar o banco
onde se encontra o registrador.
Banco 0: RP0 = 0, RP1 = 0
Banco 1: RP0 = 1, RP1 = 0
Banco 2: RP0 = 0, RP1 = 1
Banco 3: RP0 = 1, RP1 = 1
Neste programa que estamos fazendo, no necessitaremos de acessar os
bancos 3 e 4, pois, os Registradores de Uso Especfico que neles se encontram tambm esto nos
bancos 0 ou 1 e no iremos precisar das posies destinadas a Registradores de Uso Geral que l se
encontram, pois, nos bastaro os disponveis no banco 0.
Como o bit RP1 inicializa com o valor 0, basta que alteremos o bit RP0,
para alternar entre os bancos 0 e 1.
Usamos a diretiva #DEFINE para que onde houver a palavra BANCO_0 o
microcontrolador execute a instruo BCF STATUS,RP0.
BANCO_0 o que chamamos de label e poderia ser outra palavra de sua
preferncia.
A instruo BCF serve para fazer o valor de um determinado bit igual a 0.
Em BCF STATUS,RP0
STATUS o nome do registrador e RP0 o
nome do bit deste registrador cujo valor ficar igual a 0.
Ns tambm usamos a diretiva #DEFINE para que onde houver a palavra
BANCO_1 o microcontrolador execute a instruo BSF STATUS,RP0.
A instruo BSF serve para fazer o valor de um determinado bit igual a 1.
Desta forma, fica mais fcil fazer a comutao entre os bancos de memria,
pois basta escrever a palavra BANCO_0 para que o banco 0 da memria de dados seja selecionado
e a palavra BANCO_1 para o banco 1.
Repare que aps digitar BCF e BSF, a cor da letra ficou azul e em negrito. O
MPLAB faz isto com qualquer termo reconhecido como uma instruo. Isto nos ajuda a perceber se
escrevermos uma instruo de forma errada.

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 4
O prximo passo definir as variveis que iremos utilizar em nosso
programa.
Uma varivel um Registrador de Uso Geral, ou seja, uma das posies da
memria de dados que podemos usar para armazenar os valores dos dados que vamos manipular no
nosso programa.
medida que vamos escrevendo o programa, vamos precisando criar
variveis. Por esse motivo, minha forma preferida para defini-las com o uso da diretiva CBLOCK:
8

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

;**********************************************************************************************
;
VARIAVEIS
CBLOCK

ENDC

0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

DELAY_0
DELAY_1
DELAY_2

;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO


;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************

A expresso 0X20 aps a diretiva CBLOCK indica o endereo na memria


de dados que assumir a primeira varivel definida (DELAY_0).
Esse endereo est em formato hexadecimal. Veja na figura 4 que ele (l
representado por 20h) o primeiro, no banco 0, que podemos usar como Registrador de Uso Geral.
Repare que o ltimo o 7Fh, totalizando 96 localidades de memria nesse
banco.
Os do endereo 70 at 7F so espelhados nos outros bancos, permitindo que
possam ser acessados sem necessidade de selecionar o banco.
No banco 1 temos outras 80 posies e no banco 2 mais 48.
Portanto, no PIC16F628A temos um total de 224 posies de memria
(registradores) que podemos usar para armazenar valores. Ou seja, podemos criar at 224 variveis.
Voltando a falar da diretiva CBLOCK, aps relacionar os nomes das nossas
variveis, encerramos a diretiva com ENDC.
Desta forma, definimos o endereo 0X20 para DELAY_0, 0X21 para
DELAY_1 e 0X22 para DELAY_2.
Se posteriormente quisermos adicionar outras variveis, podemos intercallas sem problemas.
H outras formas de definir variveis, atravs das diretivas #DEFINE e
EQU, mas creio que a mais prtica seja atravs da diretiva CBLOCK.
O prximo passo definir as constantes.
Constantes so valores numricos que utilizamos durante o programa.
Por exemplo, uma determinada varivel pode precisar ser reiniciada sempre
com o mesmo valor. Este valor uma constante.
No nosso programa, as variveis DELAY_0, DELAY_1 c DELAY_2 sero
reiniciadas, cada qual, com valores que sero sempre os mesmos.
Esses valores sero ajustados depois que fizermos a rotina principal do
programa, por isso, os valores que iremos escrever agora sero provisrios.
Para definir as constantes, usamos a diretiva EQU:
;**********************************************************************************************
;
CONSTANTES
INI_DELAY_0
EQU .255 ;VALOR QUE DELAY_0 INICIA
INI_DELAY_1
EQU .50
;VALOR QUE DELAY_1 INICIA
INI_DELAY_2
EQU .13
;VALOR QUE DELAY_2 INICIA
;***********************************************************************************************

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

No momento em que o MPLAB for montar o programa, onde estiver escrito


INI_DELAY_0, ele ir substituir essa expresso pelo valor 255 (decimal); INI_DELAY_1 por 50 e
INI_DELAY_2 por 13.
A vantagem de fazer isso que se constatarmos que os valores para aquelas
variveis no estavam satisfatrios, basta alter-los ali, em vez de modific-los em todas as linhas
do programa onde forem feitas reinicializaes das variveis.
A propsito, vamos falar de como representar, no programa, os valores numricos
usando o nmero 10 como exemplo.
Quando estivermos nos referindo ao nmero 10 do sistema decimal, escreveremos
assim: D'10' ou ainda .10
Se for o numero 10 do sistema binrio (2 do sistema decimal), escreveremos assim:

B'10'
Se for o nmero 10 do sistema hexadecimal (16 do sistema decimal),
escreveremos assim: H'10' ou assim: 0X10
A seguir vamos atribuir a label LED para o bit 0 do registrador PORTA.
;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************

A diretiva #DEFINE atribuiu a label LED para o bit 0 do registrador


PORTA.
Toda vez que aparecer no programa a palavra LED, o MPLAB saber que se
trata do bit 0 do registrador PORTA.
Os registradores associados aos pinos de I/O so o PORTA e o PORTB.
O prprio nome do pino j nos diz qual o registrador e o bit.
Pino RA0 bit 0 do PORTA
Pino RA1 bit 1 do PORTA
Pino RA2 bit 2 do PORTA
Pino RA3 bit 3 do PORTA
Pino RA4 bit 4 do PORTA
Pino RA5 bit 5 do PORTA
Pino RA6 bit 6 do PORTA
Pino RA7 bit 7 do PORTA
Pino RB0 bit 0 do PORTB
Pino RB1 bit 1 do PORTB
Pino RB2 bit 2 do PORTB
Pino RB3 bit 3 do PORTB
Pino RB4 bit 4 do PORTB
Pino RB5 bit 5 do PORTB
Pino RB6 bit 6 do PORTB
Pino RB7 bit 7 do PORTB

10

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Quando um pino estiver configurado como entrada (veremos depois como


se faz a configurao dos pinos como entradas ou sadas), o nvel lgico presente nele poder ser
verificado fazendo-se a leitura do valor do bit correspondente. Se o valor do bit igual a 1, ento o
nvel lgico no pino alto e vice-versa.
Por exemplo, suponhamos que o pino RB2 esteja configurado como entrada.
Para sabermos qual o seu nvel lgico, fazemos a leitura do bit 2 do
registrador PORTB (veremos no momento oportuno como verificar o nvel lgico de um bit).
Para o pino RA6, lemos o bit 6 do PORTA e assim por diante.
Se um pino estiver configurado como sada, e quisermos levar o seu nvel
para alto, tornamos o valor do seu bit correspondente igual a 1. Para levar o pino para nvel baixo,
tornamos o valor do bit correspondente igual a 0, ou seja, controlando o valor do bit controlamos o
nvel no pino.
O prximo passo o vetor de reset.
;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************

Aps a inicializao e depois de um reset, o microcontrolador executa a


instruo que estiver no endereo 0X00 da memria de programa.
Em seguida ele ir executar a instruo presente no endereo 0X01, depois
0X02 e assim por diante.
A diretiva ORG indica em qual endereo da memria de programa dever
ser escrita a instruo seguinte. No nosso programa, a instruo GOTO INICIO ocupar o endereo
0X00 da memria de programa, ou seja, ser a primeira instruo a ser executada pelo
microcontrolador.
O microcontrolador ao executar esta instruo desvia para o endereo da
memria de programa ocupado pela instruo que estiver aps a label INICIO.
Mas, porque fazer esse desvio?
Os microcontroladores possuem um recurso muito til chamado Interrupo,
que a interrupo da execuo do programa devido a um evento provocado por um perifrico do
microcontrolador configurado para isso. Perifricos so os circuitos presentes no microcontrolador
que fazem funes especficas como contadores, geradores de sinal PWM, comparadores, etc...
Quando uma interrupo ocorre, o microcontrolador executa a instruo
presente no endereo 0X04 da memria de programa (no caso do PIC16F628A).
Este o motivo de fazermos um desvio logo no endereo 0X00. Este desvio
ser para depois do fim da rotina de interrupo, pois, o programa no caberia entre o endereo
0X00 e 0X03 e ele no pode ocupar os endereos a partir do 0X04, pois, ali estar a rotina de
interrupo.
Como neste programa no iremos utilizar o recurso da interrupo, iremos
escrever no nosso programa a instruo RETFIE no endereo 0X04 para que se, por acaso, ocorrer
uma interrupo indesejada, o programa possa retornar para o ponto de onde foi desviado:
;**********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04
;VETOR DAS INTERRUPES
RETFIE
;RETORNA
;***********************************************************************************************

11

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Em outra parte deste tutorial falaremos detalhadamente sobre interrupes.


O prximo passo configurar os Registradores de Uso Especfico.
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF

;SELECIONA BANCO 1 DE MEMORIA


B'11111110'
TRISA
B'11111111'
TRISB

BANCO_0
MOVLW
MOVWF

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;TODOS OS PINOS DO PORTB COMO ENTRADAS
;SELECIONA BANCO 0 DE MEMORIA

B'00000111'
CMCON

;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************

Repare que aqui est a label INICIO.


Nesta parte do programa devemos configurar todos os Registradores de Uso
Especfico que estejam envolvidos com os recursos do microcontrolador que iremos utilizar.
Por exemplo, se formos utilizar o TIMER 0, teremos de configurar o
registrador relacionado a ele. Se formos utilizar o mdulo de PWM, devemos configurar o
registrador a ele relacionado e assim por diante, por isto devemos ler o datasheet do
microcontrolador para sabermos quais registradores deveremos configurar.
No nosso circuito estamos utilizando o pino RA0 do PORTA e por isto,
devemos configurar o registrador TRISA, responsvel por definir cada pino do PORTA como
entrada ou sada.
Aqui tambm h uma relao direta entre o bit e o pino.
O bit 0 do TRISA configura o pino RA0, o bit 1 o pino RA1 e assim por
diante.
Se for atribudo o valor 0 para o bit, o pino configurado como sada e se
for atribudo o valor 1, o pino configurado como entrada. Memorize essa regra.
Observe, na figura 4, que o registrador TRISA est no banco 1.
Para termos acesso a esse registrador precisamos selecionar o banco 1,
escrevendo BANCO_1 (label que definimos para isso).
Os demais pinos no sero utilizados e no precisamos configur-los, mas
aqui vai uma dica:
Configure como entrada os pinos que no estiverem sendo utilizados, pois,
se estiverem configurados como sada e se, por engano, um destes pinos for ligado diretamente ao
VSS ou ao VDD, poder provocar a queima do microcontrolador. Estando configurados como
entrada, eles assumem alta impedncia e no tem problema se forem ligados diretamente no VDD
ou no VSS.
O pino RA0 ser configurado como sada e os demais pinos do PORTA
como entrada, ento, precisamos escrever o nmero binrio 11111110 no registrador TRISA (os bits
em um registrador esto na seguinte ordem: bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0).

12

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

No existe uma instruo para escrever diretamente um nmero num


registrador do PIC16F628A.
No microcontrolador existe um registrador chamado de W (Work).
Quando queremos escrever um nmero num registrador, primeiramente
devemos escrever esse nmero no registrador W.
Fazemos isso com a instruo MOVLW, desta forma:
MOVLW

B'11111110'

Assim, escreve-se no registrador W o nmero binrio 11111110.


O nome das instrues foram criados de forma a lembrar a sua funo.
No caso da instruo MOVLW, MOV lembra mover. L lembra literal. A
instruo MOVLW move um nmero para o registrador W. Reparou na correspondncia? (move L
para W).
Com o nmero j escrito no registrador W, podemos escrev-lo no
registrador TRISA, usando a instruo MOVWF, assim:
MOVWF

TRISA

A instruo MOVWF move o que estiver no registrador W para o


registrador escrito aps a instruo, no caso, o TRISA.
Melhor dizendo, o contedo do registrador W copiado para o TRISA, pois,
depois de executada a instruo, o registrador W continua com o mesmo valor que estava antes.
Pronto, configuramos o pino RA0 para funcionar como sada e os demais
pinos do PORTA para funcionarem como entrada.
Agora vamos configurar todos os pinos do PORTB como entrada, pelo
mesmo motivo que configuramos os outros pinos do PORTA.
O registrador TRISB onde configuramos os pinos do PORTB como
entrada ou sada:
MOVLW
MOVWF

B'11111111'
TRISB

No PIC16F628A, bem como noutros modelos de microcontroladores, a


maioria dos pinos so compartilhados por mais de um recurso do microcontrolador.
o caso do pino RA0 que estamos utilizando.
Alm de ele ser um pino que podemos usar como entrada ou sada de sinal,
tambm um dos pinos de entrada do mdulo comparador.
O mdulo comparador um circuito do PIC16F628A que funciona como
um CI comparador de tenso.
Na inicializao do PIC16F628A, os pinos RA0, RA1, RA2 e RA3, esto
vinculados ao mdulo comparador de tenso e, por isso, para que possamos utiliz-los como pinos
de entrada ou sada de sinal, precisamos configurar o registrador CMCON.
O registrador CMCON est no banco 0 de memria, conforme voc pode
ver na figura 4 e, ento, selecionamos este banco, escrevendo BANCO_0.
Conforme pode ser visto no datasheet do PIC16F628A, se os bits 2, 1 e 0 do
CMCON tiverem os valores 1, 0, e 1, respectivamente, os pinos RA0 e RA3 ficaro disponveis
para serem usados como entrada ou sada e se os valores desses mesmos bits forem 1, 1 e 1, os
pinos RA0, RA1, RA2 e RA3 ficaram disponveis.
No nosso caso qualquer das duas alternativas serve, pois, s iremos usar o
pino RA0.
Ento, vamos escrever o valor B'00000111' no registador CMCON:
MOVLW
MOVWF

B'00000111'
CMCON

13

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

So apenas esses os Registradores de Uso Especfico que precisamos


configurar nesse programa.
O prximo passo inicializar as variveis.
;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF

INI_DELAY_0
DELAY_0
INI_DELAY_1
DELAY_1
INI_DELAY_2
DELAY_2

;W = INI_DELAY_0
;INICIALIZA DELAY_0
;W = INI_DELAY_1
;INICIALIZA DELAY_1
;W = INI_DELAY_2
;INICIALIZA DELAY_2

;***********************************************************************************************

Inicializar as variveis escrever nesses registradores os valores que eles


devem ter na inicializao do programa.
Ns criamos 3 variveis: DELAY_0, DELAY_1 e DELAY_2.
A varivel DELAY_0 deve ser iniciada com o valor decimal 255. A
DELAY_1 com o valor decimal 50 e a DELAY_3 com o valor decimal 13.
Ns criamos constantes para esses valores, que foram INI_DELAY_0, para
o valor 255, INI_DELAY_1, para o valor 50 e INI_DELAY_2, para o valor 13.
Por isso, quando escrevemos MOVLW INI_DELAY_0, o registrador W
assume o valor 255, ocorrendo o mesmo para os outros dois valores.
O prximo passo a rotina principal do programa.
Nosso programa aguarda que passe meio segundo e testa o LED para ver se
est aceso ou apagado. Se estiver aceso, apaga e se estiver apagado, acende, voltando a aguardar
meio segundo para testar o LED novamente.
H mais de uma forma de contar este tempo de meio segundo. Neste
programa vamos fazer isso decrementando os valores de variveis. No prximo programa iremos
utilizar outra forma mais eficiente.
Nossa rotina ir decrementar a varivel DELAY_0 at que ela chegue ao
valor 0.
Quando DELAY_0 chega ao valor 0, ela reiniciada e a varivel DELAY_1
decrementada.
Quando DELAY_1 chega a 0, ela reiniciada e a varivel DELAY_2
decrementada.
Quando DELAY_2 chegar a 0 ter passado aproximadamente meio segundo.
A maioria das instrues no PIC16F628A so executadas em 1 ciclo de
instruo, sendo 1 ciclo de instruo igual a 4 ciclos do sinal de clock. Algumas instrues so
executadas em 2 ciclos de instruo, entre elas GOTO e CALL.
Neste projeto, estamos utilizando o oscilador interno numa frequncia de 4
MHz e, portando, o ciclo do sinal de clock de 250 nanosegundos (1/4.000.000). Sendo assim, o
ciclo de instruo de 1 microssegundo.
Durante a simulao, iremos medir o tempo gasto at que DELAY_2 chegue
a 0, para ento definirmos os valores definitivos das variveis, pois, os valores que definimos so
uma estimativa.
Vamos l!
14

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Primeiramente escrevemos a label PRINCIPAL.


Toda vez que quisermos que o programa volte a este ponto escreveremos:
GOTO
PRINCIPAL. (goto em Ingls significa v para).
H certo preconceito a respeito da instruo GOTO. Algumas pessoas dizem
que se deve evitar usar essa instruo.
O que se deve evitar us-la desnecessariamente.
Sempre que for necessrio usar essa instruo use-a sem medo. Ela foi feita
para ser usada!
A primeira instruo DECFSZ
DELAY_0,F
Essa instruo decrementa o valor de DELAY_0 e, aps, verifica se o valor
ficou igual a 0.
Repare na letra F aps o DELAY_0. Ela indica que o resultado ser gravado
nele prprio, ou seja, supondo que o valor de DELAY_0 fosse 255, ento, ficar igual a 254.
Se a letra fosse W, o resultado seria gravado no registrador W e o registrador
DELAY_0 teria ficado com o mesmo valor de antes, ou seja, W ficaria com o valor de 254 e
DELAY_0 com 255.
Se aps decrementar DELAY_0, o seu valor for igual a 0, a prxima linha
do programa ser pulada, se no, a prxima linha ser executada.
Repare no nome desta instruo: DEC vem de decrementar, F, o registrador
que ser decrementado, S, da palavra skip (neste caso, pular, em Ingls) e Z de zero. DECFSZ =
decrementa o registrador F e pula a prxima linha se o resultado for zero.
Se voc procurar fazer essas associaes entre o nome das instruo e sua
funo, ir memoriz-la mais facilmente.
Voltando ao nosso programa, se o resultado da operao for diferente de
zero, a prxima linha do programa ser executada.
O que precisamos que ocorra quando a varivel DELAY_0 ainda no
chegou a 0?
Precisamos que ela continue a ser decrementada at que o seu valor seja
igual a 0.
Por isto, na prxima linha escrevemos:
GOTO PRINCIPAL.
Isto faz com que a varivel DELAY_0 seja decrementada novamente at que
seu valor chegue a 0, quando ento, a linha aps a instruo DECFSZ ser pulada.
Neste momento em que DELAY_0 chega a zero, ns iremos reinici-la.
Fazemos isto, da mesma forma que fizemos para escrever o seu valor, na
parte de Inicializao das Variveis:
MOVLW
MOVWF

INI_DELAY_0
DELAY_0

Aps reinicializar DELAY_0, vamos decrementar DELAY_1 e testar se seu


valor chegou a 0:
DECFSZ

DELAY_1,F

Se o seu valor no for igual a 0, o programa dever voltar para decrementar


DELAY_0 e por isto, usamos a mesma instruo de antes:
GOTO

PRINCIPAL

15

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Porm, se o valor de DELAY_1 chegou a 0, reiniciaremos DELAY_1 e


iremos decrementar DELAY_2 e testar se o seu valor chegou a 0:
MOVLW
MOVWF
DECFSZ

INI_DELAY_1
DELAY_1
DELAY_2,F

Igualmente, se DELAY_2 no chegou a 0, o programa dever voltar para


decrementar DELAY_0:
GOTO

PRINCIPAL

Mas, se DELAY_2 chegou a 0, iremos reinici-la e ter terminado a


contagem do tempo:
MOVLW
MOVWF

INI_DELAY_2
DELAY_2

Parece complicado? Com a prtica isso fica bem simples.


Recapitulando: DELAY_0 decrementada at que seu valor chegue a 0,
quando ento, DELAY_1 decrementada. Quando DELAY_1 chega a 0, DELAY_2
decrementada. Quando DELAY_2 chega a 0, a contagem de tempo terminou.
Com os valores que escrevemos provisoriamente nestas variveis,
DELAY_0 ter que zerar 50 vezes para que DELAY_1 seja zerada, enquanto que DELAY_1 ter
zerar 13 vezes para que DELAY_2 seja zerada.
Fazendo os clculos, DELAY_0 ser decrementada 165750 vezes para que a
contagem de tempo chegue ao fim.
Parece muito? Lembre-se de que o microcontrolador executa 1 instruo em
1 microssegundo.
Quando fizermos a simulao da execuo do programa, iremos medir o
tempo que demorou para DELAY_2 zerar e ento, faremos os ajustes nos valores das variveis, para
que esse tempo seja de aproximadamente meio segundo.
A rotina principal at o momento est assim:
************************************************************************************************
PRINCIPAL
DECFSZ
GOTO
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF

;ROTINA PRINCIPAL DO PROGRAMA


DELAY_0,F
PRINCIPAL
INI_DELAY_0
DELAY_0
DELAY_1,F
PRINCIPAL
INI_DELAY_1
DELAY_1
DELAY_2,F
PRINCIPAL
INI_DELAY_2
DELAY_2

;DECREMENTA DELAY_0. DELAY_0 = 0?


;NO
;SIM, W = INI_DELAY_0
;REINICIALIZA DELAY_0
;DECREMENTA DELAY_1. DELAY_1 = 0?
;NO
;SIM, W = INI_DELAY_1
;REINICIALIZA DELAY_1
;DECREMENTA DELAY_2. DELAY_2 = 0?
;NO
;SIM, W = INI_DELAY_2
;REINICIALIZA DELAY_2

16

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Agora que passou o tempo de meio segundo, devemos testar o LED para ver
se ele est aceso ou apagado.
O LED estar aceso se o pino RA0 estiver em nvel alto e apagado se estiver
em nvel baixo.
Para testar o estado deste pino, devemos verificar qual o valor do bit 0 do
registrador PORTA.
Para verificar o valor de um bit, existem 2 instrues: BTFSS E BTFSC.
BTFSS testa o bit e pula a prxima linha se o valor for 1. (BTFSS = testa o
bit do registrador F e pula se estiver setado).
BTFSC testa o bit e pula a prxima linha se o valor for 0. (BTFSC = testa o
bit do registrador F e pula se estiver limpo (clean)).
A escolha entre uma ou outra depende das particularidades do trecho do
programa onde sero usadas.
Neste nosso programa no faz diferena e, portanto, vamos escolher BTFSS:
BTFSS

LED

Voc se lembra de que ns definimos a label LED para o bit 0 do registrador


PORTA. Portanto, quando escrevemos esta instruo, aquele bit que ser testado.
Vamos supor que o valor do bit seja igual a 1 e, neste caso, a prxima linha
do programa ser pulada.
Se o valor do bit 0 do PORTA igual a 1, significa que o LED est aceso e,
ento, devemos apag-lo e para isso devemos fazer o valor do bit 0 do PORTA igual a 0.
Lembre-se de que para fazer o valor de um bit igual a 0, usamos a instruo
BCF.
BCF

LED

Com isso o LED ir apagar.


Mas, se quando testamos o bit 0 do PORTA com a instruo BTFSS, o valor
do bit era igual a 0, ento, a prxima linha do programa seria executada.
Sendo o valor do bit 0 do PORTA igual a 0, significa que o LED est
apagado e, ento, precisamos acend-lo.
Para isso usamos a instruo BSF para fazer o valor do bit 0 do PORTA
igual a 1:
BSF

LED

Com isso acendemos o LED.


Ento, este trecho do nosso programa ficou assim:
BTFSS
BSF
BCF

LED
LED
LED

;testa o valor do bit 0 do PORTA


;valor = 0, acende o LED
;valor = 1, apaga o LED

Espere. Temos um problema a:


No caso do valor do bit ser igual a 0, ele executa a instruo BSF LED e
em seguida executa a instruo BCF LED, ou seja, o LED aceso e apagado em seguida. Como
faremos para resolver isso?

Faremos assim:
17

Tutorial de Programao Assembly para Microcontroladores PIC -

BTFSS
GOTO
BCF
GOTO

LED
ACENDE_LED
LED
PRINCIPAL

ACENDE_LED
BSF
LED
GOTO PRINCIPAL
END

Parte 1 Pisca LED

;testa o valor do bit 0 do PORTA


;valor = 0, desvia
;valor = 1, apaga o LED
;desvia

;ACENDE O LED
;desvia
;Fim do programa

Desta forma, quando o valor do bit for igual a 0, o programa ser desviado
para onde est escrito ACENDE_LED, executando a instruo BSF LED.
Repare que depois de acender ou de apagar o LED ele desvia para o comeo
da rotina principal, onde, comear novamente a decrementar as rotinas.
Com isso chegamos ao final do nosso programa.
Devemos indicar o fim do programa ao MPLAB atravs da diretiva END.
Lembre-se de que ns ativamos o WDT nos bits de configurao.
O WDT um circuito que reinicia o microcontrolador caso o programa
trave.
Ele um contador que incrementado continuamente e quando atinge o
valor mximo, provoca o reset do microcontrolador.
Em algum ponto do nosso programa deveremos escrever a instruo
CLRWDT, que reinicia o contador do WDT toda vez que executada.
Caso o programa trave, esta instruo no ser executada, provocando o
reset do microcontrolador.
assim que o WDT funciona.
Vamos escrev-la no comeo da rotina principal, finalizando o programa:
;***********************************************************************************************
;
PROGRAMA: PISCA LED
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA
#DEFINE BANCO_1 BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA
;**********************************************************************************************

18

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

VARIAVEIS
CBLOCK 0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

DELAY_0
DELAY_1
DELAY_2
ENDC

;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO


;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************
;
CONSTANTES
INI_DELAY_0
INI_DELAY_1
INI_DELAY_2

EQU .255
EQU .50
EQU .13

;VALOR QUE DELAY_0 INICIA


;VALOR QUE DELAY_1 INICIA
;VALOR QUE DELAY_2 INICIA

;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04
RETFIE

;VETOR DAS INTERRUPES


;RETORNA

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF

B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;TODOS OS PINOS DO PORTB COMO ENTRADAS
;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************

19

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

;**********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF

INI_DELAY_0
DELAY_0
INI_DELAY_1
DELAY_1
INI_DELAY_2
DELAY_2

;W = INI_DELAY_0
;INICIALIZA DELAY_0
;W = INI_DELAY_1
;INICIALIZA DELAY_1
;W = INI_DELAY_2
;INICIALIZA DELAY_2

;***********************************************************************************************
PRINCIPAL
CLRWDT
DECFSZ
GOTO
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
GOTO
BCF
GOTO
ACENDE_LED
BSF
GOTO

;ROTINA PRINCIPAL DO PROGRAMA

DELAY_0,F
PRINCIPAL
INI_DELAY_0
DELAY_0
DELAY_1,F
PRINCIPAL
INI_DELAY_1
DELAY_1
DELAY_2,F
PRINCIPAL
INI_DELAY_2
DELAY_2
LED
ACENDE_LED
LED
PRINCIPAL

;LIMPA O WDT
;DECREMENTA DELAY_0. DELAY_0 = 0?
;NO
;SIM, W = INI_DELAY_0
;REINICIALIZA DELAY_0
;DECREMENTA DELAY_1. DELAY_1 = 0?
;NO
;SIM, W = INI_DELAY_1
;REINICIALIZA DELAY_1
;DECREMENTA DELAY_2. DELAY_2 = 0?
;NO
;SIM, W = INI_DELAY_2
;REINICIALIZA DELAY_2
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;DESVIA

LED
PRINCIPAL

;ACENDE O LED
;DESVIA

;**********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************

Nosso prximo passo simular a execuo do programa para ver se ele se


comporta como esperamos.
No menu Project, clique em Project Wizard.
Na janela que se abre clique em Avanar:

20

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 5
Na janela seguinte (Step One), selecione o PIC16F628A e clique em
Avanar:

Figura 6

21

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na prxima janela (Step Two), clique em Avanar:

Figura 7
Na prxima janela (Step Three), clique em Browse:

Figura 8

Na janela que se abre, escolha um local e d um nome para o projeto, por


exemplo Pisca LED e clique em Salvar:

22

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 9

Em seguida clique em Avanar

Figura 10

23

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na janela seguinte (Step Four), selecione o arquivo Pisca LED.asm,


clique em Add e em seguida clique em Avanar:

Figura 11
Na janela seguinte (Summary), clique em concluir:

Figura 12

24

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

No menu Project, clique em Build All. Na janela que se abre, clique em


Absolute:

Figura 13
A seguir, expanda a janela chamada Output:

25

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 14
A mensagem BUILD SUCCEEDED, confirma que no ocorreu nenhum
erro na compilao.
Com isto, ns j temos disponvel o arquivo Pisca LED.hex para ser gravado
no microcontrolador, criado na mesma pasta onde est o arquivo Pisca LED.asm., mas, antes vamos
simular a execuo do programa.
A mensagem Message[302] E:\PISCA LED.ASM 56 : Register in operand
not in bank 0. Ensure that bank bits are correct um aviso de que o registrador objeto da
instruo presente naquela linha do programa (linha 56), no est no banco 0, afim de que nos
certifiquemos de ter setado corretamente o banco. uma mensagem que aparece mesmo que o
banco tenha sido selecionado corretamente.
Abra o arquivo Pisca LED.asm, clicando no menu File em Open.
Clique no menu Edit, depois em Properties e depois na aba ASM File
Types e selecione Line Numbers.
Aparecero os nmeros das linhas esquerda.
V linha 56 e veja que o registrador em questo o TRISA, que est no
banco 1. Repare que ns selecionamos esse banco antes e, por isso, no precisamos nos preocupar.
O mesmo ocorre para a mensagem da linha 58.
Agora vamos simulao:
Clique no menu Debugger e depois, em Select Tool, selecione MPLAB
SIM.
Clique novamente no menu Debugger e depois em Settings
Na aba Osc/Trace, em Processor Frequency digite 4 e selecione Mhz.
Na aba Animation / Real Time Updates, selecione Enable Real Time
Watch Updates e leve o cursor todo para a esquerda Fastest.
Clique em OK.
No menu View, clique em Watch.

26

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na janela Watch, clique onde est indicado na figura abaixo, selecione o


PORTA e clique em Add SFR:

Figura 15
Depois, clique onde est indicado na figura abaixo e selecione DELAY_0 e
clique em Add Symbol.
Faa o mesmo para DELAY_1 e DELAY_2.

Figura 16

27

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Em Add SFR adicionamos os Registradores de Uso Especfico que


queremos visualizar, enquanto em Add Symbol adicionamos as variveis por ns criadas que
queremos visualizar.
No menu Window, clique em Pisca LED.asm:

Figura 17
Na imagem abaixo, a seta est apontando para a barra de botes do
simulador.
Aponte o mouse para cada boto para ver seus nomes. So eles: Run,
Halt, Animate, Step Into, Step Over, Reset e Breakpoints:

28

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 18
Clique no boto Reset.
O cursor vai para a linha 46 onde est a instruo GOTO INICIO.
Esta a posio 0X00 da memria de programa, e, portanto a instruo
contida nesta posio que o microcontrolador ir executar em primeiro lugar, quando for ligado ou
resetado.
Repare que apareceu uma seta verde do lado esquerdo:

Figura 19

29

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Esta seta indica qual instruo est para ser executada.


Clique no boto Step Into.
Este boto executa uma instruo a cada vez que pressionado.
A instruo GOTO INICIO foi executada e, portanto, o programa foi
desviado para a linha aps a label INICIO.
Clique novamente em Step Into.
Agora, a instruo representada pela label BANCO_1, ou seja, BSF
STATUS, RP0 foi executada e o banco 1 foi selecionado.
Repare na parte de baixo da janela, que o banco selecionado o 1:

Figura 20
Outras informaes podem ser vistas nessa barra, como o modelo do
microcontrolador, o valor do contador de programa (0X2), o valor do registrador W, dos bits z, dc e
c do registrador STATUS, etc...
O contador de programa PC, armazena o endereo na memria de
programa onde est a instruo que ser executado pelo microcontrolador.
Veremos o significado dos valores dos bits z, dc e c do registrador STATUS
em outra parte deste tutorial.
Continue clicando no boto Step Into e acompanhando a simulao da
execuo do programa.
Aps ser executada a instruo MOVWF DELAY_0, no menu Window
escolha a janela Watch e repare que a varivel DELAY_0 assumiu o valor 255.
Volte para a janela do programa, escolhendo-a no menu Window,
continue clicando em Step Into e depois visualize na janela Watch que DELAY_1 e DELAY_2,
assumem os valores 50 e 13 respectivamente.
Continue clicando no boto Step Into e veja que aps a instruo
DECFSZ DELAY_0 ser executada, o valor de DELAY_0 passa a ser 254 e que como o seu valor
diferente de 0, o programa volta para a linha aps a label PRINCIPAL, pois, executa a instruo
GOTO PRINCIPAL.

30

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Se continuar clicando em Step Into, voc poder acompanhar a varivel


DELAY_0 sendo decrementada.
Ela ir ser decrementada at chegar ao valor 0, quando, ento, o programa
ir pular a linha com a instruo GOTO PRINCIPAL.
Para agilizar, na janela Watch, d um duplo clique no valor da varivel
DELAY_0, e altere o seu valor para 1.
Depois, volte a clicar em Step Into e repare que, como DELAY_0 chegou
ao valor 0, a linha com a instruo GOTO PRINCIPAL pulada, sendo executadas as instrues
que reiniciam DELAY_0 e depois a que decrementa DELAY_1.
DELAY_1, agora vale 49 e como diferente de 0, o programa desviado
para onde est a label PRINCIPAL.
A partir de agora, DELAY_0 voltar a ser decrementada at chegar a 0 de
novo.
Vamos mudar os valores de DELAY_0 e de DELAY_1 para 1 e continuar
clicando em Step Into.
Veremos que DELAY_1 chega a 0, reiniciada e DELAY_2 decrementada.
Agora vamos mudar o valor das trs para 1.
Clicando em Step Into veremos que agora DELAY_2 chega a 0,
reiniciada e o programa ir executar a instruo BTFSS LED para testar o valor do bit 0 do PORTA,
o que o mesmo que verificar se o LED est aceso ou apagado.
Neste teste ele constata que o valor do bit igual a 0 e o programa, ento,
desviado para a instruo aps a label ACENDE_LED, onde executada a instruo BSF LED.
Em seguida ele volta para PRINCIPAL.
V para a janela Watch e veja que o bit 0 do PORTA foi setado, isto , seu
valor igual a 1, acendendo o LED.
Agora, o programa voltar a decrementar as variveis.
Vamos agilizar, alterando o valor das trs variveis para 1.
Desta vez no teste do bit ele verifica que o valor 1 e executa a instruo
BCF LED, fazendo o valor do bit igual a 0, apagando o LED.
Verifique na janela Watch que o bit 0 do PORTA foi apagado (= 0).
Agora vamos medir se o tempo que demora para a varivel DELAY_2
chegar a 0 de aproximadamente 500 milissegundos.
D um duplo clique na linha que contm a instruo BTFSS LED.
Voc ver que aparece uma letra B dentro de um crculo vermelho,
conforme a figura abaixo:

31

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 21

Voc acaba de inserir um Breakpoint. O programa ser interrompido toda


vez que encontrar um Breakpoint ativo.
Clique no boto Reset da barra de ferramentas do simulador e depois v
clicando em Step Into at chegar linha onde est a instruo CLRWDT.
No menu Debugger, clique em StopWatch.
Eis a janela do StopWatch:

32

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 22
Nesta janela, clique no boto Zero.
Volte para a janela do programa, selecionando-a no menu Window e
clique no boto Run da barra de ferramentas do simulador.
O programa ser executado at a linha onde est o Breakpoint, ou seja, na
linha onde est a instruo BTFSS.
Volte para a janela do StopWatch.
Veja no campo Time que se passaram 665 milissegundos desde que o
StopWatch foi zerado (quando clicamos em Zero):

33

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 23

Ou seja, est demorando 665 milissegundos para que a varivel DELAY_2


chegue a 0, mas, ns queremos que demore 500 milissegundos.
Vamos medir de quanto em quanto tempo a varivel DELAY_2
decrementada.
Para isto, vamos inserir outro Breakpoint na linha onde est a instruo
DECFSZ DELAY_2.
Aps inserir o Breakpoint, clique no boto Reset do simulador e v
clicando no boto Step Into at chegar instruo CLRWDT.
V para a janela do StopWatch e clique em Zero.
Volte para a janela do programa e clique em Run.
Quando o programa parar na linha onde est o Breakpoint v para a janela
do StopWatch.
Repare que passaram 51 milissegundos, ou seja, a varivel DELAY_2
decrementada a cada 51 milissegundos.

34

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 24

Estamos com um excesso de 125 milissegundos no tempo total.


Se ns diminuirmos o valor de inicializao da varivel DELAY_2 em 3
unidades, ou seja, diminuirmos para 10, o tempo total dever cair para cerca de 512 milissegundos.
Vamos verificar.
V para a janela do programa e na parte CONSTANTES, altere a linha
INI_DELAY_2
EQU .13 para INI_DELAY_1 EQU .10
Como alteramos o programa, precisamos compilar de novo e para isso, no
menu Project clique em Build All.
Retire o Breakpoint da linha onde est a instruo DECFSZ DELAY_2,
dando um duplo clique nessa linha, e deixe o outro que est na linha com a instruo BTFSS LED.
Clique no boto Reset do simulador e v clicando em Step Into at
chegar linha com a instruo CLRWDT. Neste momento, v para a janela StopWatch e clique
em Zero.
Volte para a janela do programa e clique no boto Run do simulador.
Quando o programa parar no Breakpoint, abra a janela StopWatch.
Repare que realmente o tempo total caiu para 512 milissegundos.

35

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 25
Ainda temos um excesso de 12 milissegundos.
Vamos experimentar diminuir o valor de inicializao de DELAY_1 para 49,
da mesma forma que mudamos o valor de DELAY_2.
Lembre-se de que temos que compilar de novo, clicando no menu Project
e em Build All.
Agora o tempo total bem prximo de 500 milissegundos:

Figura 26
36

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Vamos experimentar diminuir o valor da varivel DELAY_0 para 254.


Agora, o tempo de praticamente 500 milissegundos.

Figura 27

Ficamos, ento com estes valores para as variveis: DELAY_0 = 254,


DELAY_1 = 49 e DELAY_2 = 10.
Nosso programa est como queramos e agora hora de grav-lo no
microcontrolador.
Voc poder comprar um gravador ou montar o seu prprio gravador.
H vrios modelos venda e tambm vrios esquemas de gravadores na
Internet para quem quiser montar o seu.
Existem gravadores que so conectados na porta paralela, outros na porta
serial e tambm os que so conectados na porta USB.
Os melhores so os USB, pela praticidade.
Alguns gravadores funcionam com o MPLAB, enquanto outros necessitam
de outro software.
A figura a seguir de um esquema de gravador para ser conectado na porta
serial do computador (conector DB9).

37

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 28
Para utiliz-lo necessrio o programa IC-prog:
http://www.ic-prog.com/icprog106B.zip
Tambm necessrio o driver para Windows XP:
http://www.ic-prog.com/icprog_driver.zip.
At hoje apenas utilizei este programa no Windows XP, e por isso, no
posso garantir que o mesmo funcione em verses posteriores do Windows.
Descompacte os arquivos do programa e do driver numa mesma pasta.
Na primeira vez que o IC-prog executado ele apresenta a janela mostrada
na figura a seguir. Clique em OK.

38

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 29

Na prxima janela tambm clique em OK, deixando como est, pois, este
gravador baseado no JDM.

Figura 30
Se for exibida a mensagem vista na figura a seguir ou outras de mesmo teor
clique em OK.

39

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 31
A janela do IC-prog vista na figura a seguir.

Figura 32
No menu Settings, clique em Options.
Na aba Language escolha Portuguese.
No menu Configurao clique em Opes.
Na aba Diversos, marque Activar Driver NT/2000/XP
40

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na janela que abre clique em Yes para reiniciar o IC-prog.

Figura 33
Na janela que se abre, perguntando se deseja instalar o driver, clique em
Yes.

Figura 34
No menu Configurao, clique em Opes e na aba Diversos, em
Processo Prioritrio, selecione Alto e clique em OK.
41

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

No menu Configurao, aponte para Dispositivo e depois para


Microchip PIC e escolha o PIC16F628A.
No menu Arquivo, clique em Abrir.
Localize e selecione o arquivo Pisca LED.hex e clique em Abrir.

Figura 35

Repare do lado direito da janela, que o tipo de oscilador e os Fusveis j


esto configurados, pois ns os configuramos no programa, com a diretiva CONFIG.
Certifique-se de que o gravador est conectado na porta serial do
computador.
No menu Comando, clique em Programar Tudo e na janela de
confirmao, clique em Yes.
Ser gravado o programa no microcontrolador e depois o programa gravado
ser lido e comparado com o arquivo. Se estiverem iguais, ser apresentada a mensagem
Dispositivo verificado com sucesso, conforme figura a seguir.

42

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 36
Agora podemos montar o circuito da figura 2 e constatar o seu
funcionamento.
Aqui termina a primeira parte deste tutorial. Espero que voc tenha gostado.
Na prxima parte, vamos criar um programa para a mesma finalidade,
porm, utilizando o TIMER 0 para obter o intervalo de meio segundo entre as piscadas do LED.

43

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Parte 2
Pisca LED II
Nesta 2 parte iremos montar o mesmo circuito da Parte 1, mas utilizaremos
o Timer 0 do PIC16F628A para obter a frequncia de cerca de 1 Hz para o LED.
O Timer 0 um circuito do microcontrolador que incrementa um registrador
chamado TMR0, ou seja, um circuito que faz com que o valor desse registrador v aumentando de
1 em 1.
O registrador TMR0 de 8 bits (como todos os registradores do
PIC16F628A) e, portanto, seu valor pode variar de 0 a 255. O seu valor pode ser lido e tambm
alterado, ou seja, podemos escrever o valor que quisermos nele (de 0 a 255).
O Timer 0 pode ser configurado para incrementar o registrador TMR0 a
partir do ciclo de instruo ou a partir do ciclo de um sinal externo aplicado no pino T0CKI (pino 3).
Quando ele incrementado pelo ciclo de instruo, diz-se que ele est sendo
usado como timer e quando incrementado por um sinal aplicado no pino T0CKI, diz-se que ele
est sendo usado como contador (pois pode ser usado para contar os ciclos do sinal externo).
No nosso caso vamos configur-lo para que seja incrementado a partir do
ciclo de instruo, pois, desejamos obter um determinado intervalo de tempo, conhecendo o tempo
de durao do ciclo de instruo.
Podemos configurar o Timer 0 para que o registrador TMR0 seja
incrementado a cada ciclo ou para que seja incrementado a cada 2, 4, 8, 16, 32, 64, 128 e 256 ciclos.
Isso o que se chama de Prescaler. Quando ele estiver configurado para incrementar a cada ciclo,
dizemos que o valor do prescaler 1:1, quando for incrementado a cada 2 ciclos, 1:2, e assim por
diante.
Quando o registrador TMR0 estiver com o valor 255, o prximo incremento
far seu valor voltar a 0 e, ento, dizemos que ele estourou.
Quando o TMR0 estoura, o bit T0IF do registrador INTCON setado, ou
seja, o valor desse bit passa a ser igual a 1, sendo que ele precisa ser apagado na rotina do programa
para que se detecte nova mudana de seu estado. Ao mesmo tempo uma interrupo provocada, se
estiver habilitada.
A vantagem de se usar o Timer 0 para obter o tempo que desejamos que o
programa fica livre para executar outras funes, bastando monitorar o estado do bit T0IF para ver
se o tempo que desejamos j passou. Outra opo habilitar a interrupo de estouro do Timer 0.
O intervalo de tempo que precisamos de 500 milissegundos.
Para uma frequncia do oscilao de 4 MHz, o ciclo de instruo de 1
microssegundo, como j vimos na parte 1 deste tutorial.
Dividindo 500 milissegundos por 1 microssegundo, obtemos o valor de
500.000, ou seja, a cada 500.000 ciclos de instruo tero se passado 500 milissegundos.
Se configurarmos o prescaler do Timer 0 para 1:1, ou seja, se o registrador
TMR0 for incrementado a cada ciclo de instruo, ele ir estourar a cada 256 microssegundos.
Como este tempo muito menor do que o que estamos querendo, vamos
configurar o prescaler para o seu valor mximo, isto , para 1:256.
Dessa forma, o TMR0 ser incrementado a cada 256 ciclos de instruo, ou
seja, a cada 256 microssegundos.
Assim, o TMR0 ir estourar a cada 256 x 256 microssegundos, isto , a cada
65.536 microssegundos, o que equivale a 65,536 milissegundos.

44

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Ou seja, mesmo com o prescaler no mximo, sero necessrios mais de 1


estouros do TMR0 para obtermos o tempo que desejamos e, portanto, teremos que contar esses
estouros.
Porm, a diviso de 500 milissegundos por 65,536 milissegundos no
resulta em um nmero exato.
Temos que, de alguma forma, obter um nmero exato de estouros que
correspondam ao tempo de 500 milissegundos.
Como vimos, 500 milissegundos correspondem a 500.000 ciclos de
instruo.
Dividindo 500.000 pelos valores de prescaler disponveis, constatamos que
o maior valor do prescaler que resulta numa diviso exata 1:32 e este valor 15.625.
Por sua vez, 15.625 igual ao produto de 125 por 125.
Com o valor do prescaler definido em 1:32, o TMR0 ser incrementado a
cada 32 ciclos de instruo, ou seja, a cada 32 microssegundos.
Se aps todas as vezes que o TMR0 estourar, ns o reiniciarmos com o valor
de 131 (escrevendo este valor nele), aps 125 incrementos (256 131) ele ir estourar, ou seja, ir
estourar a cada 32 x 125 microssegundos = 4.000 microssegundos = 4 milissegundos.
Se contarmos 125 estouros do TMR0, teremos o tempo de 500
milissegundos.
Vamos ao programa!
O fluxograma o mesmo e o programa igual at este ponto:
;***********************************************************************************************
;
PROGRAMA: PISCA LED II
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE
#DEFINE

BANCO_0
BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************

Para no ter de escrever tudo de novo, no MPLAB, abra o arquivo Pisca


LED.asm e, no menu File, clique em Save As... e mude o nome do arquivo para Pisca LED
II.asm e v fazendo as alteraes.
O prximo passo do programa a definio das variveis.
Iremos utilizar apenas uma varivel, que ser usada para contar os estouros
do TMR0.
Vamos nome-la de CONT_EST_TMR0:
;**********************************************************************************************
;
VARIVEIS
CBLOCK

0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

45

Tutorial de Programao Assembly para Microcontroladores PIC CONT_EST_TMR0


ENDC

Parte 2 Pisca LED II

;USADO PARA CONTAR OS ESTOUROS DO TMR0


;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************

O prximo passo a definio das constantes.


Iremos utilizar duas constantes, uma no valor de 131 que ser usada para
reinicializar o TMR0 e outra no valor de 125 para a varivel que ir contar os estouros do TMR0.
Vamos cham-las de INI_TMR0 e INI_CONT_EST_TMR0.
A partir da, o programa igual at a configurao dos registradores:
;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0

EQU .131
EQU .125

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA

;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04
RETFIE

;VETOR DAS INTERRUPES


;RETORNA

;***********************************************************************************************

Como iremos utilizar o Timer 0, precisamos configurar o registrador


OPTION_REG, que est associado a ele.
Esse registrador encontra-se no banco 1 de memria.
Conforme consta no datasheet do PIC16F628A, o bit 5 desse registrador, o
que define se o TMR0 ser incrementado pelo ciclo de instruo ou a partir de um sinal externo.
Para que ele seja incrementado pelo ciclo de instruo, o valor desse bit deve ser igual a 0.

O bit 3 define se o prescaler ser usado pelo Timer 0. Para que o Timer 0
use o prescaler, o valor desse bit deve ser igual a 0.
Os bits 2, 1 e 0 definem o valor do prescaler. No nosso caso, iremos utilizar
o valor 1:32, e, portanto, os valores desses bits devero ser 1, 0 e 0, respectivamente.
Os demais bits no nos interessam e, portanto, vamos deix-los com o valor
1, valor com o qual eles so inicializados.
Dessa forma, iremos escrever o seguinte nmero binrio no registrador
OPTION_REG: 11010100.
As configuraes dos outros registradores so as mesmas.
A seguir, inicializamos a varivel e teremos chegado rotina principal:

46

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF

B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

;TODOS OS PINOS DO PORTB COMO ENTRADAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************
;
INICIALIZACAO DA VARIAVEL
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0

;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0

;***********************************************************************************************
PRINCIPAL

;ROTINA PRINCIPAL DO PROGRAMA

A primeira instruo da rotina principal CLRWDT para limpar o WDT.


A seguir, iremos testar o bit T0IF do registrador INTCON para verificarmos
se o TMR0 estourou:
BTFSS

INTCON,TOIF

;TMR0 ESTOUROU?

Se o TMR0 no houver estourado, o valor desse bit ser igual a 0 e a


prxima linha do programa ser executada. Portanto, nessa linha escreveremos a instruo GOTO
PRINCIPAL, para que o bit seja testado novamente.
GOTO

PRINCIPAL

;NAO

Se o TMR0 houver estourado, o valor do bit ser igual a 1 e a linha com a


instruo GOTO PRINCIPAL ser pulada.
Nesse caso, a primeira providncia que iremos tomar zerar o bit TOIF para
que na prxima vez que o TMR0 estourar possamos detectar a mudana do seu valor para 1:
BCF

INTCON,T0IF

;SIM

A seguir, iremos reiniciar o TMR0 com o valor 131, usando a constante que
criamos:
MOVLW
MOVWF

INI_TMR0
TMR0

;W = INI_TMR0
;REINICIA TMR0

Em seguida, decrementamos o valor da varivel e ao mesmo tempo


verificamos se o seu valor chegou a 0:
DECFSZ

CONT_EST_TMR0,F

;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

Se o seu valor no for igual a 0, a prxima linha ser executada e, nesse caso,
desviaremos o programa para o comeo da rotina principal:
GOTO

PRINCIPAL

;NAO

47

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Se o valor da varivel houver chegado a 0, iremos reinici-la e, nesse caso,


tero se passado cerca de 500 milissegundos.
A partir daqui, o resto da rotina igual ao do programa da parte I deste
tutorial.
Portanto, o programa ficou assim:
;***********************************************************************************************
;
PROGRAMA: PISCA LED II
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE
#DEFINE

BANCO_0
BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************
;
VARIVEIS
CBLOCK

0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

CONT_EST_TMR0

;USADO PARA CONTAR OS ESTOUROS DO TMR0

ENDC

;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0

EQU .131
EQU .125

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA

;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04
RETFIE

;VETOR DAS INTERRUPES


;RETORNA

48

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF

B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

;TODOS OS PINOS DO PORTB COMO ENTRADAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************
;
INICIALIZACAO DA VARIAVEL
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0

;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0

;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
GOTO
BCF
GOTO
ACENDE_LED
BSF
GOTO

INTCON,T0IF
PRINCIPAL
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
PRINCIPAL
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED
ACENDE_LED
LED
PRINCIPAL

;LIMPA O WDT
;TMR0 ESTOUROU?
;NAO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;DESVIA

LED
PRINCIPAL

;ACENDE O LED
;DESVIA

;**********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************

Salve o arquivo.
A seguir iremos simular a execuo do programa com o MPLAB SIM.
No menu Project, clique em Open. Localize o projeto de nome Pisca
LED, selecione-o e clique em Abrir.
No menu Project, em Remove Files to Project, clique no arquivo Pisca
LED.asm (o da parte I) para remov-lo.
No menu Project, clique em Add Files to Project..., localize o arquivo
Pisca LED II.asm (o novo), selecione-o e clique em Abrir.
No menu Project, clique em Buid All.
Verifique se a montagem foi feita com sucesso, selecionando a janela
Output no menu Window:

49

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Figura 1
Selecione a janela com o programa Pisca LED II.asm, no menu Window e
execute o programa at a linha que contm a instruo CLRWDT, clicando no boto Step Into da
barra do simulador.
Insira um Breakpoint na linha que contm a instruo BTFSS LED, dando
um duplo clique nessa linha:

Figura 2
A seguir, selecione a janela Stop Watch no menu Window e clique em
Zero.
Volte para a janela do programa e clique no boto Run do simulador. O
programa ir parar no Breakpoint.
50

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

V para a janela do Stop Watch e veja que demorou 505 milissegundos


para o programa chegar neste ponto, ou seja, a cada 505 milissegundos o LED ser testado e
mudar de estado.

Figura 3
O erro de 5 milissegundos devido ao tempo gasto com as instrues que reiniciam o TMR0 com o
valor 131 toda vez que ele estoura.
Experimente mudar este valor para 132 (na constante), monte novamente o
projeto e volte a fazer a simulao e medir o tempo.
Voc ver que o tempo agora de 497 milissegundos:

Figura 4

Como a diferena menor, ficaremos com esse valor.


51

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Este projeto no exige um tempo exato, pois, no se trata, por exemplo, de


um relgio.
Programas de relgio usam cristais cujo valor da frequncia um mltiplo
de 2 e desta forma, no preciso reiniciar o Timer, deixando que ele rode de 0 a 255.
Em outra parte deste tutorial voltaremos a falar sobre esse assunto.
Grave o programa no microcontrolador e constate o seu funcionamento!
Aqui termina a 2 parte deste tutorial.
Na prxima parte, vamos continuar com este circuito, mas utilizaremos o
recurso da interrupo provocada pelo estouro do Timer 0.

52

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Parte 3
Pisca LED III
Nesta terceira parte, continuaremos com o mesmo circuito utilizado at
agora.
O Timer 0 continuar sendo usado para obtermos o tempo de cerca de 500
milissegundos entre as mudanas de estado do LED.
A diferena que iremos habilitar a interrupo do Timer 0 para que no
seja necessrio ficar testando o bit T0IF para sabermos quando o registrador TMR0 estourou.
O recurso de interrupo permite que o microcontrolador possa executar
outras tarefas, sendo interrompido quando ocorre o evento esperado, quando ento, os
procedimentos relativos a esse evento so tomados.
Quando ocorre uma interrupo, o microcontrolador salva o endereo da
prxima instruo que seria executada e desvia para o endereo 0X04 da memria de programa,
executando a instruo contida nesse endereo.
Quando o microcontrolador encontra uma instruo chamada RETFIE, ele
recupera o endereo da instruo que seria executada antes de ocorrer a interrupo, voltando a
executar o programa do ponto onde havia sido interrompido.
A interrupo de cada perifrico do microcontrolador, como o Timer 0, pode
ser habilitada ou desabilitada individualmente atravs de um bit especfico.
Alm disso, tambm existe um bit (PEIE - bit 6 do registrador INTCON),
que permite habilitar e desabilitar as interrupes de todos os perifricos ao mesmo tempo e outro
bit (GIE bit 7 do mesmo registrador) que permite habilitar e desabilitar todas as interrupes do
microcontrolador ao mesmo tempo. Isso porque, alm das interrupes dos perifricos existem as
interrupes por mudana de estado em determinados pinos do PORTB.
Conforme consta no datasheet do PIC16F628A, para habilitar a interrupo
do Timer 0, precisamos setar o bit 5 (T0IE) do registrador INTCON, ou seja, fazer com que o
valor deste bit seja igual a 1.
Como o Timer 0 um perifrico, tambm precisamos setar o bit PEIE (bit 6
do INTCON) para habilitar as interrupes de perifricos.
Finalmente, setamos o bit GIE (bit 7 do INTCON) para habilitar as
interrupes de forma geral.
Vamos ao programa!
No MPLAB, abra o arquivo Pisca LED II.asm, salve-o com o nome Pisca
LED III.asm e faa as alteraes, para no ter de digitar tudo novamente.
O programa igual ao da Parte 2 at este ponto:

;***********************************************************************************************
;
PROGRAMA: PISCA LED III
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

53

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE
#DEFINE

BANCO_0
BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************

O prximo passo a definio das variveis.


Quando estamos trabalhando com interrupes, a primeira providncia que
devemos tomar dentro da rotina de interrupo salvar os contedos dos registradores W e
STATUS.
O registrador W, como j vimos, aquele onde primeiramente escrevemos o
valor que dever ser gravado em algum registrador, ou para onde copiamos o valor de um
registrador para depois escrev-lo em outro, pois no possvel escrevermos diretamente nos
registradores, bem como, copiarmos o valor de um registrador diretamente para outro.
No registrador STATUS, onde selecionamos o banco de memria de dados
(bits RP0 e RP1) e onde o microcontrolador registra informaes sobre o estouro do WDT, entrada
em modo de economia de energia (Sleep), bem como, se operaes de soma, subtrao, rotao de
bits, etc... resultaram em zero e se houve estouro dos registradores envolvidos.
Nos programas que fizemos at agora, no efetuamos nenhuma leitura do
registrador STATUS, porque foram programas bem simples.
necessrio salvar os contedos dos registradores W e STATUS porque eles
so usados durante a rotina de interrupo.
No retorno da interrupo, se estes registradores no estiverem com os
valores que estavam antes, ocorrer um erro.
Criaremos uma varivel chamada W_TEMP para salvarmos o valor do
registrador W e outra chamada STATUS_TEMP para o registrador STATUS.
Esses nome so apenas sugestivos.
A varivel CONT_EST_TMR0 ter a mesma funo do programa anterior,
ou seja, a de contar os estouros do registrador TMR0.
A partir da definio das variveis, o programa igual at a rotina de
interrupo:
;**********************************************************************************************
;
VARIVEIS
CBLOCK 0X20
W_TEMP
STATUS_TEMP
CONT_EST_TMR0
ENDC

;ENDERECO INICIAL DA MEMORIA DO USUARIO


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;USADA PARA CONTAR OS ESTOUROS DO TMR0


;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************

54

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

CONSTANTES

INI_TMR0
INI_CONT_EST_TMR0

EQU .131
EQU .125

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA

;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

Nos programas utilizados nas partes 1 e 2 deste tutorial, havia aqui apenas a
instruo RETFIE, pois no utilizamos o recurso de interrupo, e a instruo RETFIE servia para
se, por acaso, ocorresse uma interrupo inesperada, o programa voltasse ao ponto de onde havia
sido desviado.
Agora iremos habilitar a interrupo de estouro do Timer 0 e, quando ela
ocorrer, o microcontrolador ir executar o cdigo contido a partir daqui.
Primeiramente vamos salvar os valores dos registradores W e STATUS,
copiando-os para as variveis W_TEMP e STATUS_TEMP.
A Microchip, fabricante do PIC16F628A, recomenda a seguinte sequncia
de instrues para salvar os contedos dos registradores W e STATUS:
MOVWF
SWAPF
BANCO_0
MOVWF

W_TEMP
STATUS,W
STATUS_TEMP

;SALVA W EM W_TEMP
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS

O registrador W salvo em W_TEMP atravs da instruo MOVWF.


A seguir, com a instruo SWAPF, inverte-se os nibles (os 4 bits mais
significativos com os 4 bits menos significativos) do registrador STATUS, gravando o resultado no
W.
A seguir, seleciona-se o banco 0 (mesmo que j estivesse selecionado) e,
depois, o contedo do registrador STATUS (que estava no W com os nibbles invertidos) salvo no
STATUS_TEMP, com a instruo MOVWF.
Uma vez salvos os contedos dos registradores W e STATUS, testamos o bit
T0IF do registrador INTCON para confirmarmos se a interrupo foi causada pelo estouro do Timer
0:
BTFSS

INTCON,T0IF

;TMR0 ESTOUROU?

Se o bit T0IF no estiver setado, significando que a interrupo no foi


causada pelo estouro do Timer 0, a prxima linha do programa ser executada, e, nesse caso, temos
de fazer o programa voltar da interrupo.

55

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Para isso usamos a instruo RETFIE, porm, antes, temos de recuperar os


valores dos registradores W e STATUS.
Faremos isso executando as seguintes instrues, recomendadas pela
Microchip:
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

;W = SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

Repare que feito um swap no registrador STATUS_TEMP, pois havia


sido feito antes, voltando a apresentar a ordem correta dos nibbles.
A seguir o valor do registrador STATUS recuperado atravs da instruo
MOVWF STATUS.
Tambm realizado um swap no registrador W_TEMP e, como no havia
sido feito antes, faz-se outro em seguida. Ao mesmo tempo, o resultado salvo no registrador W.
A seguir, vem a instruo RETFIE que faz o microcontrolador retornar da
interrupo.
Lembrando que esse procedimento recomendado pela Microchip e pode
ser visto no datasheet do PIC16F628A.
Como teremos mais de uma situao em que precisaremos retornar da
interrupo, para evitarmos repetir as instrues acima, deixando nosso cdigo o mais resumido
possvel, iremos colocar essas instrues no fim da rotina de interrupo, aps a label SAI_INT.
Assim, quando quisermos retornar da interrupo, usaremos a instruo
GOTO SAI_INT:
GOTO

SAI_INT

;RETORNA DA INTERRUPO

Se o bit T0IF estiver setado, indicando que a interrupo foi causada pelo
estouro do Timer 0, a linha com a instruo GOTO SAI_INT ser pulada, e, nesse caso, na prxima
instruo apagaremos o bit T0IF:
BCF

INTCON,T0IF

;SIM

necessrio apagar esse bit, caso contrrio, quando o programa retornar da


interrupo, outra ser gerada em seguida, j que o bit ainda estar setado.
Continuando com a rotina, vm agora as instrues que reiniciam o
registrador TMR0:
MOVLW
MOVWF

INI_TMR0
TMR0

;W = INI_TMR0
;REINICIA TMR0

A seguir decrementamos a varivel que conta os estouros do Timer 0 e ao


mesmo tempo verificamos se ela chegou a 0:
DECFSZ

CONT_EST_TMR0,F

;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

Se o valor dessa varivel no houver chegado a zero, a prxima linha do


programa ser executada.
Nesse caso, novamente iremos retornar da interrupo e, ento, escrevemos
a instruo GOTO SAI_INT:
GOTO

SAI_INT

;NAO

56

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

J, se a varivel houver chegado a 0, essa linha ser pulada e seguem-se as


instrues que reiniciam a varivel:
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0

;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0

A seguir, testamos o estado do LED e, aps mud-lo, retornamos da


interrupo:
BTFSS
GOTO
BCF
GOTO

LED
ACENDE_LED
LED
SAI_INT

ACENDE_LED
BSF
LED

;TESTA O VALOR DO BIT 0 DO PORTA


;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;RETORNA DA INTERRUPCAO

;ACENDE O LED

Recapitulando:
O Timer 0 foi configurado para estourar a cada 4 milissegundos. A cada vez
que o registrador TMR0 estoura, gerada uma interrupo, onde a varivel CONT_EST_TMR0
decrementada. Como essa varivel iniciada com o valor 125, quando ela chega a 0, tero se
passado cerca de 500 milissegundos, quando, ento, o estado do LED testado e alterado.
Ou seja, o que era feito na rotina principal do programa na parte 2 deste
tutorial, agora feito dentro da rotina de interrupo.
O programa da parte 2 fica testando o bit T0IF para detectar quando ele for
setado. Aqui, no precisamos fazer isto, porque, quando o bit setado, gerada uma interrupo.
A cada interrupo, a varivel CONT_EST_TMR0 decrementada. Quando
o seu valor chega a 0, mudamos o estado do LED.
Neste programa to simples, talvez voc no veja muita vantagem nisso,
mas, em programas mais complexos, o recurso da interrupo muito til.
Nosso objetivo aqui foi explicar como usar o recurso da interrupo do
microcontrolador.
Com isso conclumos a rotina de interrupo que ficou assim:
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS

;VETOR DAS INTERRUPES

W_TEMP
STATUS,W
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
SAI_INT
;NAO
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA

57

Tutorial de Programao Assembly para Microcontroladores PIC -

GOTO
BCF
GOTO
ACENDE_LED
BSF
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

ACENDE_LED
LED
SAI_INT

;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO

LED

;ACENDE O LED

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

Parte 3 Pisca LED III

;**********************************************************************************************

O prximo passo a configurao dos registradores de uso especfico.


A diferena aqui em relao ao programa da parte 2, a configurao do
registrador INTCON.
Conforme j havamos comentado, temos que setar os bits 5 (T0IE), 6
(PEIE) e 7 (GIE) do registrador INTCON e, portanto, escreveremos o valor binrio 11100000
neste registrador:
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

;TODOS OS PINOS DO PORTB COMO ENTRADAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;**********************************************************************************************

A seguir vem a inicializao da varivel CONT_EST_TRMR0.


No necessrio inicializar W_TEMP e STATUS_TEMP, pois, no so
variveis que precisam ter um determinado valor na inicializao.
Finalmente, vem a rotina principal, que consiste apenas na execuo da
instruo CLRWDT.
O programa fica executando a instruo CLRWDT at que ocorra uma
interrupo.
O programa completo ficou assim:

58

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

;***********************************************************************************************
;
PROGRAMA: PISCA LED III
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0
#DEFINE BANCO_1

BCF STATUS,RP0
BSF STATUS,RP0

;SETA BANCO 0 DE MEMORIA


;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************
;
VARIVEIS
CBLOCK 0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP
STATUS_TEMP
CONT_EST_TMR0

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;USADA PARA CONTAR OS ESTOUROS DO TMR0

ENDC

;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0

EQU .131
EQU .125

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA

;***********************************************************************************************
;
SADA
#DEFINE

LED PORTA,0

;LED LIGADO EM RA0

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

MOVWF
SWAPF
BANCO_0
MOVWF

W_TEMP
STATUS,W
STATUS_TEMP

;VETOR DAS INTERRUPES


;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS

59

Tutorial de Programao Assembly para Microcontroladores PIC -

BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
GOTO
BCF
GOTO

INTCON,T0IF
SAI_INT
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
SAI_INT
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED
ACENDE_LED
LED
SAI_INT

;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO

ACENDE_LED
BSF
LED

;ACENDE O LED

SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

;W = SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

Parte 3 Pisca LED III

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

;TODOS OS PINOS DO PORTB COMO ENTRADAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
;
INICIALIZACAO DA VARIVEL
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0

;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0

;***********************************************************************************************
PRINCIPAL
CLRWDT
GOTO

;ROTINA PRINCIPAL DO PROGRAMA


;LIMPA O WDT
PRINCIPAL

;**********************************************************************************************
END
;FIM DO PROGRAMA

60

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Vamos simular a execuo do programa.


Abra o MPLAB e no menu Project, clique em Open, selecione e abra o
projeto de nome Pisca LED.
No menu Project, em Remove File From Project, clique no arquivo
Pisca LED II para remov-lo.
Em seguida, no menu Project, clique em Add File To Project, selecione
o arquivo Pisca LED III e clique em Abrir para adicion-lo ao projeto.
No menu Project, clique em Build All.
Verifique se a montagem foi efetuada com sucesso:

Figura 1
No menu File, clique em Open, localize e abra o arquivo Pisca LED III.
Na barra de ferramentas do simulador, clique no boto Reset:

61

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Figura 2
Na mesma barra de ferramentas, v clicando no boto Step Into, e observe
que, na rotina principal, ele fica executando a instruo CLRWDT.
Clique duas vezes na linha da primeira instruo da rotina de interrupo
(MOVWF W_TEMP), para adicionar um breakpoint.
Abra a janela do StopWatch, no menu Window.
Clique em Zero.
Clique no boto Run da barra de ferramentas do simulador.
Na janela do Stopwatch repare que demorou cerca de 4 milissegundos
para que ocorresse uma interrupo.
V clicando no boto Step Into e observando a execuo da rotina de
interrupo, e repare que aps a execuo da instruo RETFIE ele retorna rotina principal.
Clique duas vezes na linha com o breakpoint para remov-lo e adicione
outro na linha com a instruo BTFSS LED.
Na janela do Stopwatch, clique em Zero, clique no boto Run e
depois, verifique no Stopwatch que o tempo que passou de cerca de 500 milissegundos.
Obs.: Se aparecer a mensagem da figura abaixo, no menu Debugger,
clique em Breakpoints... e remova os outros que estiverem aparecendo.

62

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Figura 3
Grave o programa no microcontrolador e teste no circuito para comprovar o
seu funcionamento.
Aqui termina a 3 parte deste tutorial.
Na prxima parte iremos adicionar um chave do tipo push-button ou seja, do
tipo pulso ao nosso circuito, atravs da qual iremos ligar e desligar nosso pisca-pisca.

63

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Parte 4
Pisca LED com boto para ligar e desligar
Agora iremos acrescentar ao nosso circuito um boto do tipo pulso N/A
(normalmente aberto) sem trava que a cada vez que for pressionado, alternar o estado do LED
entre piscando e apagado.
Nesse tipo de chave os contatos ficam fechados apenas enquanto o boto
est pressionado.
Primeiramente devemos decidir em qual pino do PIC16F628A iremos ligar
o boto.
Um boto um dispositivo de entrada de dados e, portanto, devemos
escolher um pino que possa ser configurado como entrada.
Conforme j foi exposto na parte 1 deste tutorial, todos os pinos do PORTA
e do PORTB podem ser configurados como entrada.
Vamos escolher o RA1.
Eis o esquema do nosso circuito com o boto includo:

Repare que ligamos um resistor entre o pino de entrada e o VDD, enquanto


que o boto foi ligado entre o pino e o VSS.
Todo pino configurado como entrada tem de estar ou em nvel alto ou em
nvel baixo, ou seja, ou na tenso de VDD ou na de VSS.
No nosso circuito, quando o boto est solto, o resistor mantm o pino em
nvel alto e quando o boto pressionado o pino vai para nvel baixo.
Se no houvssemos ligado o resistor, quando o boto estivesse solto, o pino
ficaria desconectado, ou seja, flutuando, ocasionando um comportamento imprevisvel do
microcontrolador quando efetuasse a leitura do estado deste pino.

64

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Poderamos, tambm, ter ligado o boto entre o pino e o VDD e o resistor


entre o pino e o VSS, mas geralmente se liga o boto no VSS.
Quando utilizamos uma chave num circuito digital, nos deparamos com um
problema:
Quando a chave acionada, a conduo da corrente eltrica em seus
contatos fica instvel durante um tempo de alguns milissegundos.
como se a chave ficasse sendo ligada e desligada at que finalmente
permanecesse ligada.
No nosso circuito, a cada vez que o boto for pressionado, o LED dever
alternar entre piscando e apagado.
Mas, com o problema da instabilidade da conduo da corrente na chave,
nunca se saberia como o LED ficaria, pois, o microcontrolador poderia detectar dois, trs, ou mais
apertos do boto a cada vez que ele fosse pressionado, devido ao problema descrito.
Para resolver esse problema, pode-se utilizar junto ao boto um circuito
conhecido como de de-bouncing, baseado em um capacitor.
Mas, quando estamos utilizando um microcontrolador, podemos dispensar o
uso deste circuito, pois possvel implementar o de-bouncing na rotina do programa.
Isso pode ser feito da seguinte forma:
Quando detectado que o estado do pino corresponde ao de boto
pressionado, ele testado por cerca de mais 50 milissegundos e, se o seu estado permanecer o
mesmo por esse tempo, considera-se que o boto foi realmente pressionado.
No nosso circuito a partir do momento em que o estado do pino RA1 for
detectado como sendo baixo, iremos testar esse pino por mais 50 milissegundos e se o estado do
pino permanecer baixo por esse tempo, iremos adotar os procedimentos correspondentes ao
acionamento do boto.
Se o seu estado voltar para alto antes de ter transcorrido o referido tempo,
iremos comear a testar o boto novamente.
Isso elimina o problema da instabilidade da conduo da corrente no
momento em que o boto pressionado.
H outro procedimento que deve ser adotado quando se utiliza um boto:
Caso se deseje que a ao seja produzida somente a cada aperto do boto (depois de realizada a
ao, mesmo que o boto seja mantido pressionado nada dever ocorrer), devemos registrar de
alguma forma que a ao j foi realizada e que se deve aguardar o boto ser solto e pressionado
novamente.
Uma forma de fazer isso, usar um bit de um registrador de uso geral. Este
bit setado aps a ao referente ao aperto do boto ser realizada e s apagado quando o boto for
solto. Bits usados para esta finalidade so chamados de flags.
Vamos ao programa!
No MPLAB, abra o arquivo Pisca LED III.asm.
No menu File, clique em Save As... e mude o nome para Pisca LED
IV.asm
A primeira alterao que faremos na seo Variveis, onde, iremos
adicionar trs: FLAGS, DB_BTA e DB_BTB.
A varivel FLAGS conter os bits de flag.
As variveis DB_BTA e DB_BTB sero usadas para a contagem do tempo
de de-bouncing do boto:

65

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

;********************************************************************************************
;
VARIVEIS
CBLOCK 0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP
STATUS_TEMP
CONT_EST_TMR0
FLAGS
DB_BTA
DB_BTB
ENDC

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
;USADA PARA CONTAR OS ESTOUROS DO TMR0
;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO
;FIM DO BLOCO DE MEMORIA

;********************************************************************************************

A seguir, vamos criar as constantes para a inicializao das variveis


DB_BTA e DB_BTB:
;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
INI_DB_BTA
INI_DB_BTB

EQU
EQU
EQU
EQU

.131
.125
.255
.50

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA
;VALOR QUE DB_BTA INICIA
;VALOR QUE DB_BTB INICIA

;**********************************************************************************************

Iremos ajustar esses valores durante a simulao, para que tenhamos um


tempo de de-bouncing em torno de 50 milissegundos.
A seguir, depois da seo Sada, vamos criar uma seo chamada
Entrada, para definirmos a label BOTAO como sendo o bit 1 do PORTA:
;***********************************************************************************************
;
ENTRADA
#DEFINE

BOTAO

PORTA,1

;BOTAO LIGADO EM RA1

;***********************************************************************************************

A seguir, iremos acrescentar uma seo chamada FLAGS onde iremos


atribuir um nome aos bits que iremos utilizar como flags:
;***********************************************************************************************
;
FLAGS
#DEFINE
#DEFINE

SOLTAR_BOTAO FLAGS,0
ESTADO_DO_LED FLAGS,1

;SE = 1 AGUARDA SOLTAR O BOTO


;SE = 1 LED PISCANDO

;***********************************************************************************************

A funo do flag SOLTAR_BOTAO, j foi explicada. A do flag


ESTADO_DO_LED veremos adiante.
Tambm faremos alteraes na rotina de interrupo, mas somente depois
que tenhamos escrito a rotina principal.

66

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

A seguir, na seo INICIALIZAO DAS VARIVEIS, vamos incluir as


novas variveis:
;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
MOVLW
MOVWF
CLRF
MOVLW
MOVWF
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0
FLAGS
INI_DB_BTA
DB_BTA
INI_DB_BTB
DB_BTB

;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0
;INICIALIZA FLAGS
;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB
;INICIALIZA DB_BTB

;***********************************************************************************************

A varivel FLAGS foi inicializada com a instruo CLRF. Esta instruo faz
todos os bits de um registrador iguais a 0.
Na rotina principal, aps a instruo CLRWDT, temos a instruo BTFSS
SOLTAR_BOTAO que testa o estado desse bit de flag.
Se o valor desse bit for 0, significando que no est se aguardando soltar o
boto, a prxima linha ser executada e programa ser desviado para onde est a label
TESTA_BOTAO, onde ser testado o estado do pino onde o boto est ligado (RA1) para ver se
est pressionado.
Porm, se o bit estiver setado, significando que est se aguardando soltar o
boto, devemos verificar se o boto j foi solto. Nesse caso, a prxima linha ser pulada e ser
executada a instruo BTFSS BOTAO, para testar o RA1.
Se o estado do RA1 for igual a 0, significa que o boto ainda no foi solto e
por isso o programa desviado para o incio da rotina PRINCIPAL, para que voltemos a test-lo
at que ele tenha sido solto.
Se o estado do RA1 for igual a 1, significa que o boto foi solto e, ento,
apagamos o flag SOLTAR_BOTAO.
Aps a label TESTA_BOTAO, temos a instruo BTFSC BOTAO, onde
testamos o estado do bit RA1 para verificarmos se o boto est pressionado.
Se ele no estiver pressionado, o estado deste bit ser igual a 1, e, portanto, a
prxima linha ser executada, desviando o programa para REINC_CONT_DEB, onde as variveis
DB_BTA e DB_BTB so reinicializadas e depois o programa desviado para o incio da rotina
principal.
Se o boto estiver pressionado (estado do bit RA1 igual a 0), a prxima
linha ser pulada e a instruo DECFSZ DB_BTA ,F ser executada, comeando o de-bouncing.
A instruo DECFSZ DB_BTA,F decrementa a varivel e ao mesmo tempo
verifica se o seu valor chegou a 0. Se no chegou, o programa retorna para o incio da rotina
PRINCIPAL e, se o boto permanecer pressionado, esta varivel ser novamente decrementada.
Toda vez que o valor de DB_BTA chega a 0, ela reinicializada e a varivel DB_BTB
decrementada. Quando o valor de DB_BTB chegar a 0, o de-bouncing ter terminado.
Mas, para que isso ocorra, necessrio que o estado do pino RA1 se
mantenha em nvel baixo durante todo esse tempo, que iremos ajustar para cerca de 50
milissegundos, atravs dos valores de inicializao de DB_BTA e DB_BTB.
Se antes disso o nvel de RA1 voltar a 1, o programa ser desviado para a
subrotina REINC_CONT_DEB, onde as variveis DB_BTA e DB_BTB so reinicializadas, para
que se comece uma nova contagem de 50 milissegundos, quando for detectado nvel baixo em RA1.

67

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Tendo o de-bouncing terminado com a varivel DB_BTB chegando a 0, ela


reiniciada.
Nesse momento podemos considerar que o boto foi pressionado e devemos
adotar as providncias decorrentes disso.
No nosso circuito, queremos que a cada vez que o boto seja pressionado, o
LED mude de estado. Se ele estiver apagado dever comear a piscar e se estiver piscando dever
parar de piscar. Portanto, quando o programa chega nesse ponto, devemos saber em que estado est
o LED.
Uma forma de sinalizar o estado atual do LED utilizar um bit de flag.
para isso que servir o bit que denominamos de ESTADO_DO_LED.
Convencionaremos que quando o valor desse bit for igual a 0, o LED estar
apagado e, quando for igual a 1, ele estar piscando.
A prxima instruo a BTFSS que verifica o valor do bit
ESTADO_DO_LED. Se ele for igual a 0, desviamos o programa para onde est a label
PISCAR_O_LED, onde, ele setado.
Se o valor do bit ESTADO_DO_LED for igual a 1, ele zerado.
Aps zerar ou setar o bit ESTADO_DO_LED, setamos o bit de flag
SOLTAR_BOTAO, que como j vimos far com que se aguarde o boto ser solto.
;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
BTFSS
GOTO
BTFSS
GOTO
BCF

SOLTAR_BOTAO
TESTA_BOTAO
BOTAO
PRINCIPAL
SOLTAR_BOTAO

TESTA_BOTAO
BTFSC
BOTAO
GOTO
REINC_CONT_DEB
DECFSZ
DB_BTA,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
DECFSZ
DB_BTB,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTB
MOVWF
DB_BTB
BTFSS
ESTADO_DO_LED
GOTO
PISCAR_O_LED
BCF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
PISCAR_O_LED
BSF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
REINC_CONT_DEB
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
MOVLW
INI_DB_BTB

;LIMPA O WDT
;AGUARDA SOLTAR O BOTAO?
;NAO, DESVIA
;SIM, O BOTO EST SOLTO?
;NAO, DESVIA
;SIM, APAGA FLAG

;O BOTO EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB_BTA. DB_BTA = 0?
;NAO, DESVIA
;SIM, W = INI_DB_BTA
;INICIALIZA DB_BTA
;DECREMENTA DB_BTB. DB_BTB = 0?
;NAO, DESVIA
;SIM, W = INI_DB_BTB
;INICIALIZA DB_BTB
;LED EST PISCANDO?
;NAO, DESVIA
;SIM, APAGA O LED
;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

;DESVIA

;FAZ O LED PISCAR


;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

;DESVIA
;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB

68

Tutorial de Programao Assembly para Microcontroladores PIC -

MOVWF
GOTO

DB_BTB
PRINCIPAL

Parte 4 Pisca LED IV

;INICIALIZA DB_BTB
;DESVIA

;*********************************************************************************************
END

;FIM DO PROGRAMA

;**********************************************************************************************

Agora vamos fazer as alteraes na rotina de interrupo.


na rotina de interrupo onde o valor do bit de flag ESTADO_DO_LED,
ser testado e o estado do LED alterado.
H mais de uma maneira de implementar isso. Vamos fazer da seguinte
forma:
Depois da instruo BCF
INTCON,T0IF, vamos testar o valor do bit
ESTADO_DO_LED. Se o seu valor for igual a 0, significando que o LED dever ficar apagado,
vamos apag-lo com a instruo BCF LED e em seguida sairemos da interrupo. Se o valor do bit
ESTADO_DO_LED for igual a 1, significando que o LED dever piscar, deixaremos que a rotina
de interrupo prossiga:

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSC
GOTO
BCF
GOTO

W_TEMP
STATUS,W

;VETOR DAS INTERRUPES

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
ESTADO_DO_LED
CONT_INTERRUPCAO
LED
SAI_INT

CONT_INTERRUPCAO
MOVLW
INI_TMR0
MOVWF
TMR0
DECFSZ
CONT_EST_TMR0,F
GOTO
SAI_INT
MOVLW
INI_CONT_EST_TMR0
MOVWF
CONT_EST_TMR0
BTFSS
LED
GOTO
ACENDE_LED
BCF
LED
GOTO
SAI_INT

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;LED DEVER PISCAR?
;SIM, DESVIA
;NAO, APAGA O LED
;SAIR DA INTERRUPCAO

;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO

ACENDE_LED
BSF
LED

;ACENDE O LED

SAI_INT
SWAPF

;SWAP EM STATUS_TEMP

STATUS_TEMP,W

69

Tutorial de Programao Assembly para Microcontroladores PIC -

MOVWF
SWAPF
SWAPF
RETFIE

STATUS
W_TEMP,F
W_TEMP,W

Parte 4 Pisca LED IV

;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

;***********************************************************************************************

Nosso programa est pronto para ser simulado, tendo ficado assim:
;***********************************************************************************************
;
PROGRAMA: PISCA LED IV
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0
#DEFINE BANCO_1

BCF STATUS,RP0
BSF STATUS,RP0

;SETA BANCO 0 DE MEMORIA


;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************
;
VARIVEIS
CBLOCK 0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP
STATUS_TEMP
CONT_EST_TMR0
FLAGS
DB_BTA
DB_BTB

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
;USADA PARA CONTAR OS ESTOUROS DO TMR0
;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO

ENDC

;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
INI_DB_BTA
INI_DB_BTB

EQU
EQU
EQU
EQU

.131
.125
.255
.50

;VALOR QUE TMR0 INICIA


;VALOR QUE CONT_EST_TMR0 INICIA
;VALOR QUE DB_BTA INICIA
;VALOR QUE DB_BTB INICIA

;***********************************************************************************************
;
SADA

70

Tutorial de Programao Assembly para Microcontroladores PIC -

#DEFINE

LED

PORTA,0

Parte 4 Pisca LED IV

;LED LIGADO EM RA0

;***********************************************************************************************
;
ENTRADA
#DEFINE

BOTAO

PORTA,1

;BOTAO LIGADO EM RA1

;***********************************************************************************************
;
FLAGS
#DEFINE
#DEFINE

SOLTAR_BOTAO
ESTADO_DO_LED

FLAGS,0
FLAGS,1

;SE = 1 AGUARDA SOLTAR O BOTO


;SE = 1 LED PISCANDO

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSC
GOTO
BCF
GOTO

W_TEMP
STATUS,W

;SALVA W
;W = SWAP EM STATUS
;SELECIONA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;LED DEVER PISCAR?
;SIM, DESVIA
;NAO, APAGA O LED
;SAIR DA INTERRUPCAO

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
ESTADO_DO_LED
CONT_INTERRUPCAO
LED
SAI_INT

CONT_INTERRUPCAO
MOVLW
INI_TMR0
MOVWF
TMR0
DECFSZ
CONT_EST_TMR0,F
GOTO
SAI_INT
MOVLW
INI_CONT_EST_TMR0
MOVWF
CONT_EST_TMR0
BTFSS
LED
GOTO
ACENDE_LED
BCF
LED
GOTO
SAI_INT
ACENDE_LED
BSF
LED
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO

;ACENDE O LED

;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

71

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

;TODOS OS PINOS DO PORTB COMO ENTRADAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
MOVLW
MOVWF
CLRF
MOVLW
MOVWF
MOVLW
MOVWF

INI_CONT_EST_TMR0
CONT_EST_TMR0
FLAGS
INI_DB_BTA
DB_BTA
INI_DB_BTB
DB_BTB

;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0
;INICIALIZA FLAGS
;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB
;INICIALIZA DB_BTB

;***********************************************************************************************
PRINCIPAL
CLRWDT
BTFSS
GOTO
BTFSS
GOTO
BCF

;ROTINA PRINCIPAL DO PROGRAMA

SOLTAR_BOTAO
TESTA_BOTAO
BOTAO
PRINCIPAL
SOLTAR_BOTAO

TESTA_BOTAO
BTFSC
BOTAO
GOTO
REINC_CONT_DEB
DECFSZ
DB_BTA,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
DECFSZ
DB_BTB,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTB
MOVWF
DB_BTB
BTFSS
ESTADO_DO_LED
GOTO
PISCAR_O_LED
BCF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL

;LIMPA O WDT
;AGUARDA SOLTAR O BOTAO?
;NAO, DESVIA
;SIM, O BOTO EST SOLTO?
;NAO, DESVIA
;SIM, APAGA FLAG

;O BOTO EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB_BTA. DB_BTA = 0?
;NAO, DESVIA
;SIM, W = INI_DB_BTA
;INICIALIZA DB_BTA
;DECREMENTA DB_BTB. DB_BTB = 0?
;NAO, DESVIA
;SIM, W = INI_DB_BTB
;INICIALIZA DB_BTB
;LED EST PISCANDO?
;NAO, DESVIA
;SIM, APAGA O LED
;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

;DESVIA

72

Tutorial de Programao Assembly para Microcontroladores PIC -

PISCAR_O_LED
BSF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
REINC_CONT_DEB
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
MOVLW
INI_DB_BTB
MOVWF
DB_BTB
GOTO
PRINCIPAL

Parte 4 Pisca LED IV

;FAZ O LED PISCAR


;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

;DESVIA

;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB
;INICIALIZA DB_BTB
;DESVIA

;*********************************************************************************************
END

;FIM DO PROGRAMA

;**********************************************************************************************

No MPLAB, no menu Project clique em Open...


Abra o projeto Pisca LED.
No menu Project, posicione o ponteiro do mouse em Remove File From
Project.
O Arquivo Pisca LED III.asm, deve aparecer direita.
Clique nele para remov-lo.
No menu Project, clique em Add Files do Project...
Selecione o arquivo Pisca LED IV.asm e clique em abrir.
No menu Project, clique em Build All.
Verifique se o projeto foi montado corretamente, sendo exibida a mensagem
BUILD SUCCEEDED:

73

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Figura 1
No menu Debugger, posicione o mouse sobre Select Tool e clique em
MPLAB SIM.
No menu File, clique em Open.
Selecione o arquivo Pisca LED IV.asm e clique em abrir.
No menu View, clique em Watch.
Deixe somente o registrador PORTA, excluindo os demais que estejam
aparecendo, referentes aos programas anteriores.
Adicione o registrador FLAGS, selecionando-o na caixa direita do boto
Add Symbol e depois clicando nesse boto.
No menu Debugger, aponte o mouse para Stimulus e clique em New
Wordbook.
Na caixa de seleo do campo Pin/SFR, selecione RA1:

74

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Figura 2
Na caixa de seleo do campo Action ao lado, selecione Set High:

Figura 3

75

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Na prxima linha, selecione novamente RA1, porm desta vez, em Action,


selecione Set Low:

Figura 4
Clique em Save, atribuindo um nome qualquer, por exemplo Pisca LED.
No menu Window, v para a janela com o programa (Pisca LED.asm).
Clique no boto reset da barra de ferramentas do simulador.
V clicando no boto Step Into, at que o cursor esteja na linha com a
instruo CLRWDT .
Caso aparea esta janela, clique em SIM:

76

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Figura 5
No menu Window, alterne para a janela do Stimulus.
Clique no boto da primeira linha ao lado do RA1:

Figura 6

Clicando nesse boto estar fazendo com que o pino RA1 fique em nvel
alto, ou seja, que o seu valor seja igual a 1.
Volte para a janela do programa e clique mais uma vez no boto Step Into .

77

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Em seguida, v para a janela do Watch e repare que o RA1 assumiu o valor 1:

Figura 7
No Stimulus, clique agora no boto da linha de baixo.
Clique mais uma vez no boto Step Into e repare, no Watch que o RA1
voltou para 0.
Atravs desses botes iremos simular que o boto foi pressionado e que foi
solto.
Aproveitando que o RA1 est em nvel baixo, simulando que o boto est
pressionado, vamos medir o tempo do de-bouncing.
No menu Debugger, clique em Breakpoints.
Se houver breakpoints listados, exclua-os e clique em OK.
Em seguida, na janela do programa, d um duplo clique na linha que contm
a instruo BTFSS ESTADO_DO LED (rotina principal) para inserir um Breakpoint, j que
quando o de-bouncing terminar, o programa ir executar essa instruo.
Abra a janela do Stopwatch, que dever estar disponvel no menu
Window e clique em Zero. Se a janela do Stopwatch no estiver disponvel no menu
Window, abra-o atravs do menu Debugger.
Clique no boto Run da barra de ferramentas do simulador.
O programa ir parar na linha onde est o breakpoint.
V para a janela do Stopwatch e veja que o tempo de de-bouncing foi de
115 milissegundos:

78

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Figura 8
Como queremos um tempo de cerca de 50 milissegundos para o debouncing, vamos experimentar diminuir o valor da varivel DB_BTB para 20.
Fazemos isso na seo CONSTANTES alterando o valor de INI_DB_BTB.
Aps alterar, temos de salvar, clicando no menu File, em Save e montar
novamente o projeto, clicando no menu Project em Build All.
Aps fazer isso, v clicando no boto Step Into at que o cursor chegue
linha da instruo CLRWDT.
Abra a janela do Stopwatch e clique em Zero.
Clique no boto Run do simulador e quando o programa parar no
breakpoint, verifique o tempo indicado pelo Stopwatch.
Repare que o tempo do de-bouncing agora foi de cerca de 46
milissegundos o que est bom, pois, no precisa ser de exatos 50 milissegundos.
V clicando no boto Step Into e acompanhe a execuo do programa.
Quando ele retornar para o incio da rotina PRINCIPAL, tero sido
setados os dois bits de flag: o que indica que se est aguardando soltar o boto e o que indica que o
LED deve piscar. Repare, no Watch, que esses dois bits esto setados.
V clicando no boto Step Into e repare que o programa est aguardando o
boto ser solto.
Vamos simular que o boto foi solto clicando, no Stimulus, no boto da
primeira linha, fazendo com que o RA1 v para nvel alto.
V clicando em Step Into e repare que ele apaga o flag
SOLTAR_BOTAO.
Continue clicando no boto Step Into e acompanhando a execuo do
programa e repare que ele ficar em loop at que o boto seja novamente pressionado.
Como o flag que indica que o boto deve piscar foi setado, vamos ver se o
pino onde o LED est ligado (RA0) est alternando de nvel.

79

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Restaure a janela do programa, de forma que possamos ver as outras janelas:

Figura 9
Arraste a janela do programa para baixo para liberar espao:

80

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

Figura 10
Posicione as janelas de forma que possa visualizar os valores do PORTA, na
janela do Watch e ao mesmo tempo possa clicar nos botes do Stimulus:

Figura 11

81

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

No menu Debugger, clique em Settings... e na aba Animation/Real


Time Updates, selecione Enable Real Time Watch Updates, ajuste o seu cursor todo para a
esquerda (Fastest) e clique em OK.
Clique no boto Run do simulador e observe na janela do Watch que o
bit 0 do PORTA, fica alternando de estado ou seja, o LED est piscando:

Figura 12
Agora vamos simular que o boto foi pressionado.
Ainda com o boto Run ativado, no Stimulus, clique no boto da
segunda linha para levar o RA1 para nvel baixo.
Repare que o flag SOLTAR_BOTAO (bit 0 do registrador FLAGS), foi
setado, o flag ESTADO_DO_LED (bit 1 do registrador FLAGS) foi apagado e que o bit RA0 parou
de alternar de estado ficando em nvel 0, ou seja, o LED est apagado.
No Stimulus clique no boto da primeira linha para simular que o boto
foi solto.
Repare que o flag SOLTAR_BOTAO foi apagado.
Simule que o boto foi pressionado novamente atravs do Stimulus e
perceba que o RA0 voltou a alternar de estado.
Uma vez que o programa est se comportando como espervamos, grave-o
no microcontrolador e monte o circuito para comprovar o seu funcionamento.
Aqui termina a 4 parte deste tutorial.
Espero que voc tenha gostado.
Na prxima parte, vamos montar um circuito onde haver um display de 7
segmentos e dois botes: um incrementar o nmero exibido no display, enquanto o outro o
decrementar.
At l.

82

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Parte 5

Contador Crescente e Decrescente

Desta vez iremos montar o circuito da figura abaixo onde o boto 1 ir


incrementar o nmero exibido no display, enquanto o boto 2 o decrementar.

Figura 1

83

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

O display que utilizaremos do modelo HD-K123 ou HS-5202AG ou outro


modelo compatvel de dois dgitos, portanto o nmero exibido estar entre 00 e 99.
Para comandar os 14 segmentos dos dois dgitos do display a partir de
apenas 7 pinos do PIC16F628A, iremos ativar, a cada vez, somente um dos dgitos, atravs de seu
pino de catodo comum.
Quando o pino RA2 estiver em nvel alto, a juno base-emissor do
transistor T1 estar diretamente polarizada, ativando o dgito 1.
Da mesma forma, quando o pino RA3 estiver em nvel alto, ser o dgito 2
que estar ativo.
Levaremos aos pinos RB0 a RB6 os nveis lgicos adequados para que seja
exibido o nmero desejado no dgito que estiver ativo no momento.
Desta forma, enquanto um dgito estiver exibindo o seu nmero, o outro
estar apagado.
Cada dgito estar ativo por cerca de 5 milissegundos, ficando apagado pelos
prximos 5 milissegundos (enquanto o outro estar ativo), voltando aps este tempo a estar ativo
por mais 5 milissegundos e assim por diante.
Devido persistncia da viso, os dois dgitos parecero estar acesos o
tempo todo.
O fluxograma do programa pode ser visto na figura 2, enquanto na figura 3
o da rotina de interrupo.

84

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 2

85

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 3

No MPLAB, abra o arquivo Pisca LED IV.asm e salve-o com o nome de


Contador.asm.
A primeira alterao que faremos na seo VARIVEIS, onde vamos
excluir a CONT_EST_TMR0 .
Como teremos dois botes, vamos renomear as variveis DB_BTA e
DB_BTB para DB1_BTA e DB1_BTB e criar outras duas: DB2_BTA e DB2_BTB.
Criaremos uma varivel chamada UNIDADE para a unidade do nmero
exibido no display e outra chamada DEZENA para a dezena.

86

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

;***********************************************************************************************
;
VARIVEIS
CBLOCK

0X20

;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W

UNIDADE
DEZENA

;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


;DEZENA DO NUMERO EXIBIDO NO DISPLAY

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

ENDC

;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************

Na seo CONSTANTES, vamos excluir INI_CONT_EST_TMR0 e


INI_TMR0, renomear as que inicializam as variveis de de-bouncing do boto 1 e criar as que
inicializam as do boto 2:
;**********************************************************************************************
;
CONSTANTES
INI_DB1_BTA
INI_DB1_BTB
INI_DB2_BTA
INI_DB2_BTB

EQU
EQU
EQU
EQU

.255
.20
.255
.20

;VALOR QUE DB1_BTA INICIA


;VALOR QUE DB1_BTB INICIA
;VALOR QUE DB2_BTA INICIA
;VALOR QUE DB2_BTB INICIA

;***********************************************************************************************

Na seo SADAS, vamos definir a label DIGITO_1 para o pino RA2 e


a label DIGITO_2 para o pino RA3.
Relembrando que quando RA2 estiver em nvel alto, o dgito 1 do display
estar ativo e quando RA3 estiver em nvel alto, o dgito 2 estar ativo:
;***********************************************************************************************
;
SADAS
#DEFINE
#DEFINE

DIGITO_1
DIGITO_2

PORTA,2
PORTA,3

;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

;***********************************************************************************************

Na seo ENTRADAS, vamos definir a label BOTAO_1 para o pino


RA0 e a label BOTAO_2 para o pino RA1, conforme o esquema do circuito:
;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE

BOTAO_1
BOTAO_2

PORTA,0
PORTA,1

;BOTAO 1 LIGADO EM RA0


;BOTAO 2 LIGADO EM RA1

;***********************************************************************************************

87

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Na seo FLAGS, vamos excluir o flag ESTADO_DO_LED, renomear


o flag SOLTAR_BOTAO para SOLTAR_BOTAO_1 e criar o flag SOLTAR_BOTAO_2:
;***********************************************************************************************
;
FLAGS
#DEFINE
#DEFINE

SOLTAR_BOTAO_1
SOLTAR_BOTAO_2

FLAGS,0
FLAGS,1

;SE = 1 AGUARDA SOLTAR O BOTO 1


;SE = 1 AGUARDA SOLTAR O BOTO 2

;***********************************************************************************************

Chegamos rotina de interrupo.


O Timer 0 ser configurado para que gere uma interrupo a cada 5
milissegundos aproximadamente. Isto ser feito depois, na seo de configurao dos registradores.
Na rotina de interrupo, iremos:
Verificar qual dgito est ativo e desativ-lo;
Ativar o outro dgito;
Converter o valor numrico a ser exibido no display para o formato de 7
segmentos;
Enviar este valor convertido para o PORTB, onde est ligado o display.
A rotina igual at este ponto:
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF

W_TEMP
STATUS,W

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF

A seguir, vamos verificar qual o dgito que est ativo, desativ-lo, e ativar o
outro:
BTFSS
GOTO
BCF
CLRF
BSF
GOTO

DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE

DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1

;DIGITO 1 ESTA ATIVADO?


;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA

;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1

Com a instruo BTFSS, testamos se o dgito 1 est ativado e, se estiver,


desativamo-lo com a instruo BCF
DIGITO_1 e ativamos o dgito 2 com a instruo
BSF DIGITO_2.

88

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Porm se o dgito 1 estiver desativado, significa que o dgito 2 est ativo e,


ento, o programa desviado para a label DESATIVA_DIGITO_2, onde o dgito 2 desativado e
o dgito 1 ativado.
Repare que antes de ativarmos o dgito, fazemos todos os bits do PORTB =
0 com a instruo CLRF, para que o dgito que ser ativado no receba os valores do dgito que
acaba de ser desativado.
Os segmentos do display esto conectados no PORTB, da seguinte forma:
Segmento Bit
a

RB0

RB1

RB2

RB3

RB4

RB5

RB6

Tabela 1
O display utilizado do tipo catodo comum, portanto os segmentos so
ativados com nvel alto. Sendo assim, os valores a serem escritos no PORTB para cada algarismo a
ser exibido no display so os constantes na tabela abaixo. O bit 7 do PORTB est desconectado,
portanto, seu valor indiferente, pelo que lhe atribumos o valor 0 para todos os algarismos.
Algarismo

PORTB

00111111

00000110

01011011

01001111

01100110

01101101

01111101

00000111

01111111

01101111
Tabela 2

As figuras a seguir ilustram os valores da tabela anterior.

89

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

00111111

00000110

01011011

01001111

90

Tutorial de Programao Assembly para Microcontroladores PIC -

01100110

01111101

Parte 5 Contador Crescente e Decrescente

01101101

00000111

91

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

01101111

01111111

Aps o dgito ser ativado, devemos enviar para o PORTB o valor referente
ao algarismo que deve ser exibido.
O dgito 1 do display exibe a dezena do nmero e o dgito 2, a unidade.
O algarismo da dezena est gravado na varivel DEZENA, enquanto que
o da unidade est gravado na varivel UNIDADE, porm, esses algarismos esto gravados nessas
variveis no formato binrio, conforme a tabela abaixo:
Algarismo Valor binrio
0

00000000

00000001

00000010

00000011

00000100

00000101

00000110

00000111

00001000

00001001
Tabela 3

92

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Esses valores so diferentes dos que deve assumir o PORTB para que os
algarismos sejam exibidos no display de 7 segmentos, conforme a tabela comparativa abaixo:
Algarismo Valor binrio

PORTB

00000000

00111111

00000001

00000110

00000010

01011011

00000011

01001111

00000100

01100110

00000101

01101101

00000110

01111101

00000111

00000111

00001000

01111111

00001001

01101111

Tabela 4
Por isso, no podemos simplesmente copiar o valor da varivel para o
PORTB.
Existe uma maneira prtica de converter o valor binrio para o
correspondente a 7 segmentos, que consiste em somar o valor binrio ao Contador de Programa (PC
- Program Counter) para provocar um desvio no programa (Computed GOTO) para uma localidade
onde exista uma instruo que faa o programa retornar com o nmero j convertido no registrador
W.
O Contador de Programa (PC), armazena o endereo da prxima instruo
que ser executada.
Quando o microcontrolador ligado e tambm depois de um reset, o valor
do PC igual a 0h (nmero 0 no formato hexadecimal), o que quer dizer que ele ir executar a
instruo gravada nessa localidade da memria de programa.
A cada instruo que executada, o PC incrementado em 1 unidade,
portanto, depois de executar a instruo contida no endereo 0h, ele ir executar a instruo contida
no endereo 1h, depois a do endereo 2h e assim por diante. Isso se as instrues contidas nesses
endereos no provocarem o desvio do programa para outra localidade da memria.
Um exemplo de instruo que provoca o desvio para outra localidade de
memria a GOTO.
O PC do PIC16F628A composto de 13 bits, sendo que os 8 bits menos
significativos (do 0 ao 7) compe o registrador PCL. Este registrador pode ser acessado diretamente
para ser alterado. Os 5 bits mais significativos do PC (do 8 ao 12), chamados de PCH s podem ser
alterados indiretamente atravs do registrador PCLATH.
Quando uma instruo GOTO executada, o endereo para onde o
programa dever ser desviado consta na prpria instruo sendo copiado para o PC; portanto, a
prxima instruo que ser executada aquela que consta na instruo GOTO.
Outro tipo de instruo que provoca um desvio no programa a instruo
CALL.

93

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Quando uma instruo CALL executada, o valor do PC (endereo da


prxima instruo aps CALL) salvo no Stack e em seguida o PC assume o endereo que
consta na instruo CALL (que para onde o programa deve ser desviado).
Uma vez desviado o programa, assim que uma instruo RETURN ou
RETLW for executada, o endereo que estava salvo no Stack recuperado para o PC e, portanto,
o programa retorna para que seja executada a instruo que estava aps a instruo CALL.
A instruo GOTO serve para provocar um desvio no programa quando no
se pretende que ele retorne, enquanto que a instruo CALL desvia o programa para que ele possa
retornar posteriormente.
A instruo RETURN simplesmente provoca o retorno, enquanto a instruo
RETLW faz com que o programa retorne com o valor escrito aps a instruo no registrador W. Por
exemplo: RETLW .10: retorna com o valor 10 decimal no registrador W.
O Stack tem 8 nveis. Se, por exemplo, uma instruo CALL tiver sido
executada e outra instruo CALL for executada antes de uma instruo RETURN ou RETLW, o
endereo de retorno da primeira instruo passa para o nvel 2 do Stack enquanto o endereo de
retorno da segunda instruo assume o nvel 1.
Quando for executada uma instruo RETURN ou RETLW, o programa
voltar para o endereo constante no nvel 1, ou seja, para depois da segunda instruo CALL. Ao
mesmo tempo o endereo de retorno da primeira instruo CALL volta a assumir o nvel 1. Quando
for executada outra instruo RETURN ou RETLW o programa voltar para depois da primeira
instruo CALL.
Se ns somarmos um nmero ao registrador PCL, estaremos alterando o PC
e, portanto, o microcontrolador ir executar a instruo que esteja localizada no endereo que o PC
assumir.
Por exemplo, suponhamos que o valor do PC seja: 0010h. Isto significa que
a prxima instruo a ser executada ser a que est localizada neste endereo da memria de
programa.
Nesse nmero hexadecimal, os dois algarismos menos significativos (10)
so o PCL e os dois mais significativos so o PCH (00).
Se, por exemplo, ns somarmos o nmero 5h ao PCL, o PC ir assumir o
valor: 0015h e, ento, ao invs de ser executada a instruo contida no endereo 0010h ser
executada a contida no endereo 0015h.
Para somarmos um nmero a um registrador qualquer, precisamos,
primeiramente, fazer com que o registrador W assuma o valor desse nmero, atravs da instruo
MOVLW. Em seguida, atravs da instruo ADDWF, somamos o nmero ao registrador.
No exemplo citado, para somar o nmero 5 ao registrador PCL, fazemos
assim:
MOVLW
ADDWF

.5
PCL,F

;W = 5
;PCL = PCL + 5

A instruo ADDWF soma o valor do registrador W ao registrador indicado,


no caso, o PCL. A letra F aps a vrgula indica que o resultado da soma ser salvo no prprio
registrador PCL.
O PCL um registrador de 8 bits, e, portanto, o seu valor pode assumir, no
mximo, o valor 255 decimal.
Isto quer dizer que se o seu valor for, por exemplo, igual a 252 e somarmos
a ele o nmero 5, ele ir assumir o valor 1, pois, ter estourado (252 + 1 = 253 + 1 = 254 + 1 = 255
+ 1 = 0 + 1 = 1).

94

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Esse estouro do PCL provocado quando somamos um nmero a ele no faz


com que o PCH seja incrementado, como ocorre quando o PC incrementado pelo ciclo de
instruo.
Desta forma, antes de somarmos um nmero ao PCL, devemos ter o cuidado
de verificar se isso no ir provocar o estouro do PCL, pois, se provocar, o programa ser desviado
para uma localidade que no a que queremos.
Por exemplo, vamos supor que o valor do PC seja 00FCh, onde o PCL est
com o valor hexadecimal FC que corresponde ao valor decimal 252.
Se nesse momento, somarmos ao PCL o valor 5, o PC ir assumir o seguinte
valor hexadecimal: 0001h. Mas, o correto seria que ele assumisse o valor 0101h, o que no ocorreu
porque o estouro do PCL no provocou o incremento do PCH.
Ou seja, o programa seria desviado para o endereo 0001h quando
queramos que fosse desviado para 0101h.
Se virmos que a soma ao PCL ir provocar o seu estouro, devemos, antes de
efetuar a soma, incrementar manualmente o PCH, atravs do registrador PCLATH, fazendo o seu
valor igual ao que dever assumir o PCH aps a soma. No momento da soma ao PCL, o PCH
assumir o mesmo valor do PCLATH, pois, toda vez que ocorre uma alterao no PCL, o contedo
do PCLATH copiado para o PCH.
Para verificarmos se uma soma ao PCL ir provocar o seu estouro,
verificamos as localidades que assumiram as instrues, depois que o cdigo esteja montado.
Veremos como fazer isso ainda nesta parte do tutorial, quando o programa estiver pronto.
Voltemos ao programa!
Aps o dgito 2 ser ativado, o programa desviado para onde se encontra a
label COPIAR_UNIDADE.
Com a instruo MOVF, copiamos o valor da varivel UNIDADE para o
registrador W:
COPIAR_UNIDADE
MOVF
UNIDADE,W

;W = UNIDADE

Em seguida usamos a instruo CALL para desviar o programa para onde


est a label CONVERTE_BINARIO_7_SEGMENTOS:
CALL

CONVERTE_BINARIO_7_SEGMENTOS

;CHAMA SUBROTINA

Nesta subrotina, usamos a instruo ADDWF para somar o valor da varivel


UNIDADE, que est copiada no registrador W, ao PCL:
CONVERTE_BINARIO_7_SEGMENTOS
ADDWF PCL,F
;PCL = PCL + W
RETLW B'00111111'
;W = 0
RETLW B'00000110'
;W = 1
RETLW B'01011011'
;W = 2
RETLW B'01001111'
;W = 3
RETLW B'01100110'
;W = 4
RETLW B'01101101'
;W = 5
RETLW B'01111101'
;W = 6
RETLW B'00000111'
;W = 7
RETLW B'01111111'
;W = 8
RETLW B'01101111'
;W = 9

95

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Se o valor do registrador W for igual a 0, o valor do PCL e


consequentemente o do PC no mudar e, portanto, a prxima instruo que ser executada
RETLW B'00111111'. O programa, ento, retornar com o este valor no registrador W, que
corresponde ao algarismo 0 no formato de 7 segmentos.
Se o valor da unidade for igual a 1, o valor do PCL aumentar 1 unidade e,
portanto, a instruo que ser executada ser a de baixo, ou seja, a que faz com que o programa
retorne com o valor B'00000110' no registrador W correspondente ao nmero 1 e assim por diante.
Aps retornar, ser executada a instruo que vem depois da instruo
CALL e como j temos o nmero convertido no registrador W, basta copi-lo para o PORTB:
MOVWF

PORTB

;PORTB RECEBE O VALOR CONVERTIDO

O mesmo procedimento adotado quando o dgito 1 for ativado, com a


diferena de que o valor da varivel DEZENA que copiado e convertido.
Em seguida, desviamos o programa para a subrotina SAI_INT para que
retorne da interrupo.
Conclumos, assim, a rotina de interrupo:
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO

W_TEMP
STATUS,W

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE

DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1
MOVF
DEZENA,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT

;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1
;W = DEZENA
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT

;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'

;PCL = PCL + W
;W = 0

96

Tutorial de Programao Assembly para Microcontroladores PIC -

RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW

B'00000110'
B'01011011'
B'01001111'
B'01100110'
B'01101101'
B'01111101'
B'00000111'
B'01111111'
B'01101111'

SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

Parte 5 Contador Crescente e Decrescente

;W = 1
;W = 2
;W = 3
;W = 4
;W = 5
;W = 6
;W = 7
;W = 8
;W = 9

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

;***********************************************************************************************

O prximo passo configurar os registradores de uso especfico.


Devemos configurar o Timer 0 para estourar a cada 5 milissegundos,
aproximadamente.
Como ele ser incrementado pelo ciclo de instruo, que dura 1
microssegundo, se definirmos o seu prescaler para 1:16, ele ser incrementado a cada 16
microssegundos e portanto ir estourar a cada 4 milissegundos aproximadamente (16 x 256).
Esse valor prximo o suficiente daquele que precisvamos.
Para configurar o prescaler do Timer 0 para 1:16, devemos ajustar os valores
dos bits 2, 1 e 0 do registrador OPTION_REG para 0,1 e 1, respectivamente, conforme consta no
datasheet do PIC16F628A.
Temos de configurar tambm o registrador TRISA para definirmos os pinos
RA0 e RA1 como entrada e os pinos RA2 e RA3 como sada. Os demais pinos do PORTA,
deixaremos como entrada.
Devemos configurar ainda o registrador TRISB para definirmos os pinos
RB0 a RB6 como sada deixando o RB7 como entrada, pois no usado.
As demais configuraes so as mesmas do programa anterior:
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010011'
OPTION_REG
B'11110011'
TRISA
B'10000000'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010011'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16

;W = B'11110011'
;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS

;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************

97

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

A seguir, em INICIALIZAO DAS VARIVEIS, inicializamos as


variveis de de-bouncing dos botes com os seus devidos valores e as variveis FLAGS,
UNIDADE e DEZENA com o valor 0 (CLRF):
;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
CLRF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
CLRF
CLRF

FLAGS
INI_DB1_BTA
DB1_BTA
INI_DB1_BTB
DB1_BTB
INI_DB2_BTA
DB2_BTA
INI_DB2_BTB
DB2_BTB
UNIDADE
DEZENA

;INICIALIZA FLAGS
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;INICIALIZA UNIDADE
;INICIALIZA DEZENA

;***********************************************************************************************

Chegamos rotina principal do programa.


Aqui vamos introduzir um conceito conhecido como Programao
Estruturada, onde, na rotina principal, chamamos atravs da instruo CALL as subrotinas do
programa.
Teremos duas subrotinas que sero as que tratam os dois botes.
Nossa rotina PRINCIPAL ficar assim:
;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
CALL
CALL
GOTO

TRATA_BOTAO_1
TRATA_BOTAO_2
PRINCIPAL

;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA

;***********************************************************************************************

Na subrotina TRATA_BOTAO_1, primeiramente testamos se o flag


SOLTAR_BOTAO_1 est setado. Se estiver, testamos o boto para verificar se ele est solto. Se
estiver, apagamos o flag. Se no estiver solto, retornamos atravs da instruo RETURN.
Se o flag SOLTAR_BOTAO_1 no estiver setado, testamos o boto. Se
ele no estiver pressionado, retornamos. Se estiver pressionado, decrementamos a varivel
DB1_BTA dando incio ao de-bouncing e em seguida retornamos.
O retorno depois de decrementar as variveis do de-bouncing para que o
programa no fique preso dentro da rotina de de-bouncing.
Quando terminar o de-bouncing, teremos chegado a este ponto:
;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS

SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1

;AGUARDA SOLTAR O BOTAO 1?


;NAO, DESVIA
;SIM, O BOTO 1 EST SOLTO?

98

Tutorial de Programao Assembly para Microcontroladores PIC -

RETURN
BCF

SOLTAR_BOTAO_1

TESTA_BOTAO_1
BTFSC
BOTAO_1
GOTO
REINC_CONT_DEB_1
DECFSZ
DB1_BTA,F
RETURN
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
DECFSZ
DB1_BTB,F
RETURN
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB

Parte 5 Contador Crescente e Decrescente

;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 1 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;DECREMENTA DB1_BTB. DB1_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB1_BTB
;INICIALIZA DB1_BTB

J podemos setar o flag para aguardar soltar o boto 1:


BSF

SOLTAR_BOTAO_1

;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1

Como ficou definido, a cada vez que o boto 1 for pressionado o nmero
exibido no display ser incrementado.
O nmero composto de dois dgitos: unidade e dezena. Para incrementar
esse nmero, devemos incrementar a unidade, o que fazemos com a instruo INCF:
INCF

UNIDADE,F

;INCREMENTA UNIDADE

Essa instruo aumenta em 1 unidade o valor do registrador UNIDADE.


A letra F depois do nome do registrador faz com que o resultado seja salvo no prprio registrador.
O valor da unidade deve variar entre 0 e 9 e, portanto, depois de
increment-la, devemos verificar se o seu valor igual a 10. Se no for, retornamos e, se for,
devemos zer-la e incrementar a dezena.
Para verificar se o valor do registrador UNIDADE igual a 10, podemos
usar a instruo XORWF.
Essa instruo efetua a operao lgica XOR entre o registrador W e outro
registrador. Essa operao realizada entre cada bit equivalente dos dois registradores (bit0 com
bit0, bit1 com bit1, etc...). Se os bits equivalentes forem iguais, o bit equivalente do resultado ser
igual a 0 e se forem diferentes ser igual a 1, de forma que se todos os bits equivalentes do
registrador W e do outro registrador forem iguais, todos os bits do resultado sero iguais a 0 e,
portanto, o valor numrico do resultado igual a 0.
Ou seja, se os valores do registrador W e o do outro registrador forem iguais,
o valor do resultado da operao XOR entre eles ser igual a 0.
Comeamos por fazer o valor do registrador W igual a 10:
MOVLW

.10

;W = 10

Em seguida, efetuamos a operao XOR entre o registrador UNIDADE e


o W, salvando o resultado no W (para no alterar o valor do UNIDADE):
XORWF

UNIDADE,W

;W = W XOR UNIDADE

Se o valor da varivel UNIDADE for igual a 10 (valor do W), o resultado


da operao ser igual a 0.
Para sabermos se o resultado da operao foi igual a 0, testamos o bit Z
do registrador STATUS:

99

Tutorial de Programao Assembly para Microcontroladores PIC -

BTFSS

STATUS,Z

Parte 5 Contador Crescente e Decrescente

;UNIDADE = 10?

O bit Z serve para indicar quando o resultado de determinadas operaes,


entre elas a XOR, foi igual a 0, sendo que, nesse caso, o valor deste bit ser igual a 1, caso contrrio
ser igual a 0.
Ento, se o valor do bit Z for igual a 0, significa que o resultado da
operao XOR entre o registrador UNIDADE e o registrador W, no foi igual a 0, e portanto, o
valor do registrador UNIDADE diferente de 10. Nesse caso, a prxima linha do programa, onde
est a instruo RETURN, ser executada.
RETURN

;NAO, RETORNA

Mas, se o bit Z for igual a 1, ento, o valor da unidade igual a 10 e,


ento, a linha com a instruo RETURN pulada.
Como o valor da unidade chegou a 10, devemos zer-la e incrementar o
valor da dezena:
CLRF
INCF

UNIDADE
DEZENA,F

;SIM, UNIDADE = 0
;INCREMENTA DEZENA

Da mesma forma que fizemos com a unidade, aps incrementarmos a


dezena, devemos verificar se o seu valor igual a 10. Se no for, basta retornar e, se for igual a 10,
devemos zer-la e depois retornar, pois no temos a centena para incrementar:
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN

.10
DEZENA,W
STATUS,Z
DEZENA

;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA

Com isso, conclumos a subrotina TRATA_BOTAO_1 que ficou assim:


;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF

SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1

BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1

;AGUARDA SOLTAR O BOTAO 1?


;NAO, DESVIA
;SIM, O BOTO 1 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 1 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;DECREMENTA DB1_BTB. DB1_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1

100

Tutorial de Programao Assembly para Microcontroladores PIC -

INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN

UNIDADE,F
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA

REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN

Parte 5 Contador Crescente e Decrescente

;INCREMENTA UNIDADE
;W = 10
;W = W XOR UNIDADE
;UNIDADE = 10?
;NAO, RETORNA
;SIM, UNIDADE = 0
;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA

;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA

;**********************************************************************************************

A seguir, vem a subrotina TRATA_BOTAO_2 que igual do boto 1


(porm fazendo referncia ao boto 2) at este ponto:
;***********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_2
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF

SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2

BOTAO_2
REINC_CONT_DEB_2
DB2_BTA,F
INI_DB2_BTA
DB2_BTA
DB2_BTB,F
INI_DB2_BTB
DB2_BTB
SOLTAR_BOTAO_2

;AGUARDA SOLTAR O BOTAO 2?


;NAO, DESVIA
;SIM, O BOTO 2 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 2 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;DECREMENTA DB2_BTB. DB2_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2

O boto 2 a cada vez que for pressionado decrementar o nmero mostrado


no display.
Devemos, portanto, decrementar a unidade e para isso usaremos a instruo
DECF, que diminui em 1 unidade o valor de um registrador:
DECF

UNIDADE,F

;DECREMENTA UNIDADE

101

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Precisamos verificar qual o valor do registrador UNIDADE, aps ser


decrementado.
Se o valor do registrador antes de ser decrementado era 0, seu valor aps o
decremento ser 255, j que se trata de um registrador de 8 bits, cujo valor varia de 0 a 255, porm,
nesse caso, a unidade dever assumir o valor 9.
O que faremos verificar se o valor da unidade igual a 255. Se no for,
retornamos e, se for 255, tornamos o valor da unidade igual a 9:
MOVLW
XORWF
BTFSS
RETURN
MOVLW
MOVWF

.255
UNIDADE,W
STATUS,Z
.9
UNIDADE

;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9

Em seguida decrementamos a dezena, e adotamos o mesmo procedimento se


o seu valor for igual a 255:
DECF
MOVLW
XORWF
BTFSS
RETURN
MOVLW
MOVWF
RETURN

DEZENA,F
.255
DEZENA,W
STATUS,Z
.9
DEZENA

;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA

Conclumos assim a subrotina TRATA_BOTAO_2:


;**********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF

SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2

TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z

;AGUARDA SOLTAR O BOTAO 2?


;NAO, DESVIA
;SIM, O BOTO 2 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 2 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;DECREMENTA DB2_BTB. DB2_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
;DECREMENTA UNIDADE
;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?

102

Tutorial de Programao Assembly para Microcontroladores PIC -

RETURN
MOVLW
MOVWF
DECF
MOVLW
XORWF
BTFSS
RETURN
MOVLW
MOVWF
RETURN

.9
UNIDADE
DEZENA,F
.255
DEZENA,W
STATUS,Z
.9
DEZENA

REINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
RETURN

Parte 5 Contador Crescente e Decrescente

;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA

;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;RETORNA

;**********************************************************************************************

O nosso programa est pronto, tendo ficado assim:


;***********************************************************************************************
;
PROGRAMA: CONTADOR CRESCENTE E DECRESCENTE
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF
& _LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0
#DEFINE BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;***********************************************************************************************
;
VARIVEIS
CBLOCK

0X20
W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB

;ENDERECO INICIAL DA MEMORIA DO USUARIO


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

103

Tutorial de Programao Assembly para Microcontroladores PIC -

UNIDADE
DEZENA

Parte 5 Contador Crescente e Decrescente

;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


;DEZENA DO NUMERO EXIBIDO NO DISPLAY

ENDC

;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
;
CONSTANTES
INI_DB1_BTA
INI_DB1_BTB
INI_DB2_BTA
INI_DB2_BTB

EQU
EQU
EQU
EQU

.255
.20
.255
.20

;VALOR QUE DB1_BTA INICIA


;VALOR QUE DB1_BTB INICIA
;VALOR QUE DB2_BTA INICIA
;VALOR QUE DB2_BTB INICIA

;***********************************************************************************************
;
SADAS
#DEFINE
#DEFINE

DIGITO_1
DIGITO_2

PORTA,2
PORTA,3

;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE

BOTAO_1
BOTAO_2

PORTA,0
PORTA,1

;BOTAO 1 LIGADO EM RA0


;BOTAO 2 LIGADO EM RA1

;***********************************************************************************************
;
FLAGS
#DEFINE
SOLTAR_BOTAO_1 FLAGS,0
;SE = 1 AGUARDA SOLTAR O BOTO 1
#DEFINE
SOLTAR_BOTAO_2 FLAGS,1
;SE = 1 AGUARDA SOLTAR O BOTO 2
;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00

;ENDERECO INICIAL DE PROCESSAMENTO

GOTO

INICIO

;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO

W_TEMP
STATUS,W

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE

DESATIVA_DIGITO_2
BCF
DIGITO_2

;DESATIVA DIGITO 2

104

Tutorial de Programao Assembly para Microcontroladores PIC -

CLRF
BSF
MOVF
CALL
MOVWF
GOTO

Parte 5 Contador Crescente e Decrescente

PORTB
DIGITO_1
DEZENA,W
CONVERTE_BINARIO_7_SEGMENTOS
PORTB
SAI_INT

;TODOS OS BITS DO PORT B = 0


;ATIVA DIGITO 1
;W = DEZENA
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT

;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'
RETLW B'00000110'
RETLW B'01011011'
RETLW B'01001111'
RETLW B'01100110'
RETLW B'01101101'
RETLW B'01111101'
RETLW B'00000111'
RETLW B'01111111'
RETLW B'01101111'

;PCL = PCL + W
;W = 0
;W = 1
;W = 2
;W = 3
;W = 4
;W = 5
;W = 6
;W = 7
;W = 8
;W = 9

SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010011'
OPTION_REG
B'11110011'
TRISA
B'10000000'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010011'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16

;W = B'11110011'
;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS

;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
CLRF
MOVLW
MOVWF

FLAGS
INI_DB1_BTA
DB1_BTA

;INICIALIZA FLAGS
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA

105

Tutorial de Programao Assembly para Microcontroladores PIC -

MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
CLRF
CLRF

INI_DB1_BTB
DB1_BTB
INI_DB2_BTA
DB2_BTA
INI_DB2_BTB
DB2_BTB
UNIDADE
DEZENA

Parte 5 Contador Crescente e Decrescente

;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;INICIALIZA UNIDADE
;INICIALIZA DEZENA

;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
CALL
CALL
GOTO

TRATA_BOTAO_1
TRATA_BOTAO_2
PRINCIPAL

;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA

;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN

SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1

BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA

REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN

;AGUARDA SOLTAR O BOTAO 1?


;NAO, DESVIA
;SIM, O BOTO 1 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 1 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;DECREMENTA DB1_BTB. DB1_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
;INCREMENTA UNIDADE
;W = 10
;W = W XOR UNIDADE
;UNIDADE = 10?
;NAO, RETORNA
;SIM, UNIDADE = 0
;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA

;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA

106

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

;********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF

SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2

TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN

;AGUARDA SOLTAR O BOTAO 2?


;NAO, DESVIA
;SIM, O BOTO 2 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 2 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;DECREMENTA DB2_BTB. DB2_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
;DECREMENTA UNIDADE
;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA

REINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
;W = INI_DB2_BTA
MOVWF
DB2_BTA
;INICIALIZA DB2_BTA
MOVLW
INI_DB2_BTB
;W = INI_DB2_BTB
MOVWF
DB2_BTB
;INICIALIZA DB2_BTB
RETURN
;RETORNA
;**********************************************************************************************
END

;FIM DO PROGRAMA

Vamos montar o programa.


No MPLAB, no menu Project, clique em Project Wizard....
Na janela Welcome, clique em Avanar.
Na janela Step One, selecione o PIC16F628A e clique em Avanar.
Na janela Step Two, clique em Avanar.
Na janela Step Three, clique em Browse. Na janela que se abre, em
Nome do arquivo, escreva: Contador e clique em salvar.
Agora, na janela Step Three, clique em Avanar.

107

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Na janela Step Four, selecione o arquivo Contador.asm, clique em Add


e depois clique em Avanar.
Na janela Summary, clique em Concluir.
No menu Project, clique em Build All.
Na janela que se abre, clique em Absolute.
Verifique se a mensagem BUILD SUCCEEDED apareceu na janela
Output e, caso contrrio, confira se o programa est exatamente igual.

Figura 4
Quando falamos sobre a operao de soma ao registrador PCL, dissemos
que aps montar o programa, deveramos verificar se a soma no iria estourar o PCL.
No menu View, clique em Disassembly Listing.
A primeira coluna corresponde ao endereo, em hexadecimal, que a
instruo ocupar na memria de programa. A segunda coluna corresponde instruo em
hexadecimal. A terceira coluna a instruo em Assembly com os nomes dos registradores
substitudos pelos seus endereos na memria de dados.

108

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 5
Repare que a instruo ADD PCL,F est localizada no endereo 01C.
Os dois dgitos menos significativos desse nmero (1C) correspondem ao
valor do registrador PCL, enquanto que o dgito mais significativo (0) o valor do registrador PCH.
A ltima instruo RETLW est localizada no endereo 026.
Repare que no h estouro do PCL nesse trecho, pois, o valor do PCH o
mesmo (0).
isso que temos que verificar, ou seja, se o valor do PCH na localidade
onde est a instruo que efetua a soma de um valor ao PCL (no nosso caso, ADD PCL,F) e o valor
do PCH na ltima instruo da tabela so iguais.
Se houvesse estouro do PCL justamente nesse trecho, a maneira mais fcil
de resolver o problema seria reposicionando a tabela no programa, de forma que ficasse numa
posio onde no houvesse o estouro.
Agora vamos simular o programa.
No menu File, clique em Open..., localize e abra o arquivo
Contador.asm.
No menu Debugger, posicione o mouse em Select Tool e clique em
MPLAB SIM.
No menu Debugger, clique em Settings.... Na aba Osc/Trace, em
Processor Frequency, digite 4 e, em Units, selecione Mhz. Na Aba Animation/Real Time
Updates, selecione Enable Realtime watch updates e mova o cursor todo para a esquerda
(Fastest). Clique em OK.
No menu View, clique em Watch.
Adicione os registradores PORTA e PORTB em Add SFR e os
registradores FLAGS, UNIDADE e DEZENA em Add Symbol:

109

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 6
No menu Debugger, posicione o mouse sobre Stimulus e clique em
New Workbook.
Na primeira linha, em Pin/SFR, selecione RA0, em Action, selecione
Pulse Low, em Width, escreva 100 e em Units selecione ms (millisecond). Faa o mesmo
na segunda linha para o RA1.
Na terceira linha, selecione o RA0 e, em Action, selecione Set High.
Faa o mesmo na quarta linha para o RA1. Na quinta linha, selecione o RA0 e, em Action,
selecione Set Low. Faa o mesmo na sexta linha para o RA1:

110

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 7
Dessa forma quando clicarmos no boto Fire da primeira linha estaremos
simulando que o boto 1 foi pressionado e solto aps 100 milissegundos. Clicando no boto Fire
da segunda linha, estaremos simulando que o boto 2 foi pressionado e solto aps 100
milissegundos.
Definimos o tempo de 100 milissegundos para que o pino se mantenha em
nvel baixo, pois esse tempo precisa ser superior ao tempo de de-bouncing que de cerca de 50
milissegundos.
Os outros botes usaremos quando quisermos que os pinos fiquem fixos nos
nveis 0 ou 1.
Clique em Save e atribua um nome, por exemplo: Contador.
No menu Window, selecione a janela do programa (Contador.asm).
V clicando no boto Step Into da barra de ferramentas do simulador at o
cursor chegar instruo CLRWDT.
V para a janela do Stimulus, selecionando-a no menu Windows e
clique nos botes Fire das terceiras e quarta linhas para levar RA0 e RA1 para nvel alto,
simulando que os botes esto soltos.
Volte para a janela do programa, clique uma vez no boto Step Into.
V para a janela do Watch e confirme se RA0 e RA1 esto em nvel alto:

111

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 8
Volte para a janela do programa e clique novamente no boto Step Into.
Repare que o cursor foi para a subrotina TRATA_BOTAO_1, pois foi
executada a instruo CALL que chamou essa subrotina.
Continue clicando no boto Step Into e acompanhando a simulao do
programa. Repare que, como o boto 1 est solto, ele reinicia as variveis do de-bouncing e tendo
encontrado uma instruo RETURN, retorna para a rotina principal, na prxima linha aps a
instruo CALL.
Em seguida, ele ir executar a instruo que chama a subrotina do boto 2.
Depois de retornar para a rotina principal ele executa a instruo GOTO
PRINCIPAL, e recomea o ciclo.
Vamos medir os tempos de de-bouncing.
Insira um breakpoint na linha que contem a instruo BSF
SOLTAR_BOTAO_1, na subrotina do boto 1.
No Stimulus, clique no boto Fire da quinta linha para fixarmos o nvel
do RA0 em 0.
No menu Debugger, clique em Stopwatch.
Clique no boto Run da barra do simulador e quando o programa parar no
breakpoint, repare, no Stopwatch que o tempo que o de-bouncing demorou foi de 138
milissegundos, no sendo necessrio um tempo to longo.
Nem necessrio medir o tempo de de-bouncing do boto 2, pois, ser o
mesmo.
Vamos ver se deixamos esse tempo prximo de 50 milissegundos,
diminuindo o valor de inicializao das variveis DB1_BTB e DB2_BTB para 10 na seo
constantes.

112

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Aps alterar o valor, devemos montar novamente o programa, clicando em


Build All, no menu Project.
Toda vez que montamos o projeto, o programa resetado, portanto v
clicando no boto Step Into at chegar instruo CLRWDT.
Como os bits RA0 e RA1 so inicializados com o valor 0, clique no boto
Fire que fixa o valor do RA1 em 1, para simular que o boto 2 est solto.
Como vamos medir o tempo do de-bouncing do boto 1, podemos deixar
o valor do RA0 em 0, simulando que ele est pressionado.
No Stopwatch, clique em Zero e depois clique no boto Run da barra
do simulador. Quando o programa parar no breakpoint, veja, no Stopwatch que o de-bouncing
agora durou 69 milissegundos.
Vamos diminuir o valor das variveis DB1_BTB e DB2_BTB, para 8 e
medir o tempo novamente.
Com este valor, o tempo do de-bouncing foi de 55 milissegundos, o que
est bom.
Vamos verificar se o contador est sendo incrementado e decrementado
corretamente.
Remova o breakpoint. No Stimulus, clique no boto Fire da 3 linha
para setar o RA0.
Posicione as janelas de modo a poder ver as janelas do Stimulus e do
Watch ao mesmo tempo:

Figura 9
Clique no boto Run da barra do simulador.
No Stimulus, clique no boto Fire da primeira linha para simular que o
boto 1 foi pressionado e em seguida solto.

113

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Repare, no Watch, que o valor da unidade foi incrementado para 1:

Figura 10
Clique novamente no boto Fire da primeira linha e repare que a unidade
foi incrementada novamente, passando para 2.
Continue clicando nesse boto e repare que a unidade passa do valor 9 para
o valor 0 enquanto a dezena incrementada para 1, ou seja, o valor do contador igual a 10.
Agora, clique no boto Fire da segunda linha para simular que o boto 2
foi pressionado e solto em seguida. Repare que agora o contador decrementado, voltando a
unidade para 9 e a dezena para 0.
Continue decrementando-o e repare que de 00 passa a 99.
Agora o incremente e veja que o seu valor volta a 00.
Incremente-o at que o seu valor seja igual a 19 e a seguir clique no boto
Halt do simulador.
Vamos conferir a rotina de interrupo.
Insira um breakpoint na linha da primeira instruo da rotina de interrupo
(MOVWF
WTEMP).
Clique no boto Run da barra do simulador e quando o programa parar no
breakpoint, v para a janela do Stopwatch e clique em Zero.
Clique no boto Run novamente e quando o programa parar outra vez no
breakpoint, verifique no Stopwatch que o tempo entre uma interrupo e outra foi de 4
milissegundos.
V clicando no boto Step Into e observando a execuo da rotina de
interrupo.

114

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Repare que quando a vez do dgito 1 estar ativo, o valor do registrador


DEZENA somado ao PCL.
Como o valor da dezena igual a 1, o programa desviado para a linha que
contem a instruo RETLW referente a este valor.
Quando a vez do dgito 2 estar ativo, o valor do registrador UNIDADE
que somado ao PCL e como o seu valor igual a 9, o programa desviado para a linha onde est a
instruo RETLW correspondente.
Depois de executar a instruo RETLW, o programa retorna e, em seguida,
copia o valor do W para o PORTB. Observe, no Watch, que o PORTB assume o valor referente ao
nmero que deve ser exibido no display de 7 segmentos.
Com isso conclumos a simulao do programa e podemos grav-lo no
microcontrolador e testar o circuito na protoboard:

Figura 11
Aqui termina a 5 parte deste tutorial. Na prxima parte, vamos utilizar a
memria EEPROM do PIC16F628A para que o valor do contador no seja perdido quando o
circuito desligado.

115

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Parte 6
Contador Crescente e Decrescente II

O contador da parte anterior no retinha o seu valor quando a alimentao era


desligada, pois ele era salvo apenas na memria de dados, que uma memria voltil, isto , cujo
contedo s mantido enquanto h energia eltrica.
Desta vez, vamos utilizar a memria EEPROM do PIC16F628A para manter
salvo o valor do contador mesmo que a alimentao seja desligada.
O PIC16F628A possui 128 localidades de memria EEPROM, cada uma com
8 bits. Essas localidades devem ser lidas ou escritas uma de cada vez, como ocorre na memria de
dados. Segundo informa a Microchip, fabricante desse microcontrolador, cada localidade dessas
suporta ser regravada cerca de um milho de vezes, no havendo indicao do limite de nmero de
leituras. Iremos utilizar duas localidades: uma para o valor da unidade e outra para o valor da dezena.
Poderamos escolher duas localidades para serem sempre as mesmas onde
seriam salvos os valores da unidade e da dezena e, dessa forma, essas localidades estariam
deterioradas aps cerca de um milho de vezes que os valores fossem salvos. Quando isso
acontecesse, teramos de trocar o microcontrolador ou reescrever o programa para definir outras duas
localidades. Porm, se todas as vezes que salvarmos aqueles valores, alterarmos as localidades,
estaremos prolongando esse tempo.
As localidades da memria EEPROM do PIC16F628A no so acessadas
diretamente como as da memria de dados. Para ler ou escrever na memria EEPROM, utilizamos
quatro registradores de uso especfico:
EEADR: Nesse registrador, devemos escrever o endereo da localidade da
memria EEPROM, que queremos ler ou escrever;
EEDATA: o registrador onde devemos escrever o valor que queremos que
seja escrito na localidade que consta no EEADR. tambm no EEDATA onde o valor escrito na
localidade da memria EEPROM aparece quando efetuamos uma leitura.
EECON1: o registrador de controle de leitura e escrita.
EECON2: Esse registrador no existe fisicamente, ou seja, no uma
localidade da memria. Seu nome usado para prover uma forma de segurana contra escrita
indesejada, conforme veremos adiante.
O tempo necessrio para se efetuar uma gravao na memria EEPROM
tipicamente de 4 milissegundos. J, no caso de leitura, ela ocorre em apenas 1 ciclo de instruo.
Para efetuarmos a leitura de uma localidade da memria EEPROM, devemos
adotar os seguintes procedimentos:

116

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

1 Escrever no EEADR o endereo da localidade que queremos ler;


2 Setar o bit RD (bit 0 do EECON1), para iniciar o processo de leitura;
O valor da localidade da memria EEPROM constar no EEDATA aps um
ciclo de instruo, e o bit RD ser zerado pelo microcontrolador.
Os registradores EEADR, EECON1 e EEDATA esto no banco 1 de memria
e, portanto, devemos selecionar esse banco antes de ler ou escrever nesses registradores.
Para efetuarmos a escrita de uma localidade da memria EEPROM, devemos
adotar os seguintes procedimentos:
1 Escrever no EEADR o endereo da localidade que queremos escrever;
2 Escrever no EEDATA, o valor que queremos escrever na localidade da
memria EEPROM;
3 Setar o bit WREN (bit 2 do EECON1);
4 Zerar o bit GIE (bit 7 do INTCON) para desabilitar as interrupes;
5 Testar se o bit GIE foi zerado (recomendao da Microchip) e, se no
houver sido, repetir a instruo para zer-lo;
6 Escrever o nmero 55 (hexadecimal) no registrador EECON2;
7 Escrever o nmero AA (hexadecimal) no registrador EECON2;
8 Setar o bit WR (bit 1 do EECON1) para iniciar a escrita;
9 Setar o bit GIE para habilitar as interrupes.
As interrupes so desabilitadas para evitar que interfiram durante o
processo de escrita.
Escrever 55h e depois AAh no EECON2 uma senha para que ocorra a
gravao na EEPROM. Serve para evitar gravaes indesejadas.
A gravao demora cerca de 4 milissegundos. Quando ela houver sido
concluda, o microcontrolador ir zerar o bit WR e ir setar o bit EEIF (bit 7 do registrador PIR1)
gerando uma interrupo, caso esteja habilitada, o que feito setando o bit EEIE (bit 7 do registrador
PIE1).
H duas formas de sabermos se a gravao terminou: testando o estado do bit
WR ou habilitando a interrupo. Seja qual for a forma escolhida, quando terminar a gravao,
devemos, por precauo, verificar se o valor gravado na localidade da memria EEPROM
corresponde ao que queramos. Para isso, efetuamos uma leitura daquela localidade e comparamos
com o valor que mandamos gravar. Se a gravao no terminar dentro do tempo esperado, devemos
reiniciar o processo de gravao.
O circuito que iremos utilizar o mesmo da parte anterior deste tutorial.
No MPLAB, abra o arquivo Contador.asm e salve-o como ContadorII.asm.
A primeira alterao que faremos na seo VARIVEIS.

117

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Como neste programa iremos acessar com frequncia registradores que se


encontram no banco 1 da memria de dados, e para que no precisemos trocar constantemente de
banco, vamos criar as variveis a partir do endereo 0x70, pois, as variveis que ocupam esse
endereo at o 0x7F podem ser acessadas a partir de qualquer banco. Repare que so apenas 16
localidades que tem esse atributo.
Iremos adicionar as variveis ESC_EEPROM_A e ESC_EEPROM_B para a
contagem do tempo de espera pelo fim da escrita na EEPROM e a varivel LOCAL_DA_UNIDADE,
que conter o endereo da localidade da EEPROM onde est salvo o valor da unidade:
;***********************************************************************************************
;
VARIVEIS
CBLOCK

0X70
W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB
UNIDADE
DEZENA
ESC_EEPROM_A
ESC_EEPROM_B
LOCAL_DA_UNIDADE

;ENDERECO DA PRIMEIRA VARIVEL


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;UNIDADE DO NUMERO EXIBIDO NO DISPLAY
;DEZENA DO NUMERO EXIBIDO NO DISPLAY
;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
;CONTEM O ENDEREO DA EEPROM ONDE EST SALVO O VALOR DA UNIDADE

ENDC

;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************

Na seo CONSTANTES, acrescentaremos as de inicializao das variveis


ESC_EEPROM_A e ESC_EEPROM_B:
;***********************************************************************************************
;
CONSTANTES
INI_DB1_BTA
INI_DB1_BTB
INI_DB2_BTA
INI_DB2_BTB
INI_ESC_EEPROM_A
INI_ESC_EEPROM_B

EQU
EQU
EQU
EQU
EQU
EQU

.255
.8
.255
.8
.255
.2

;VALOR QUE DB1_BTA INICIA


;VALOR QUE DB1_BTB INICIA
;VALOR QUE DB2_BTA INICIA
;VALOR QUE DB2_BTB INICIA
;VALOR QUE ESC_EEPROM_A INICIA
;VALOR QUE ESC_EEPROM_B INICIA

;***********************************************************************************************

A seguir, na seo FLAGS, acrescentaremos os seguintes:


APAGAR_UNIDADE, GRAVAR_UNIDADE, GRAVAR_DEZENA, ESP_FIM_GRV_EEPROM,
CONF_GRV_EEPROM que sero usados na subrotina de gravao da EEPROM.
;***********************************************************************************************
;
FLAGS
#DEFINE

SOLTAR_BOTAO_1

FLAGS,0

;SE = 1, AGUARDA SOLTAR O BOTO 1

118

Tutorial de Programao Assembly para Microcontroladores PIC -

#DEFINE SOLTAR_BOTAO_2
#DEFINE APAGAR_UNIDADE
#DEFINE GRAVAR_UNIDADE
#DEFINE GRAVAR_DEZENA
#DEFINE ESP_FIM_GRV_EEPROM
#DEFINE CONF_GRV_EEPROM

FLAGS,1
FLAGS,2
FLAGS,3
FLAGS,4
FLAGS,5
FLAGS,6

Parte 6 Contador II

;SE = 1, AGUARDA SOLTAR O BOTO 2


;SE = 1, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE

;SE = 1, GRAVAR UNIDADE NA EEPROM


;SE = 1, GRAVAR DEZENA NA EEPROM
;SE = 1, ESPERA O FIM DA GRAVAO NA EEPROM
;SE = 1, CONFERE A GRAVAO NA EEPROM

;***********************************************************************************************

Para verificarmos se a gravao da EEPROM terminou, podemos escolher


entre testar o estado do bit WR at que ele seja zerado ou habilitar a interrupo de gravao
completa na EEPROM. Ficaremos com o teste do bit, por ser mais simples e, portanto, no iremos
fazer nenhuma alterao na rotina de interrupo.
A prxima alterao na seo de Inicializao das Variveis, onde
inclumos as instrues para a inicializao das variveis criadas para a contagem do tempo de espera
pelo fim da escrita na EEPROM.
As variveis UNIDADE e DEZENA no sero inicializadas com o valor 0,
como fizemos na parte anterior deste tutorial, mas, sim, com os valores que houverem sido salvos na
memria EEPROM, pois, queremos que quando o circuito seja ligado, ele mostre o valor que tinha
antes de ser desligado.
Como havamos comentado, todas as vezes que formos salvar os valores da
unidade e da dezena, iremos alterar as localidades da memria EEPROM, a fim de prolongar sua vida
til. Assim sendo, quando o programa for iniciado, ele ter de encontrar as localidades onde os
valores esto salvos.
Como o valor da unidade varia entre 0 e 9, apenas os quatro bits menos
significativos (bits 0 a 4) da localidade da memria so necessrios para salv-lo:

Valor em decimal Valor em binrio Valor em decimal Valor em binrio


0

0000 0000

0000 0101

0000 0001

0000 0110

0000 0010

0000 0111

0000 0011

0000 1000

0000 0100

0000 1001

Tabela 1
Sendo assim, usaremos os bits 5 a 8 para gravar um cdigo que far com que
o programa identifique a localidade onde est armazenado o valor da unidade.
O cdigo que utilizaremos ser este: 0110, ou seja, esses sero os valores dos
bits 5 a 8 da localidade onde o valor da unidade estiver salvo. Esse cdigo ser gravado todas as
vezes que salvarmos o valor da unidade, porm, na gravao do programa no microcontrolador,
devemos escrever o cdigo na primeira localidade da memria EEPROM, caso contrrio, no haver
nenhuma localidade com o cdigo para que o programa encontre na primeira vez que o
microcontrolador for ligado. Isso feito com o uso da diretiva DE, desta forma:

119

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

;**********************************************************************************************
;

INICIALIZAO DA EEPROM
ORG
DE

2100
B'01100000', .0

;APONTA PARA O ENDEREO 00H DA EEPROM


;ESCREVE O NMERO BINRIO 01100000 NO ENDEREO 00H DA EEPROM

;E O NMERO DECIMAL 0, NA LOCALIDADE 01H


;**********************************************************************************************

A diretiva DE serve para escrevermos nas localidades da memria


EEPROM durante a gravao do programa no microcontrolador. Para o PIC16F628A, devemos nos
referir primeira localidade da memria EEPROM como 2100. Se quisermos escrever em localidades
sequenciais, basta separar os valores por vrgula. Por exemplo, se escrevssemos assim:
DE .1, .5, .3 escreveramos os nmeros decimais 1, 5 e 3, nas trs localidades iniciadas pela que foi
apontada na diretiva ORG.
No nosso caso, o nmero binrio 01100000 ser escrito na localidade 00h e o
nmero decimal 0 na localidade seguinte, ou seja, a 01h. Assim, na primeira vez que o programa for
executado, ele encontrar o cdigo na primeira localidade da memria EEPROM, iniciando a unidade
com o valor 0. Na localidade seguinte, escrevemos 0 para que a dezena tambm seja iniciada com o
valor 0.
Insira a seo INICIALIZAO DA EEPROM, entre as sees BITS DE
CONFIGURAO e PAGINAO DE MEMRIA.
Voltando seo INICIALIZAO DAS VARIVEIS, o programa ir ler
a primeira localidade da memria EEPROM (00h) em busca do cdigo. Se encontrar, ele saber que
o valor da unidade est salvo naquela localidade e, portanto, que o valor da dezena est salvo na
prxima (01h). Se no encontrar, ele ir ler a terceira localidade (02h). Se encontrar o cdigo, ele
saber que o valor da unidade est salvo naquela localidade, e a dezena na prxima (03h) e assim por
diante at encontrar onde esto salvos os valores:
BANCO_1
MOVLW
.254
MOVWF
EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF
EEADR,F
INCF
EEADR,F
BSF
EECON1,RD
MOVF
EEDATA,W
ANDLW
B'11110000'
XORLW
B'01100000'
BTFSS
STATUS,Z
GOTO
INICIALIZA_UNIDADE_E_DEZENA
MOVF
EEADR,W
MOVWF
LOCAL_DA_UNIDADE
MOVF
EEDATA,W
ANDLW
B'00001111'
MOVWF
UNIDADE
INCF
EEADR,F
BSF
EECON1,RD
MOVF
EEDATA,W
MOVWF
DEZENA
BANCO_0

;SELECIONA BANCO 1 DE MEMORIA


;W = 254
;INICIALIZA EEADR
;INCREMENTA EEADR
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
;W = W XOR 01100000
;W = 01100000?
;NAO
;SIM, W = EEADR
;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
;W = VALOR DA LOCALIDADE DA EEPROM
;W = W AND B'00001111'
;INICIALIZA UNIDADE
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;INICIALIZA DEZENA
;SELECIONA BANCO 0 DE MEMORIA

120

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Primeiramente, inicializamos o EEADR com o valor 254.


A seguir, ele incrementado duas vezes, assumindo o valor 0 (254 + 1 = 255
+ 1 = 0).
Aps isso, o bit RD setado, iniciando a leitura da localidade 00h da
memria EEPROM (valor do EEADR).
Em seguida, o contedo dessa localidade que estar disponvel no EEDATA,
copiado para o registrador W.
A seguir, com a instruo ANDLW, efetuarmos a operao lgica AND entre
o W e o nmero binrio 11110000, para que os bits 0 a 4 sejam zerados e os bits 5 a 8 permaneam
com o mesmo valor. O resultado salvo no prprio W.
A operao AND efetuada bit a bit entre os bits equivalentes do registrador
W e o nmero 11110000. O bit do resultado ser igual a 1 somente se os dois bits forem iguais a 1.
Nas demais situaes, o bit do resultado ser 0.
Como no nmero binrio 11110000, os bits 0 a 4 so iguais a zero, os bits 0 a
4 do resultado sero iguais a zero, no importando o valor destes bits no W.
J os bits 5 a 8 do nmero binrio 11110000 so iguais a 1, e, portanto, os
valores dos bits 5 a 8 do W sero mantidos, pois, se o bit do W igual a 0, o bit do resultado ser
igual a 0 e se o bit do W for igual a 1, o bit do resultado ser igual a 1.
A seguir, atravs da instruo XORLW, efetuamos a operao lgica XOR
entre o registrador W e o nmero binrio 01100000, salvando o resultado no W. Repare que os bits 5
a 8 desse nmero contm o cdigo que indica a localidade de memria EEPROM onde est salvo o
valor da unidade.
A operao lgica XOR tambm realizada bit a bit. Nela, o bit do resultado
ser igual a 0 se os bits envolvidos tiverem o mesmo valor e ser igual a 1 se forem diferentes. Se
todos os bits forem iguais, ou seja, se o registrador W tiver o valor 01100000, todos os bits do
resultado da operao XOR sero iguais a 0, o que significa que o resultado da operao foi igual a 0.
Para saber se o resultado da operao foi igual a 0, testamos o bit Z do
registrador STATUS. Se o resultado houver sido igual a 0, esse bit estar setado, caso contrrio, estar
zerado.
A instruo BTFSS STATUS,Z testa o valor do bit Z do registrador STATUS.
Se o seu valor for 0, significa que o resultado da operao XOR no foi igual a 0, ou seja, que o
registrador W diferente de 01100000, e, ento, no na localidade testada que est salvo o valor da
unidade. Neste caso, a prxima linha executada, e o programa desviado para onde est a label
INICIALIZA_UNIDADE_E_DEZENA, onde o EEADR incrementado duas vezes, assumindo o
valor 02h. O processo se repete para verificar se nessa localidade que est salvo o valor da unidade
e assim por diante at que ela seja encontrada.
Quando a localidade onde estiver salvo o valor da unidade for encontrada, o
resultado da operao XOR entre o registrador W e o nmero binrio 01100000 ser igual a 0,
portanto o bit Z do registrador STATUS estar setado. Com isso, a prxima linha depois da instruo
BTFSS STATUS,Z ser pulada. Nesse caso, o valor do EEADR copiado para o W e, em seguida,
deste para a varivel LOCAL_DA_UNIDADE, inicializando essa varivel.

121

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

A seguir, copiamos o valor do EEDATA para o W e, aps isso, realizamos a


operao lgica AND entre o W e o nmero binrio 00001111 para zerar os bits 5 a 8, onde est o
cdigo, deixando apenas o valor da unidade nos bits 0 a 4. Ento, copiamos o W para o registrador
UNIDADE, inicializando essa varivel.
A seguir, o EEADR incrementado, a fim de apontar para a prxima
localidade da memria EEPROM. Em seguida, o bit RD setado, iniciando a leitura, e, na prxima
instruo, o valor do EEDATA, que agora contm a dezena, copiado para o W. Depois, copiamos o
valor do W para o registrador DEZENA, inicializando essa varivel.
Repare, que antes de acessarmos os registradores EEADR, EECON1 e
EEDATA, selecionamos o banco 1, pois eles esto localizados nesse banco.
Com isso, conclumos a seo de inicializao das variveis, que ficou assim:
;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
CLRF
FLAGS
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
MOVLW
INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
MOVLW
INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
BANCO_1
MOVLW
.254
MOVWF
EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF
EEADR,F
INCF
EEADR,F
BSF
EECON1,RD
MOVF
EEDATA,W
ANDLW
B'11110000'
XORLW
B'01100000'
BTFSS
STATUS,Z
GOTO
INICIALIZA_UNIDADE_E_DEZENA
MOVF
EEADR,W
MOVWF
LOCAL_DA_UNIDADE
MOVF
EEDATA,W
ANDLW
B'00001111'
MOVWF
UNIDADE
INCF
EEADR,F
BSF
EECON1,RD
MOVF
EEDATA,W
MOVWF
DEZENA
BANCO_0

;INICIALIZA FLAGS
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;W = INI_ESC_EEPROM_A
;INICIALIZA ESC_EEPROM_A
;W = INI_ESC_EEPROM_B
;INICIALIZA ESC_EEPROM_B
;SELECIONA BANCO 1 DE MEMORIA
;W = 254
;INICIALIZA EEADR
;INCREMENTA EEADR
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
;W = W XOR 01100000
;W = 01100000?
;NAO
;SIM, W = EEADR
;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
;W = VALOR DA LOCALIDADE DA EEPROM
;W = W AND B'00001111'
;INICIALIZA UNIDADE
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;INICIALIZA DEZENA
;SELECIONA BANCO 0 DE MEMORIA

;***********************************************************************************************

122

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Na rotina principal, acrescentaremos uma instruo CALL que chamar a


subrotina de gravao da EEPROM, ficando assim:
;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
CALL
CALL
CALL
GOTO

TRATA_BOTAO_1
TRATA_BOTAO_2
GRAVA_EEPROM
PRINCIPAL

;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA

;***********************************************************************************************

Na subrotina do boto 1, aps a unidade ser incrementada, iremos setar os


flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA, pois todas as vezes que
o valor da unidade for alterado, iremos salvar os valores da unidade e da dezena, sendo que, tambm,
precisamos apagar a localidade anterior da unidade para limpar o cdigo que a identificava.
;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF
INCF
BSF
BSF
BSF
MOVLW
XORWF
BTFSS
RETURN
CLRF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN

SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1

BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA

;AGUARDA SOLTAR O BOTAO 1?


;NAO, DESVIA
;SIM, O BOTO 1 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 1 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;DECREMENTA DB1_BTB. DB1_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
;INCREMENTA UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;W = 10
;W = W XOR UNIDADE
;UNIDADE = 10?
;NAO, RETORNA
;SIM, UNIDADE = 0
;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA

123

Tutorial de Programao Assembly para Microcontroladores PIC -

REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN

Parte 6 Contador II

;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA

;********************************************************************************************

Na subrotina do boto 2, tambm iremos setar esses mesmos flags aps a


unidade ser decrementada:
;********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF

SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2

TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN

;AGUARDA SOLTAR O BOTAO 2?


;NAO, DESVIA
;SIM, O BOTO 2 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 2 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;DECREMENTA DB2_BTB. DB2_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
;DECREMENTA UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA

REINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
;W = INI_DB2_BTA
MOVWF
DB2_BTA
;INICIALIZA DB2_BTA
MOVLW
INI_DB2_BTB
;W = INI_DB2_BTB
MOVWF
DB2_BTB
;INICIALIZA DB2_BTB
RETURN
;RETORNA
;**********************************************************************************************

124

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

A seguir, vamos escrever a subrotina de gravao da EEPROM.


Quando o valor da unidade for alterado, seja por ter sido incrementado, seja
por ter sido decrementado, iremos salvar os valores da unidade e da dezena em duas novas
localidades da memria EEPROM.
Antes de salv-los, iremos apagar a localidade onde, anteriormente, estava
escrito o valor da unidade, pois, precisamos apagar o cdigo que identificava aquela localidade.
Portanto, so trs etapas de escrita na EEPROM:
1) Escrever o nmero 0 na localidade anterior da unidade;
2) Escrever o valor da unidade com o cdigo na nova localidade;
3) Escrever o valor da dezena na nova localidade.
Nas rotinas dos botes, depois que o valor da unidade alterado, setamos os
flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA.
Na rotina de gravao da EEPROM, depois de escrevermos o nmero 0 na
localidade anterior da unidade, iremos zerar o flag APAGAR_UNIDADE. Depois de escrevermos o
valor da unidade na nova localidade, iremos zerar o flag GRAVAR_UNIDADE e depois de
escrevermos o valor da dezena na nova localidade, iremos zerar o flag GRAVAR_DEZENA.
Depois
de
iniciada
cada
gravao
setaremos
o
flag
ESP_FIM_GRV_EEPROM, para que o programa seja desviado para onde est a label
TESTA_FIM_DA_GRAVACAO onde iremos verificar se a gravao terminou, testando o bit
WR, j que uma gravao demora cerca de 4 milissegundos e s poderemos iniciar outra gravao
depois de que a anterior esteja concluda.
Depois de efetuar as trs gravaes, setamos o flag CONF_GRV_EEPROM
para que o programa seja desviado para onde est a label CONFERE_DEZENA a partir de onde
iremos conferir se os valores foram gravados corretamente.
A primeira instruo testa o flag que informa se o programa est aguardando a
concluso de uma gravao na EEPROM:
GRAVA_EEPROM
BTFSC

ESP_FIM_GRV_EEPROM

;AGUARDA O FIM DA GRAVACAO NA EEPROM?

Se esse flag estiver setado, o programa desviado para onde est a label
TESTA_FIM_DA_GRAVACAO:
GOTO

TESTA_FIM_DA_GRAVACAO

;SIM

Se o flag estiver zerado, testamos o flag que informa se j podemos conferir a


gravao:
BTFSC

CONF_GRV_EEPROM

;NAO, CONFERIR A GRAVAO?

Se esse flag estiver setado, o programa desviado para onde est a label
CONFERE_DEZENA:
GOTO

CONFERE_DEZENA

;SIM

Se o flag estiver zerado, testamos o flag que informa se a vez de apagar a


localidade anterior da unidade:

125

Tutorial de Programao Assembly para Microcontroladores PIC -

BTFSC

APAGAR_UNIDADE

Parte 6 Contador II

;NAO, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE?

Se esse flag estiver setado, o programa desviado para onde est a label
APAGA_UNIDADE_ANTERIOR:
GOTO

APAGA_UNIDADE_ANTERIOR

;SIM

Se o flag estiver zerado, testamos o flag que informa se a vez de gravar a


unidade na nova localidade:
BTFSC

GRAVAR_UNIDADE

;NAO, GRAVAR UNIDADE?

Se esse flag estiver setado, o programa desviado para onde est a label
GRAVA_A_UNIDADE:
GOTO

GRAVA_A_UNIDADE

;SIM

Se o flag estiver zerado, testamos o flag que informa se a vez de gravar a


dezena na nova localidade:
BTFSC

GRAVAR_DEZENA

;NAO, GRAVAR DEZENA?

Se esse flag estiver setado, o programa desviado para onde est a label
GRAVA_A_DEZENA:
GOTO

GRAVA_A_DEZENA

;SIM

Se o flag estiver zerado, retornamos:


RETURN

;NAO

Observe que, nesse ltimo caso, como nenhum dos flags estava setado, no h
nada para se fazer na subrotina de gravao da EEPROM.
Quando o flag APAGAR_UNIDADE est setado, o programa desviado
para onde est a label APAGA_UNIDADE_ANTERIOR. Nesse trecho do programa, iremos apagar
a localidade onde anteriormente estava gravado o valor da unidade, escrevendo nela o valor 0 (zero).
No precisamos apagar a localidade anterior da dezena, pois, ela no contm o cdigo de localizao.
Primeiramente, copiamos o valor da varivel LOCAL_DA_UNIDADE para o
EEADR para que este aponte para o endereo onde est gravada a unidade:
APAGA_UNIDADE_ANTERIOR
BANCO_1
MOVF
LOCAL_DA_UNIDADE,W
MOVWF
EEADR

;SELECIONA BANCO 1 DE MEMRIA


;W = ENDEREO DA EEPROM ONDE EST GRAVADA A UNIDADE

;EEADR RECEBE ENDERECO

A seguir, zeramos o EEDATA:


CLRF

EEDATA

;EEDATA = 0

Em seguida, setamos o bit WREN (bit 2 do EECON1) para habilitar a escrita


na EEPROM:
BSF

EECON1,WREN

;HABILITA ESCRITA NA EEPROM

A seguir, zeramos o bit GIE (bit 7 do INTCON), para desabilitar as


interrupes:
BCF

INTCON,GIE

;DESABILITA AS INTERRUPES

Aps isso, testamos esse bit para confirmarmos que ele foi zerado:
BTFSC

INTCON,GIE

;BIT GIE EST ZERADO?

126

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Se ele no houver sido zerado, executamos novamente a instruo BCF


INTCON,GIE, para zer-lo:
GOTO

$-2

;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA

A instruo GOTO $-2, desvia o programa para 2 linhas acima, onde est a
instruo BCF INTCON,GIE. O nmero aps o cifro indica a ordem da linha para a qual o
programa ir desviar. Se fosse, por exemplo, $+3, ele seria desviado para a 3 linha abaixo. Esse
nmero deve estar no formato hexadecimal. Por exemplo, se escrevermos GOTO $+16, o programa
ser desviado para a 22 linha abaixo, pois, 16 no sistema hexadecimal igual a 22 no sistema
decimal. Se quisssemos que o programa fosse desviado para a 16 linha abaixo, teramos que
escrever GOTO $+10, pois, 10, no sistema hexadecimal equivale ao nmero 16 no sistema decimal.
Confirmado que o bit GIE foi zerado, escrevemos o nmero 55 e depois o
nmero AA hexadecimais no EECON2:
MOVLW
MOVWF
MOVLW
MOVWF

0x55
EECON2
0xAA
EECON2

;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON = AA HEXADECIMAL

Em seguida, setamos o bit WR (bit 1 do EECON1) para iniciar a gravao:


BSF

EECON1,WR

;INICIA A GRAVAO

A seguir, setamos o bit GIE para habilitar as interrupes:


BSF

INTCON,GIE

;HABILITA INTERRUPES

Aps isso, zeramos o flag APAGAR_UNIDADE:


BCF

APAGAR_UNIDADE

;APAGA O FLAG

Por fim, setamos o flag ESP_FIM_GRV_EEPROM, selecionamos o banco


0 e retornamos:
BSF
BANCO_0
RETURN

ESP_FIM_GRV_EEPROM

;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO

;SELECIONA O BANCO 0 DE MEMRIA


;RETORNA

Na prxima vez que o programa entrar na subrotina de gravao da EEPROM,


ele encontrar o flag ESP_FIM_GRV_EEPROM setado e ser desviado para onde est a label
TESTA_FIM_DA_GRAVACAO.
Nesse trecho do programa, iremos testar, durante cerca de 10 milissegundos,
se o bit WR foi zerado. Esse bit zerado pelo microcontrolador quando termina o processo de
gravao da EEPROM, que dura cerca de 4 milissegundos.
Para a contagem do tempo de 10 milissegundos, iremos usar as variveis
ESC_EEPROM_A e ESC_EEPROM_B. A varivel ESC_EEPROM_A ser decrementada todas as
vezes que o bit WR for testado e no estiver zerado. Quando essa varivel chegar a 0, ela ser
reiniciada e a varivel ESC_EEPROM_B ser decrementada. Quando essa ltima chegar a 0, ter
passado cerca de 10 milissegundos.

127

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Se passar 10 milissegundos sem que o bit WR tenha sido zerado, ou seja,


sem que a gravao tenha sido concluda, iremos setar os flags APAGAR_UNIDADE,
GRAVAR_UNIDADE e GRAVAR_DEZENA para reiniciar todo o processo de gravao e
apagaremos os flags ESP_FIM_GRV_EEPROM e CONF_GRV_EEPROM (este ltimo estar
setado se a demora ocorreu na gravao da dezena).
Raramente isso ir ocorrer, mas temos de contar com essa situao.
Quando
o
bit
WR
for
zerado,
apagaremos
o
flag
ESP_FIM_GRV_EEPROM. Em seguida, iremos zerar o bit WREN para desabilitar a gravao
da EEPROM. A seguir, reiniciaremos as variveis de contagem do tempo e retornaremos:
TESTA_FIM_DA_GRAVACAO
BANCO_1
;SELECIONA O BANCO 1 DE MEMRIA
BTFSC
EECON1,WR
;A GRAVAO TERMINOU?
GOTO
DEC_CONT_TEMPO_FIM_ESCRITA
;NAO, DESVIA
BCF
ESP_FIM_GRV_EEPROM
;SIM, APAGA FLAG
BCF
EECON1,WREN
;DESABILITA ESCRITA NA EEPROM
MOVLW
INI_ESC_EEPROM_A
;W = INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
;REINICIA ESC_EEPROM_A
MOVLW
INI_ESC_EEPROM_B
;W = INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
;REINICIA ESC_EEPROM_B
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
RETURN
;RETORNA
DEC_CONT_TEMPO_FIM_ESCRITA
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
DECFSZ
ESC_EEPROM_A,F
;DECREMENTA ESC_EEPROM_A. ESC_EEPROM_A = 0?
RETURN
;NAO, RETORNA
MOVLW
INI_ESC_EEPROM_A
;SIM, W = INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
;REINICIA ESC_EEPROM_A
DECFSZ
ESC_EEPROM_B,F
;DECREMENTA ESC_EEPROM_B.ESC_EEPROM_B = 0?
RETURN
;NAO, RETORNA
MOVLW
INI_ESC_EEPROM_B
;SIM, W = INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
;REINICIA ESC_EEPROM_B
BSF
APAGAR_UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE
BSF
GRAVAR_UNIDADE
;SETA O FLAG PARA GRAVAO DA UNIDADE
BSF
GRAVAR_DEZENA
;SETA O FLAG PARA GRAVAO DA DEZENA
BCF
ESP_FIM_GRV_EEPROM
;APAGA FLAG DE ESPERA PELO FIM DA GRAVACAO
BCF
CONF_GRV_EEPROM
;APAGA O FLAG PARA CONFERIR A GRAVAO DA EEPROM
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
RETURN
;RETORNA

Repare que antes de retornar, selecionamos o banco 0, j que havamos


selecionado o banco 1 anteriormente. Isso porque, quando o programa retornar, ele ir executar a
subrotina do boto 1, onde testado um bit do PORTA, que se encontra no banco 0. claro que
poderamos ter selecionado o banco 0 no comeo subrotina do boto.
Concluda a gravao da EEPROM que apagou a localidade anterior da
unidade, na prxima vez que o programa entrar na rotina de gravao da EEPROM, ele ir encontrar
setado o flag GRAVAR_UNIDADE e ser desviado para onde est a label GRAVA_A_UNIDADE.
Nesse trecho do programa, iremos gravar o valor da unidade em uma nova
localidade da memria EEPROM, juntamente com o cdigo para que ela seja encontrada na
inicializao do programa.
Nesse ponto do programa, O EEADR est com o valor do endereo onde
estava gravada anteriormente a unidade, ento, devemos incrementar o EEADR duas vezes para que
ele aponte para o endereo da nova localidade onde iremos gravar a unidade:

128

Tutorial de Programao Assembly para Microcontroladores PIC -

GRAVA_A_UNIDADE
BANCO_1
INCF
EEADR,F
INCF
EEADR,F

Parte 6 Contador II

;SELECIONA O BANCO 1 DE MEMRIA


;INCREMENTA EEADR
;INCREMENTA EEADR

O registrador EEADR de 8 bits, o que significa que seu valor pode variar de
0 a 255, porm, no PIC16F628A, existem somente 128 localidades de memria EEPROM. Por isso, o
valor do EEADR dever variar entre 0 e 127. Por esse motivo, depois de incrementar o EEADR,
testamos se o seu valor igual a 128. Se for, zeramos o EEADR:
MOVLW
XORWF
BTFSS
GOTO
CLRF

.128
EEADR,W
STATUS,Z
CONT_GRV_UNIDADE
EEADR

;W = 128
;W = W XOR EEADR
;EEADR = 128?
;NAO, DESVIA
;SIM, EEADR = 0

A seguir, copiamos o valor da unidade para o EEDATA:


CONT_GRV_UNIDADE
MOVF
UNIDADE,W
MOVWF
EEDATA

;W = UNIDADE
;EEDATA = UNIDADE

Em seguida, copiamos o nmero binrio 01100000 para o W e, depois,


efetuamos a operao lgica OR, entre o W e o EEDATA, atravs da instruo IORWF, salvando o
resultado no EEDATA:
MOVLW
IORWF

B'01100000'
EEDATA,F

;W = 01100000
;EEDATA = EEDATA OR 01100000

A operao lgica OR efetuada bit a bit entre o W, cujo valor igual ao


nmero binrio 01100000, e o EEDATA. Quando pelo menos um dos bits for igual a 1, o bit do
resultado ser igual a 1. Se os dois bits forem iguais a 0, o bit do resultado ser igual a 0.
Nos bits 0 a 4 do EEDATA, est o valor da unidade, que copiamos antes.
Como os bits 0 a 4 do nmero binrio 01100000 so iguais a 0, o valor dos bits 0 a 4 do EEDATA
sero mantidos, pois, se o bit do EEDATA igual a 0, o bit do resultado ser igual a 0 e se o bit do
EEDATA for igual a 1, o do resultado ser igual a 1.
Como os bits 5 a 8 do EEDATA so iguais a 0, pois o valor da unidade varia
de 0 a 9 (veja a tabela 1), os bits 5 a 8 do nmero binrio 01100000 sero mantidos.
Dessa forma, aps a execuo da instruo IORWF, nos bits 0 a 4 do
EEDATA estar o valor da unidade e nos bits 5 a 8 estar o cdigo que identifica a localidade da
memria EEPROM onde estar gravada a unidade.
A seguir, escrevemos a sequncia de instrues para a gravao da EEPROM:
BSF
BCF
BTFSC
GOTO
MOVLW
MOVWF
MOVLW
MOVWF
BSF
BSF

EECON1,WREN
INTCON,GIE
INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE

;HABILITA ESCRITA NA EEPROM


;DESABILITA AS INTERRUPES
;BIT GIE EST ZERADO?
;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON2 = AA HEXADECIMAL
;INICIA A GRAVAO
;HABILITA INTERRUPES

A seguir, zeramos o flag


ESP_FIM_GRV_EEPROM e retornamos:

GRAVAR_UNIDADE, setamos o flag

129

Tutorial de Programao Assembly para Microcontroladores PIC -

BCF
BSF
BANCO_0
RETURN

GRAVAR_UNIDADE
ESP_FIM_GRV_EEPROM

Parte 6 Contador II

;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO

;SELECIONA BANCO 0 DE MEMORIA


;RETORNA

Na prxima vez que o programa entrar na subrotina de gravao da EEPROM,


ele ir encontrar o flag ESP_FIM_GRV_EEPROM setado e ento ser desviado para onde est a
label TESTA_FIM_DA_GRAVACAO.
Depois que o flag ESP_FIM_GRV_EEPROM houver sido apagado, na
prxima vez que o programa entrar na subrotina da gravao da EEPROM, ele ir encontrar o flag
GRAVAR_DEZENA setado e ser desviado para onde est a label GRAVA_A_DEZENA.
Nesse trecho do programa, iremos efetuar a gravao do valor da dezena na
localidade de memria EEPROM que vem em seguida quela onde gravamos a unidade.
Portanto, a primeira instruo que escrevemos a que incrementa o EEADR:
GRAVA_A_DEZENA
BANCO_1
INCF
EEADR,F

;SELECIONA O BANCO 1 DE MEMRIA


;INCREMENTA EEADR

A seguir, copiamos o valor da dezena apara o registrador EEDATA:


MOVF
MOVWF

DEZENA,W
EEDATA

;W = DEZENA
;EEDATA = DEZENA

Em seguida, escrevemos as instrues que realizam a gravao na EEPROM:


BSF
BCF
BTFSC
GOTO
MOVLW
MOVWF
MOVLW
MOVWF
BSF
BSF

EECON1,WREN
INTCON,GIE
INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE

;HABILITA ESCRITA NA EEPROM


;DESABILITA AS INTERRUPES
;BIT GIE EST ZERADO?
;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON2 = AA HEXADECIMAL
;INICIA A GRAVAO
;HABILITA INTERRUPES

Aps, zeramos o flag


GRAVAR_DEZENA e setamos os flags
ESP_FIM_GRV_EEPROM e CONF_GRV_EEPROM, retornando em seguida:
BCF
BSF
BSF
BANCO_0
RETURN

GRAVAR_DEZENA
ESP_FIM_GRV_EEPROM
CONF_GRV_EEPROM

;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
;SETA O FLAG PARA CONFERIR A GRAVAO DA EEPROM
;SELECIONA BANCO 0 DE MEMORIA
;RETORNA

Na prxima vez que o programa entrar na subrotina de gravao da EEPROM,


ele ir encontrar o flag ESP_FIM_GRV_EEPROM setado e ento ser desviado para onde est a
label TESTA_FIM_DA_GRAVACAO.
Depois que o flag ESP_FIM_GRV_EEPROM houver sido apagado, na
prxima vez que o programa entrar na subrotina da gravao da EEPROM, ele ir encontrar o flag
CONF_GRV_EEPROM setado e ento ser desviado para onde est a label
CONFERE_DEZENA.

130

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Neste trecho do programa, vamos conferir se o valor da dezena gravado na


EEPROM est correto.
Setamos o bit RD e aps 1 ciclo de instruo teremos, no EEDATA, o valor
da localidade onde foi gravada a dezena.
CONFERE_DEZENA
BANCO_1
BSF
EECON1,RD

;SELECIONA O BANCO 1 DE MEMRIA


;INICIA LEITURA

A seguir, copiamos o valor da dezena para o W:


MOVF

DEZENA,W

;W = DEZENA

Em seguida efetuamos a operao lgica XOR entre o W e o registrador


EEDATA, para verificarmos se so iguais:
XORWF

EEDATA,W

;W = W XOR EEDATA

Testamos o bit Z do registrador STATUS, o qual estar setado se eles forem


iguais:
BTFSC

STATUS,Z

;VALOR DA DEZENA FOI GRAVADO CORRETAMENTE?

Estando setado,
CONFERE_APAGAMENTO:
GOTO

CONFERE_APAGAMENTO

desviamos

programa

para

onde

est

label

;SIM

Porm, se o bit Z estiver zerado, significa que o valor gravado no est


igual ao da dezena, portanto apagamos o flag CONF_GRV_EEPROM, setamos os flags
APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA para que o processo de
gravao seja repetido.
BCF
BSF
BSF
BSF
BANCO_0
RETURN

CONF_GRV_EEPROM
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA

;APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA

Em CONFERE_APAGAMENTO, iremos conferir se a localidade onde


estava gravada anteriormente a unidade foi de fato apagado.
Como, neste ponto, o EEADR est apontando para o endereo atual a dezena,
pois acabamos de conferi-la, precisamos decrement-lo trs vezes para que ele aponte para a
localidade onde anteriormente estava gravada a unidade, conforme pode ser comprovado no esquema
abaixo:
Unidade Anterior Dezena Anterior Unidade Atual Dezena Atual

Como o EEADR um registrador de 8 bits, cujo valor pode variar entre 0 e 255 e,
supondo que seu valor seja 1 (unidade atualmente na localidade 00 e dezena na 01), aps decrement-lo trs vezes,
ele ir exibir o valor 254 (1 1 = 0; 0 1 = 255; 255 1 = 254), mas, como s existem 128 localidades de memria
EEPROM no PIC16F628A, o valor do EEADR deve variar entre 0 a 127. Qualquer valor alm disso invlido, pois,
corresponde a uma localidade que no existe na EEPROM. Por esse motivo, aps decrementarmos trs vezes o
EEADR, iremos testar seu valor. Se ele for igual a 254, iremos faz-lo igual a 126, pois esse valor que ele deve
assumir aps ser decrementado trs vezes partindo do valor 1 (1 1 = 0; 0 1 = 127; 127 1 = 126).

131

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Pode ser que voc esteja se perguntando o que ocorreria se o valor do EEADR fosse 0 ou
2.
Isso no possvel, pois, neste ponto do programa, o EEADR aponta para o endereo
onde a dezena est gravada atualmente. A dezena estar sempre gravada numa localidade mpar (01, 03, 05, etc.),
pois, ela gravada pela primeira vez na localidade 01, durante a gravao do programa no microcontrolador, por
meio da diretiva DE. A partir da, ela sempre ser gravada duas localidades aps a anterior, na subrotina de
gravao da EEPROM.
Por esse motivo, aps decrementarmos o EEADR, testamos se o seu valor igual a 254 e,
se for, o fazemos igual a 126.
CONFERE_APAGAMENTO
DECF
EEADR,F
DECF
EEADR,F
DECF
EEADR,F
MOVLW
.254
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONFERENCIA
MOVLW
.126
MOVWF
EEADR

;DECREMENTA EEADR
;DECREMENTA EEADR
;DECREMENTA EEADR
;W = 254
;W = W XOR EEADR
;EEADR = 254?
;NAO, DESVIA
;SIM, W = 126
;EEADR = 126

A seguir, setamos o bit RD e no prximo ciclo de instruo teremos o valor


dessa localidade no EEDATA, o qual copiamos para o W:
CONT_CONFERENCIA
BSF
EECON1,RD
MOVF
EEDATA,W

;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM

Como j comentamos, o bit Z do registrador STATUS serve para indicar


quando o resultado da ltima instruo executada pelo microcontrolador resultou em 0, inclusive a
instruo MOVF.
No so todas as instrues que afetam o bit Z. No datasheet do
microcontrolador, h uma descrio de todas as instrues e quais bits so afetados por cada uma.
Como esperamos que o valor dessa localidade seja igual a 0, j podemos
testar o bit Z do registrador STATUS, pois, se o valor copiado do EEDATA para o W for igual a 0,
aquele bit estar setado. Se ele estiver setado, significa que o valor da localidade igual a 0 e,
portanto, desviamos o programa para onde est a label CONFERE_UNIDADE. Se o bit Z estiver
zerado, setamos os flags para que o processo de gravao seja repetido:
BTFSC
GOTO
BCF
BSF
BSF
BSF
BANCO_0
RETURN

STATUS,Z
CONFERE_UNIDADE
CONF_GRV_EEPROM
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA

;LOCALIDADE ANTERIOR DA UNIDADE FOI APAGADO CORRETAMENTE?

;SIM
;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA

Em CONFERE_UNIDADE, iremos conferir se o valor da unidade foi


gravado corretamente na EEPROM. Primeiramente, incrementamos duas vezes o registrador EEADR
para que ele aponte para o endereo onde est atualmente gravada a unidade, testando se o seu valor
igual a 128, como j fizemos quando gravamos a unidade:

132

Tutorial de Programao Assembly para Microcontroladores PIC -

CONFERE_UNIDADE
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONF_UNIDADE
CLRF
EEADR

Parte 6 Contador II

;INCREMENTA EEADR
;INCREMENTA EEADR
;W = 128
;W = W XOR EEADR
;EEADR = 128?
;NAO, DESVIA

Em seguida, procedemos da mesma forma que foi feito na conferncia do


valor da dezena, com a diferena de que aps copiarmos a unidade para o W, inserimos o cdigo nos
bits 5 a 8 do W, com a instruo IORWF, antes de comparar com o registrador EEDATA.
Se a gravao estiver correta, o programa desviado para onde est a label
GRAVACAO_CORRETA, onde apagamos o flag CONF_GRV_EEPROM, copiamos o valor do
EEADR para a varivel LOCAL_DA_UNIDADE, atualizando essa varivel e retornamos,
finalizando o processo de gravao.
Mas, se o valor da unidade no houver sido gravado corretamente, apagamos
o flag CONF_GRV_EEPROM, setamos os flags APAGAR_UNIDADE, GRAVAR_UNIDADE e
GRAVAR_DEZENA para que o processo de gravao seja repetido:
CONT_CONF_UNIDADE
BSF
EECON1,RD
MOVF
UNIDADE,W
IORLW
B'01100000'
XORWF
EEDATA,W
BTFSC
STATUS,Z
GOTO
GRAVACAO_CORRETA
BCF
CONF_GRV_EEPROM
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
BANCO_0
RETURN
GRAVACAO_CORRETA
BCF
CONF_GRV_EEPROM
MOVF
EEADR,W
MOVWF
LOCAL_DA_UNIDADE
BANCO_0
RETURN

;INICIA LEITURA
;W = UNIDADE
;W = W OR B'01100000'
;W = W XOR EEDATA
;VALOR DA UNIDADE FOI GRAVADO CORRETAMENTE?
;SIM
;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA
;APAGA FLAG
;W = EEADR
;LOCAL_DA_UNIDADE = EEADR
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA

Com isso, terminamos de escrever o programa que ficou assim:


;***********************************************************************************************
;
PROGRAMA: CONTADOR CRESCENTE E DECRESCENTE
;
VERSO 1.1
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>
;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A
;***********************************************************************************************

133

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BITS DE CONFIGURAO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF &
_LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;

INICIALIZAO DA EEPROM
ORG
DE

2100
B'01100000', .0

;APONTA PARA O ENDEREO 00H DA EEPROM


;ESCREVE O NMERO BINRIO 01100000 NO ENDEREO 00H DA EEPROM

;E O NMERO DECIMAL 0 NA LOCALIDADE 01h


;**********************************************************************************************
;
PAGINACAO DE MEMORIA
#DEFINE BANCO_0
#DEFINE BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;***********************************************************************************************
;

VARIVEIS
CBLOCK

0X70

;ENDERECO PRIMEIRA VARIVEL

W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W

UNIDADE
DEZENA
ESC_EEPROM_A
ESC_EEPROM_B
LOCAL_DA_UNIDADE

;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


;DEZENA DO NUMERO EXIBIDO NO DISPLAY

;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM


;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
;CONTEM O ENDEREO DA EEPROM ONDE EST SALVO O VALOR DA UNIDADE

ENDC

;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
;
CONSTANTES
INI_DB1_BTA
INI_DB1_BTB
INI_DB2_BTA
INI_DB2_BTB
INI_ESC_EEPROM_A
INI_ESC_EEPROM_B

EQU
EQU
EQU
EQU
EQU
EQU

.255
.8
.255
.8
.255
.2

;VALOR QUE DB1_BTA INICIA


;VALOR QUE DB1_BTB INICIA
;VALOR QUE DB2_BTA INICIA
;VALOR QUE DB2_BTB INICIA
;VALOR QUE ESC_EEPROM_A INICIA
;VALOR QUE ESC_EEPROM_B INICIA

;***********************************************************************************************
;
SADAS
#DEFINE
#DEFINE

DIGITO_1
DIGITO_2

PORTA,2
PORTA,3

;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

;***********************************************************************************************

134

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

ENTRADAS
#DEFINE
#DEFINE

BOTAO_1
BOTAO_2

PORTA,0
PORTA,1

;BOTAO 1 LIGADO EM RA0


;BOTAO 2 LIGADO EM RA1

;***********************************************************************************************
;
FLAGS
#DEFINE SOLTAR_BOTAO_1
#DEFINE SOLTAR_BOTAO_2
#DEFINE APAGAR_UNIDADE

FLAGS,0
FLAGS,1
FLAGS,2

;SE = 1, AGUARDA SOLTAR O BOTO 1


;SE = 1, AGUARDA SOLTAR O BOTO 2
;SE = 1, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE

#DEFINE GRAVAR_UNIDADE
FLAGS,3
;SE = 1, GRAVAR UNIDADE NA EEPROM
#DEFINE GRAVAR_DEZENA
FLAGS,4
;SE = 1, GRAVAR DEZENA NA EEPROM
#DEFINE ESP_FIM_GRV_EEPROM FLAGS,5
;SE = 1, ESPERA O FIM DA GRAVAO NA EEPROM
#DEFINE CONF_GRV_EEPROM
FLAGS,6
;SE = 1, CONFERE A GRAVAO NA EEPROM
;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00

;ENDERECO INICIAL DE PROCESSAMENTO

GOTO

INICIO

;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO

W_TEMP
STATUS,W

;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA

STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE

DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1
MOVF
DEZENA,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT

;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1
;W = DEZENA
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT

;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA

135

Tutorial de Programao Assembly para Microcontroladores PIC -

CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'
RETLW B'00000110'
RETLW B'01011011'
RETLW B'01001111'
RETLW B'01100110'
RETLW B'01101101'
RETLW B'01111101'
RETLW B'00000111'
RETLW B'01111111'
RETLW B'01101111'

;PCL = PCL + W
;W = 0
;W = 1
;W = 2
;W = 3
;W = 4
;W = 5
;W = 6
;W = 7
;W = 8
;W = 9

SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE

;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO

STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W

Parte 6 Contador II

;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

B'11010011'
OPTION_REG
B'11110011'
TRISA
B'10000000'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010011'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16

;W = B'11110011'
;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS

;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS


;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
CLRF
FLAGS
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
MOVLW
INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
MOVLW
INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
BANCO_1
MOVLW
.254
MOVWF
EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF
EEADR,F

;INICIALIZA FLAGS
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;W = INI_ESC_EEPROM_A
;INICIALIZA ESC_EEPROM_A
;W = INI_ESC_EEPROM_B
;INICIALIZA ESC_EEPROM_B
;SELECIONA BANCO 1 DE MEMORIA
;W = 254
;INICIALIZA EEADR
;INCREMENTA EEADR

136

Tutorial de Programao Assembly para Microcontroladores PIC -

INCF
BSF
MOVF
ANDLW
XORLW
BTFSS
GOTO
MOVF
MOVWF
MOVF
ANDLW
MOVWF
INCF
BSF
MOVF
MOVWF
BANCO_0

EEADR,F
EECON1,RD
EEDATA,W
B'11110000'
B'01100000'
STATUS,Z
INICIALIZA_UNIDADE_E_DEZENA
EEADR,W
LOCAL_DA_UNIDADE
EEDATA,W
B'00001111'
UNIDADE
EEADR,F
EECON1,RD
EEDATA,W
DEZENA

Parte 6 Contador II

;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
;W = W XOR 01100000
;W = 01100000?
;NAO
;SIM, W = EEADR
;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
;SIM, W = VALOR DA LOCALIDADE DA EEPROM
;W = W AND B'00001111'
;INICIALIZA UNIDADE
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;INICIALIZA DEZENA
;SELECIONA BANCO 0 DE MEMORIA

;***********************************************************************************************
PRINCIPAL
CLRWDT
CALL
CALL
CALL
GOTO

;ROTINA PRINCIPAL DO PROGRAMA

TRATA_BOTAO_1
TRATA_BOTAO_2
GRAVA_EEPROM
PRINCIPAL

;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA

;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF
INCF
BSF
BSF
BSF
MOVLW
XORWF
BTFSS
RETURN
CLRF

SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1

BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
.10
UNIDADE,W
STATUS,Z
UNIDADE

;AGUARDA SOLTAR O BOTAO 1?


;NAO, DESVIA
;SIM, O BOTO 1 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 1 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;DECREMENTA DB1_BTB. DB1_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
;INCREMENTA UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;W = 10
;W = W XOR UNIDADE
;UNIDADE = 10?
;NAO, RETORNA
;SIM, UNIDADE = 0

137

Tutorial de Programao Assembly para Microcontroladores PIC -

INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN

DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA

REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN

Parte 6 Contador II

;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA

;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA

;********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF

SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2

TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN

;AGUARDA SOLTAR O BOTAO 2?


;NAO, DESVIA
;SIM, O BOTO 2 EST SOLTO?
;NAO, RETORNA
;SIM, APAGA FLAG

;O BOTO 2 EST PRESSIONADO?


;NO, DESVIA
;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
;NAO,RETORNA
;SIM, W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;DECREMENTA DB2_BTB. DB2_BTB = 0?
;NAO, RETORNA
;SIM, W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
;DECREMENTA UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA

138

Tutorial de Programao Assembly para Microcontroladores PIC -

EINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
RETURN

Parte 6 Contador II

;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;RETORNA

;**********************************************************************************************
GRAVA_EEPROM
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
RETURN

ESP_FIM_GRV_EEPROM
TESTA_FIM_DA_GRAVACAO
CONF_GRV_EEPROM
CONFERE_DEZENA
APAGAR_UNIDADE
APAGA_UNIDADE_ANTERIOR
GRAVAR_UNIDADE
GRAVA_A_UNIDADE
GRAVAR_DEZENA
GRAVA_A_DEZENA

APAGA_UNIDADE_ANTERIOR
BANCO_1
MOVF
LOCAL_DA_UNIDADE,W
MOVWF
EEADR
CLRF
EEDATA
BSF
EECON1,WREN
BCF
INTCON,GIE
BTFSC
INTCON,GIE
GOTO
$-2
MOVLW
0x55
MOVWF
EECON2
MOVLW
0xAA
MOVWF
EECON2
BSF
EECON1,WR
BSF
INTCON,GIE
BCF
APAGAR_UNIDADE
BSF
ESP_FIM_GRV_EEPROM
BANCO_0
RETURN
GRAVA_A_UNIDADE
BANCO_1
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_GRV_UNIDADE
CLRF
EEADR
CONT_GRV_UNIDADE
MOVF
UNIDADE,W
MOVWF
EEDATA
MOVLW
B'01100000'
IORWF
EEDATA,F
BSF
EECON1,WREN
BCF
INTCON,GIE

;AGUARDA O FIM DA GRAVACAO NA EEPROM?


;SIM
;NAO, CONFERIR A GRAVAO?
;SIM
;NAO, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE?

;SIM
;NAO, GRAVAR UNIDADE?
;SIM
;NAO, GRAVAR DEZENA?
;SIM
;NAO

;SELECIONA BANCO 1 DE MEMRIA


;W = ENDEREO DA EEPROM ONDE EST GRAVADA A UNIDADE

;EEADR RECEBE ENDERECO


;EEDATA = 0
;HABILITA ESCRITA NA EEPROM
;DESABILITA AS INTERRUPES
;BIT GIE EST ZERADO?
;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON = AA HEXADECIMAL
;INICIA A GRAVAO
;HABILITA INTERRUPES
;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO

;SELECIONA O BANCO 0 DE MEMRIA


;RETORNA

;SELECIONA O BANCO 1 DE MEMRIA


;INCREMENTA EEADR
;INCREMENTA EEADR
;W = 128
;W = W XOR EEADR
;EEADR = 128?
;NAO, DESVIA
;SIM, EEADR = 0
;W = UNIDADE
;EEDATA = UNIDADE
;W = 01100000
;EEDATA = EEDATA OR 01100000
;HABILITA ESCRITA NA EEPROM
;DESABILITA AS INTERRUPES

139

Tutorial de Programao Assembly para Microcontroladores PIC -

BTFSC
GOTO
MOVLW
MOVWF
MOVLW
MOVWF
BSF
BSF
BCF
BSF
BANCO_0
RETURN

INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE
GRAVAR_UNIDADE
ESP_FIM_GRV_EEPROM

GRAVA_A_DEZENA
BANCO_1
INCF
EEADR,F
MOVF
DEZENA,W
MOVWF
EEDATA
BSF
EECON1,WREN
BCF
INTCON,GIE
BTFSC
INTCON,GIE
GOTO
$-2
MOVLW
0x55
MOVWF
EECON2
MOVLW
0xAA
MOVWF
EECON2
BSF
EECON1,WR
BSF
INTCON,GIE
BCF
GRAVAR_DEZENA
BSF
ESP_FIM_GRV_EEPROM
BSF
CONF_GRV_EEPROM
BANCO_0
RETURN

Parte 6 Contador II

;BIT GIE EST ZERADO?


;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON2 = AA HEXADECIMAL
;INICIA A GRAVAO
;HABILITA INTERRUPES
;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO

;SELECIONA BANCO 0 DE MEMORIA


;RETORNA

;SELECIONA O BANCO 1 DE MEMRIA


;INCREMENTA EEADR
;W = DEZENA
;EEDATA = DEZENA
;HABILITA ESCRITA NA EEPROM
;DESABILITA AS INTERRUPES
;BIT GIE EST ZERADO?
;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
;W = NUMERO 55 HEXADECIMAL
;EECON2 = 55 HEXADECIMAL
;W = NUMERO AA HEXADECIMAL
;EECON2 = AA HEXADECIMAL
;INICIA A GRAVAO
;HABILITA INTERRUPES
;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
;SETA O FLAG PARA CONFERIR A GRAVAO DA EEPROM
;SELECIONA BANCO 0 DE MEMORIA
;RETORNA

TESTA_FIM_DA_GRAVACAO
BANCO_1
;SELECIONA O BANCO 1 DE MEMRIA
BTFSC
EECON1,WR
;A GRAVAO TERMINOU?
GOTO
DEC_CONT_TEMPO_FIM_ESCRITA
;NAO, DESVIA
BCF
ESP_FIM_GRV_EEPROM
;SIM, APAGA FLAG
BCF
EECON1,WREN
;DESABILITA ESCRITA NA EEPROM
MOVLW
INI_ESC_EEPROM_A
;W = INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
;REINICIA ESC_EEPROM_A
MOVLW
INI_ESC_EEPROM_B
;W = INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
;REINICIA ESC_EEPROM_B
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
RETURN
;RETORNA
DEC_CONT_TEMPO_FIM_ESCRITA
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
DECFSZ
ESC_EEPROM_A,F
;DECREMENTA ESC_EEPROM_A. ESC_EEPROM_A = 0?
RETURN
;NAO, RETORNA
MOVLW
INI_ESC_EEPROM_A
;SIM, W = INI_ESC_EEPROM_A
MOVWF
ESC_EEPROM_A
;REINICIA ESC_EEPROM_A
DECFSZ
ESC_EEPROM_B,F
;DECREMENTA ESC_EEPROM_B.ESC_EEPROM_B = 0?
RETURN
;NAO, RETORNA
MOVLW
INI_ESC_EEPROM_B
;SIM, W = INI_ESC_EEPROM_B
MOVWF
ESC_EEPROM_B
;REINICIA ESC_EEPROM_B
BSF
APAGAR_UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE
BSF
GRAVAR_UNIDADE
;SETA O FLAG PARA GRAVAO DA UNIDADE

140

Tutorial de Programao Assembly para Microcontroladores PIC -

BSF
BCF
BCF
BANCO_0
RETURN

GRAVAR_DEZENA
ESP_FIM_GRV_EEPROM
CONF_GRV_EEPROM

CONFERE_DEZENA
BANCO_1
BSF
EECON1,RD
MOVF
DEZENA,W
XORWF
EEDATA,W
BTFSC
STATUS,Z
GOTO
CONFERE_APAGAMENTO
BCF
CONF_GRV_EEPROM
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
BANCO_0
RETURN
CONFERE_APAGAMENTO
DECF
EEADR,F
DECF
EEADR,F
DECF
EEADR,F
MOVLW
.254
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONFERENCIA
MOVLW
.126
MOVWF
EEADR
CONT_CONFERENCIA
BSF
EECON1,RD
MOVF
EEDATA,W
BTFSC
STATUS,Z
GOTO
CONFERE_UNIDADE
BCF
CONF_GRV_EEPROM
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
BANCO_0
RETURN
CONFERE_UNIDADE
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONF_UNIDADE
CLRF
EEADR
CONT_CONF_UNIDADE
BSF
EECON1,RD
MOVF
UNIDADE,W
IORLW
B'01100000'
XORWF
EEDATA,W
BTFSC
STATUS,Z
GOTO
GRAVACAO_CORRETA
BCF
CONF_GRV_EEPROM

Parte 6 Contador II

;SETA O FLAG PARA GRAVAO DA DEZENA


;APAGA FLAG DE ESPERA PELO FIM DA GRAVACAO
;APAGA O FLAG PARA CONFERIR A GRAVAO DA EEPROM

;SELECIONA O BANCO 0 DE MEMRIA


;RETORNA

;SELECIONA O BANCO 1 DE MEMRIA


;INICIA LEITURA
;W = DEZENA
;W = W XOR EEDATA
;VALOR DA DEZENA FOI GRAVADO CORRETAMENTE?
;SIM
;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA

;DECREMENTA EEADR
;DECREMENTA EEADR
;DECREMENTA EEADR
;W = 254
;W = W XOR EEADR
;EEADR = 254?
;NAO, DESVIA
;SIM, W = 126
;EEADR = 126
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;LOCALIDADE ANTERIOR DA UNIDADE FOI APAGADO CORRETAMENTE?

;SIM
;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

;SETA O FLAG PARA GRAVAO DA UNIDADE


;SETA O FLAG PARA GRAVAO DA DEZENA
;SELECIONA O BANCO 0 DE MEMRIA
;RETORNA

;INCREMENTA EEADR
;INCREMENTA EEADR
;W = 128
;W = W XOR EEADR
;EEADR = 128?
;NAO, DESVIA
;SIM, EEADR = 0
;INICIA LEITURA
;W = UNIDADE
;W = W OR B'01100000'
;W = W XOR EEDATA
;VALOR DA UNIDADE FOI GRAVADO CORRETAMENTE?
;SIM
;NAO, APAGA FLAG

141

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BSF
APAGAR_UNIDADE
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE
BSF
GRAVAR_UNIDADE
;SETA O FLAG PARA GRAVAO DA UNIDADE
BSF
GRAVAR_DEZENA
;SETA O FLAG PARA GRAVAO DA DEZENA
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
RETURN
;RETORNA
GRAVACAO_CORRETA
BCF
CONF_GRV_EEPROM
;APAGA FLAG
MOVF
EEADR,W
;W = EEADR
MOVWF
LOCAL_DA_UNIDADE
;LOCAL_DA_UNIDADE = EEADR
BANCO_0
;SELECIONA O BANCO 0 DE MEMRIA
RETURN
;RETORNA
;*************************************************************************************************
END

;FIM DO PROGRAMA

Vamos simular a execuo do programa.


No MPLAB, no menu Project, clique em Open e abra o projeto de nome
Contador. No menu Project, clique em Remove File From Project e remova o arquivo
Contador.asm. No menu Project, clique em Add Files to Project e inclua o arquivo
ContadorII.asm. Ateno: A opo Add Files to Project e no Add New File to Project.
No menu Project, clique em Build All.
Na janela Output, verifique se a mensagem BUILD SUCCEEDED foi
exibida. Caso contrrio, confira se o programa est exatamente igual.
No menu View, clique em EEPROM. Repare que a localidade 00 est
com o valor 60 hexadecimal, que corresponde ao nmero binrio 01100000, enquanto a localidade 01
est com o nmero 00. O MPLAB escreveu esses valores ao executar a diretiva DE constante no
programa:

142

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Figura 1
No Watch, no boto ADD SFR, inclua os registradores EECON1,
EEADR, EEDATA e WREG.
Na barra de ferramentas do simulador, clique no boto Reset. Em seguida,
v clicando no boto Step Into.
Quando chegar em Inicializao das Variveis, clique nos botes do
Stimulus que fixam o RA0 e o RA1 em nvel alto (Set High) para simular que os botes 1 e 2
esto soltos.
Durante a inicializao das variveis, acompanhe, no Watch, os valores dos
registradores EECON1, EEADR, EEDATA e W, conforme as instrues vo sendo executadas.
Vamos medir o tempo de espera pela concluso da gravao da EEPROM, que
queremos que seja de cerca de 10 milissegundos.
Esse o tempo que o programa ir esperar para que o bit WR volte a 0,
depois que a gravao iniciada.
Para podermos medir esse tempo, vamos fazer uma alterao no programa:
Em TESTA_FIM_DA_GRAVACAO, onde consta: BTFSC EECON1,WR
mude para: BTFSS EECON1,WR
Dessa forma, poderemos medir o tempo, pois esse bit est com o valor 0 e no
mudar.
Aps essa alterao, monte o projeto novamente, clicando em Build All, no
menu Project.
Clique no boto Reset do simulador e depois v clicando no boto Step
Into at chegar inicializao das variveis.

143

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

No Stimulus, clique nos botes que fixam o RA0 e o RA1 em nvel alto
para simular que os botes esto soltos.
Continue clicando em Step Into at chegar subrotina de gravao da
EEPROM.
Em TESTA_FIM_DA_GRAVACAO, insira um breakpoint na linha que
contm a instruo BCF ESP_FIM_GRV_EEPROM, dando um duplo clique nessa linha.
Quando o programa for executar essa instruo, o tempo de espera ter
terminado.
Precisamos setar manualmente o flag ESP_FIM_GRV_EEPROM para que
o programa entre em TESTA_FIM_DA_GRAVACAO.
Para fazer isso, no Watch, d um duplo clique no campo Binary da linha
do registrador FLAGS, e altere o bit 5 para 1:

Figura 2
No Stopwatch, clique em Zero.
A seguir, clique no boto Run da barra de ferramentas do simulador. O
programa ir parar no breakpoint.
Confira no Stopwatch que demorou cerca de 22 milissegundos para que a
varivel ESC_EEPROM_B chegasse a 0:

144

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Figura 3
Vamos diminuir esse tempo, alterando o valor de inicializao dessa varivel
para 1 na seo Constantes, em INI_ESC_EEPROM_B.
Aps essa alterao, monte o projeto novamente, clicando em Build All, no
menu Project.
Clique no boto Reset do simulador e depois v clicando no boto Step
Into at chegar inicializao das variveis.
No Stimulus, clique nos botes que fixam o RA0 e o RA1 em nvel alto
para simular que os botes esto soltos.
Continue clicando em Step Into at chegar subrotina de gravao da
EEPROM.
No Watch, sete novamente o flag ESP_FIM_GRV_EEPROM, dando um
duplo clique no campo Binary da linha do registrador FLAGS, e alterando o bit 5 para 1.
No Stopwatch, clique em Zero.
A seguir, clique no boto Run da barra de ferramentas do simulador. O
programa ir parar novamente no breakpoint.
Confira, no Stopwatch que o tempo diminuiu para cerca de 11
milissegundos:

145

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Figura 4
Podemos deixar este tempo pois, est bem prximo dos 10 milissegundos que
pretendamos.
Vamos desfazer a alterao feita em TESTA_FIM_DA_GRAVACAO,
voltando a instruo para: BTFSC EECON1,WR.
Aps isso, monte o projeto novamente, clicando em Build All, no menu
Project.
Clique no boto Reset do simulador e depois v clicando no boto Step
Into at chegar inicializao das variveis.
No Stimulus, clique nos botes que fixam o RA0 e o RA1 em nvel alto
para simular que os botes esto soltos.
No menu Debugger, clique em Breakpoints. Na janela que se abre, clique
em Remove All.
Posicione as janelas para que possa clicar nos botes do Stimulus enquanto
observa os valores dos registradores no Watch.
Clique no boto Run do simulador.
No Stimulus, clique no boto que simula que o boto 1 foi pressionado e
solto (RA0 Pulse Low).
No Watch repare que o valor da unidade foi incrementado.
Clique no boto Halt do simulador.
No menu Window, selecione a janela EEPROM. Se ela no estiver na
lista, clique em EEPROM no menu View para exibi-la.

146

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Repare que a localidade 02 est com o valor 61 hexadecimal. Esse valor


corresponde em binrio a 01100001, que contm o valor da unidade (1) nos bits 0 a 4 e o cdigo nos
bits 5 a 8. A prxima localidade est com o valor 0 que corresponde ao valor da dezena:

Figura 5

Clique no boto Run do simulador e em seguida incremente novamente o


contador, clicando no boto do Stimulus.
Clique no boto Halt do simulador.
Na janela EEPROM, repare que a localidade 04 est com o valor 62
hexadecimal, que corresponde em binrio a 01100010, que contm o valor da unidade (2) nos bits 0 a
4 e o cdigo nos bits 5 a 8. A prxima localidade est com o valor 0 da dezena. Repare, tambm que a
localidade 02 foi zerada. Lembre-se que a localidade anterior da dezena no apagado, pois no
necessrio:

147

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Figura 6

Continue incrementando ou decrementando o contador e repare que a cada


vez que o valor da unidade alterado, os valores da unidade e da dezena so salvos em duas novas
localidades da memria EEPROM, conforme planejado.
Grave o programa no microcontrolador e teste na protoboard.
Repare que quando ligamos o circuito, ele exibe o valor com que estava antes
de ser desligado.
Aqui termina esta parte do tutorial. Na prxima, utilizaremos o PIC16F628A
para gerar um sinal PWM para controlar o brilho de um LED utilizando dois botes. Um dos botes
far o brilho aumentar at o mximo enquanto o outro o far diminuir at o LED apagar.
At l!

148

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Parte 7
Dimmer para LED
Nesta parte do tutorial, vamos montar o circuito da figura abaixo para
controlar o brilho de um LED usando dois botes: um para aument-lo e outro para diminui-lo.

Figura 1
Para isso, vamos utilizar o modo PWM do PIC16F628A. Esse recurso do
microcontrolador produz um sinal PWM no pino RB3/CCP1 (pino 9). A forma de onda de um sinal
PWM pode ser vista na figura abaixo:

Figura 2

149

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Chamaremos o tempo durante o qual a tenso mxima de semiciclo ativo.


Suponha que apliquemos esse sinal a um LED de forma que, durante o
semiciclo ativo, ele esteja aceso e, no restante do tempo, apagado. Assim, esse LED ficar piscando
na frequncia do sinal. A partir de uma determinada frequncia, teremos a impresso de que ele est
permanentemente aceso, devido ao fenmeno da persistncia da viso. Se reduzirmos o tempo de
durao do semiciclo ativo, mantendo o do ciclo, conforme figura abaixo, teremos a impresso de que
o brilho do LED diminuiu. Isso ocorre porque apesar de, durante o semiciclo ativo, o LED acender
com a mesma intensidade, ele fica aceso por um tempo menor.

Figura 3
Por outro lado, se aumentarmos o tempo de durao do semiciclo ativo,
mantendo o do ciclo, conforme figura abaixo, teremos a impresso de que o brilho do LED aumentou.

Figura 4
Como voc pode observar, o tempo de durao do ciclo do sinal no muda,
portanto a frequncia do sinal PWM, que igual ao inverso do valor do tempo de durao do ciclo,
no muda. O que ir mudar o tempo de durao do semiciclo ativo, isto , o tempo em que o sinal
ficar em nvel alto.

150

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Para que no se perceba que o LED est piscando, temos de escolher uma
frequncia de, pelo menos, 75 Hz para o sinal PWM.
Vamos ver como o PIC16F628A produz o sinal PWM.
Na parte 2 deste tutorial, falamos sobre o Timer 0. O PIC16F628A possui
outros dois circuitos semelhantes: o Timer 1 e o Timer 2.
A principal diferena do Timer 1 em relao ao Timer 0 que ele composto
por dois registradores de 8 bits enquanto que o Timer 0 possui apenas um. Os registradores do Timer
1 so o TMR1L e o TMR1H.
Quando o Timer 1 incrementado, esse incremento ocorre no TMR1L que
pode ir at o valor 255. No prximo incremento, ele volta para o valor 0 e o TMR1H incrementado.
Assim, o Timer 1 pode ser incrementado at o valor 65535, o que o torna ideal para contagem de
tempos mais longos.
O Timer 1 pode ser incrementado tanto a partir do ciclo de instruo como a
partir de um sinal externo aplicado no pino 13 (RB7/T1OSI/PGD). Um cristal pode ser ligado entre
esse pino e o pino 12 (RB6/T1OSO/T1CKI/PGC), para fazer funcionar um oscilador interno
otimizado para a frequncia de 32.768 KHz, ideal para relgios.
O Timer 1 possui um prescaler que pode ser configurado para 1:1, 1:2, 1:4 ou
1:8.
O Timer 2, assim como o Timer 0, constitudo de apenas um registrador de 8
bits, o TMR2 e, portanto, seu valor pode ser incrementado at 255, porm, somente possvel
increment-lo a partir do ciclo de instruo, no sendo possvel increment-lo a partir de um sinal
externo.
O Timer 2 possui algumas caractersticas diferentes dos demais:
Existe um registrador chamado PR2 cujo valor define at onde o registrador
TMR2 poder ser incrementado. Por exemplo, se o valor do PR2 for igual a 255, o TMR2 poder ser
incrementado at esse valor e, no prximo incremento ele ir estourar, ou seja, seu valor voltar para
0. J, se o valor do PR2 for, por exemplo, 100, o TMR2 poder ser incrementado at esse valor
estourando no prximo incremento. Podemos escrever qualquer valor entre 0 e 255 no PR2.
O seu Prescaler pode assumir apenas os seguintes valores: 1:1, 1:4 ou 1:16, ou
seja, ele pode incrementado a cada ciclo de instruo ou a cada quatro ciclos ou a cada dezesseis
ciclos.
O Timer 2 possui um Postscaler, que pode ser configurado de 1:1 at 1:16. O
Postscaler define o nmero de vezes que o TMR2 dever estourar para gerar uma interrupo. Por
exemplo, se ele estiver configurado para 1:1, a cada vez que o TMR2 estourar, o flag TMR2IF ser
setado, gerando uma interrupo (desde que ela esteja habilitada). J, se o Postscaler estiver
configurado, por exemplo, para 1:5, uma interrupo ser gerada a cada 5 estouros do TMR2.
As configuraes do Prescaler e do Postscaler so feitas no registrador
T2CON, onde tambm h um bit para ligar e desligar o Timer 2.
no mdulo CCP do PIC16F628A que gerado o sinal PWM. A
configurao do mdulo CCP feita no registrador CCP1CON. Devemos setar os bits 3 e 2 desse
registrador para habilitar o modo PWM.

151

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

O ciclo do sinal PWM reinicia toda vez que o TMR2 estoura. A frmula para
o clculo do tempo de durao do ciclo do sinal PWM esta:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
fcil entender essa frmula, considerando que:
O ciclo termina (e um novo inicia) quando o TMR2 estoura.
O TMR2 estoura no prximo incremento aps seu valor se igualar ao PR2
(PR2 +1)
O TMR2 incrementado pelo ciclo de instruo.
O prescaler define de quantos em quantos ciclos de instruo o TMR2 ser
incrementado.
No nosso caso, queremos um sinal PWM com uma frequncia de 75 Hz, o
que equivale a um ciclo de cerca de 13 milissegundos. Como estamos usando o oscilador interno do
PIC, que de 4 MHz, o ciclo de instruo tem a durao de 1 microssegundo, pois o ciclo de instruo igual a quatro vezes o valor do ciclo do oscilador (1/4.000.000 x 4).
Vamos aplicar a frmula com o valor do prescaler em 1:1:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 1
0,013 =
(PR2 + 1) x 0,000001
PR2 + 1 = 0,013/0,000001
PR2 + 1 = 13.000
PR2 = 13.000 1
PR2 = 12.999
Mas, o valor mximo para o PR2 de 255. Vamos ver qual seria o valor do
PR2 para um prescaler de 1:4:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 4
0,013 =
(PR2 + 1) x 0,000004
PR2 + 1 = 0,013/0,000004
PR2 + 1 = 3.250
PR2 = 3.250 1
PR2 = 3.249
Novamente obtivemos um valor muito alto para o PR2. Vamos, ento, aumentar o valor do prescaler para 1:16:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 16
0,013 =
(PR2 + 1) x 0,000016
PR2 + 1 = 0,013/0,000016
PR2 + 1 = 812,5
PR2 = 812,5 1
PR2 = 811,5

152

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

O valor a ser escrito no PR2 continua acima de 255. Isto mostra que no
possvel obter um sinal PWM de 75 Hz se a frequncia de oscilao do microcontrolador de 4 MHz.
Teramos de diminuir a frequncia do oscilador se quisssemos um sinal PWM de 75 Hz. Poderamos
fazer isso alterando a frequncia do oscilador interno para 48 KHz ou ento usando um cristal externo.
Escrevendo no PR2 o seu valor mximo (255) e configurando o prescaler
tambm para seu valor mximo (16), obtemos a mxima durao do ciclo do sinal PWM para uma
frequncia de oscilao de 4 MHz:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
Ciclo = (255 + 1) x 0,000001 x 16
Ciclo = 256 x 0,000001 x 16
Ciclo = 0,004096 segundo
Esse tempo de durao do ciclo corresponde frequncia de 244 Hz
(1/0,0049096). No nosso circuito, precisamos que o sinal PWM tenha uma frequncia maior do que
75 Hz para evitar que se perceba que o LED est piscando. Sendo assim, podemos usar a frequncia
de 244 Hz, at mesmo porque o LED pode operar em frequncias bem maiores que esta.
Vimos como definir a durao do ciclo do sinal PWM. Vamos ver agora como
se define o tempo de durao do semiciclo ativo. O semiciclo ativo comea junto com o ciclo e termina quando o sinal vai para nvel baixo.
O sinal PWM do PIC16F628A pode ter uma resoluo de at 10 bits, dependendo da frequncia do prprio sinal e da frequncia de oscilao. Uma resoluo de 10 bits significa
que podemos definir 1024 (210) tempos de durao diferentes para o semiciclo ativo.
No nosso caso, o tempo de durao do ciclo de 4,096 milissegundos. Dividindo este valor por 1024, conclumos que podemos variar o tempo de durao do semiciclo ativo em
passos de 0,004 milissegundo desde o mnimo de 0,004 milissegundo at o mximo de 4,092 milissegundos.
Para definirmos o tempo de durao do semiciclo ativo, escrevemos um valor
entre 0 e 1024 na combinao de 10 bits formada pelo registrador CCPR1L e os bits 5 e 4 do registrador CCP1CON. Nessa combinao, o registrador CCPR1L representa os 8 bits mais significativos:
Bit 9

Bit 8

Bit 7

Bit 6

Bit 5

Bit 4

CCPR1L

Bit 3

Bit 2

Bit 1
CCP1CON
Bit 5

Bit 0
CCP1CON
Bit 4

Tabela 1
Se escrevermos o valor 0, o sinal ficar o tempo todo em nvel baixo. Se escrevermos o valor 1024, ele ficar o tempo todo em nvel alto. Nesses casos, no teremos um sinal
PWM.
Se escrevermos o valor 1, o semiciclo ter a durao mnima (0,004 milissegundo) e, se escrevermos o valor 1023, a mxima (4,092 milissegundos).
Vamos supor que queiramos que o tempo de durao do semiciclo ativo seja
de 10% do tempo de durao do ciclo. Nesse caso, temos de escrever o valor 102,4 (10% de 1024)
nos 10 bits da referida combinao.
Como o nmero a ser escrito tem de ser inteiro, arredondamos para 102, que,
em binrio, igual a 1100110. Portanto:

153

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Bit 9

Bit 8

Bit 7

Bit 6

Bit 5

Bit 4

Bit 3

Bit 2

Bit 1
CCP1CON
Bit 5

Bit 0
CCP1CON
Bit 4

CCPR1L
Tabela 2

Ou seja, temos de escrever o nmero binrio 00011001 no registrador


CCPR1L, setar o bit 5 e zerar o bit 4 do registrador CCP1CON.
Uma outra combinao de 10 bits formada pelo registrador TMR2 e dois bits
do oscilador interno do microcontrolador incrementada a cada ciclo do oscilador. Quando as duas
combinaes se igualam o semiciclo ativo termina, isto , o sinal PWM vai para nvel baixo.
Se voc preferir, pode usar a seguinte frmula para o clculo do tempo de durao do semiciclo ativo:
Semiciclo ativo = (CCPR1L:CCP1CON<5:4>) x ciclo de oscilao x prescaler do TMR2
Nessa frmula, (CCPR1L:CCP1CON<5:4>) o valor de 0 a 1024 a ser escrito na combinao de 10 bits formada pelo registrador CCPR1L e os bits 5 e 4 do CCP1CON; ciclo
de oscilao o tempo de durao de um ciclo do oscilador do microcontrolador, que, no nosso caso
igual a 0,00000025 segundo (1/4000000).
Vamos aplicar a frmula para o exemplo dos 10% que demos acima, onde a
durao do semiciclo ativo de 10% do ciclo, ou seja, 0,0004096 segundo:
Semiciclo ativo = (CCPR1L:CCP1CON<5:4>) x ciclo de oscilao x prescaler do TMR2
0,0004096 = (CCPR1L:CCP1CON<5:4>) x 0,00000025 x 16
0,0004096 = (CCPR1L:CCP1CON<5:4>) x 0,000004
(CCPR1L:CCP1CON<5:4>) = 0,0004096 / 0,000004
(CCPR1L:CCP1CON<5:4>) = 102,4
Que resulta no valor 102,4 que havamos encontrado quando dividimos o nmero 1024 por 10.
A figura abaixo mostra os eventos que provocam o reincio do ciclo e o fim
do semiciclo ativo do sinal PWM.

154

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 5
No nosso circuito, quando o boto 1 for pressionado, o brilho do LED ir aumentar at o mximo e, quando o boto 2 for pressionado, o brilho ir diminuir at o LED apagar.
Com o LED apagado, o boto 1 dever ficar pressionado por cerca de 5 segundos para que o brilho atinja o mximo. Esse tambm ser o tempo que o boto 2 dever ser mantido pressionado para que o LED apague, partindo do brilho mximo.
Como vimos, possvel definir 1024 valores diferentes para o tempo de durao do semiciclo ativo do sinal PWM, escrevendo na combinao de 10 bits, um valor entre 0 e 1024.
No precisamos de uma resoluo to alta. Se modificarmos apenas o valor do
registrador CCPR1L, j teremos 256 valores diferentes, o que mais do que suficiente para uma variao suave no brilho. Dividindo 5 segundos por 256, obtemos 0,01953125 segundo, ou seja, aproximadamente 19 milissegundos.
Iremos configurar o Timer 0 para que ele provoque uma interrupo a cada
cerca de 19 milissegundos. Na rotina da interrupo, iremos verificar qual boto est pressionado. Se
for o boto 1, iremos incrementar o registrador CCPR1L. Se for o boto 2 decrementaremos o
CCPR1L. Se nenhum boto estiver pressionado, manteremos o valor do CCPR1L.
Para configurarmos o Timer 0 a fim de que ele provoque uma interrupo a
cada 19 milissegundos, primeiramente dividimos 19 milissegundos pelo tempo de durao de um
ciclo de instruo, que de 1 microssegundo: 0,019 / 0,000001 = 19.000.
Isto significa que 19 milissegundos equivalem a 19.000 ciclos de instruo, ou
seja, o registrador TMR0 dever estourar a cada 19.000 ciclos de instruo. Como o registrador
TMR0 estoura a cada 256 incrementos, se fizssemos o valor do prescaler igual a 1:1, onde, o TMR0
incrementado a cada ciclo de instruo, ele iria estoura a cada 256 ciclos de instruo apenas. Ento,
precisamos aumentar o valor do prescaler para que ele estoure a cada 19.000 ciclos de instruo.

155

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Dividindo 19.000 por 256, encontramos o valor do prescaler: 19.000 / 256 =


74. Mas o prescaler pode ser definido para os seguintes valores: 1:1, 1:2, 1:4, 1:8, 1:16, 1:32, 1:64,
1:128 e 1:256, ou seja, no h como definir ele para 1:74. Nesse caso, vamos adotar o valor maior
mais prximo, que 1:128.
Se o valor do prescaler de 1:128, o TMR0 ser incrementado a cada 128 ciclos de instruo, estourando a cada: 256 x 128 = 32.768 ciclos de instruo, porm queremos que ele
estoure a cada 19.000 ciclos de instruo.
Para resolver isso, a cada vez que o TMR0 estourar (seu valor passar de 255
para 0, gerando uma interrupo), iremos escrever nele um determinado valor. Para encontrar esse
valor, inicialmente dividimos 19.000 por 128, que resulta em 148,4375, que arredondamos para 148.
A seguir, subtramos esse nmero de 256, o que resulta em 108 (256 148 = 108). Esse o valor que
iremos escrever no TMR0 toda vez que ele estourar.
Se o TMR0 comea a ser incrementado com o valor 108, ele ir estourar a cada 148 incrementos. Como o valor do prescaler de 128, ele ir estourar a cada 128 x 148 = 18.944
ciclos de instruo. Esse valor o mais prximo que conseguimos de 19.000.
Vamos ao programa!
No MPLAB, abra o arquivo Pisca LED III.asm da parte 3 deste tutorial e
salve-o com o nome Dimmer para LED.asm.
A primeira alterao na seo VARIVEIS. Exclua essa seo. Isso mesmo, no precisaremos de nenhuma varivel neste programa!
Exclua tambm a seo CONSTANTES.
Renomeie a seo SADA para ENTRADAS e defina a label BOTAO_1
para o pino RA0 e a label BOTAO_2 para o RA1:
;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE

BOTAO_1
BOTAO_2

PORTA,0
PORTA,1

;BOTAO 1 LIGADO EM RA0


;BOTAO 2 LIGADO EM RA1

;***********************************************************************************************

Na rotina de interrupo, a primeira instruo ser BTFSS INTCON,T0IF


portanto, exclua as anteriores a ela. Essa instruo testa se a interrupo foi a do Timer 0. Caso no
tenha sido, a instruo da prxima linha ser executada, onde samos da interrupo. Se a interrupo
foi do Timer 0, apagamos o flag na linha seguinte:
;************************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

BTFSS
RETFIE
BCF

INTCON,T0IF

;TMR0 ESTOUROU?
;NAO, SAI DA INTERRUPO
;SIM, APAGA O FLAG

INTCON,T0IF

A seguir, escrevemos o nmero 108 no registrador TMR0:


MOVLW
MOVWF

.108
TMR0

;W = 108
;REINICIA TMR0

156

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Agora, testamos se o boto 1 est pressionado. Se estiver, desviamos o programa para onde esta a label INCREMENTA_CCPR1L:
BTFSS
GOTO

BOTAO_1
INCREMENTA_CCPR1L

;BOTAO 1 EST PRESSIONADO?


;SIM

Caso contrrio, testamos se o boto 2 est pressionado. Se estiver, desviamos


o programa para onde est a label DECREMENTA_CCPR1L:
BTFSS
GOTO

BOTAO_2
DECREMENTA_CCPR1L

;NAO, BOTAO 2 EST PRESSIONADO?


;SIM

Se o boto 2 no estiver pressionado, samos da interrupo:


RETFIE

;NAO, SAI DA INTERRUPO

Em INCREMENTA_CCPR1L, primeiramente testamos se o valor do


CCPR1L igual a 255, pois, se for, iremos sair da interrupo sem increment-lo, caso contrrio seu
valor passaria para 0, apagando o LED e queremos que quando o brilho do LED chegar ao mximo,
fique no mximo:
INCREMENTA_CCPR1L
MOVLW
.255
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE

;W = 255
;W = W XOR CCPRR1L
;CCPR1L = 255?
;SIM, SAI DA INTERRUPO

Se o valor do CCPR1L no for igual a 255, incrementamo-lo e, em seguida,


samos da interrupo:
INCF
RETFIE

CCPR1L,F

;NAO, INCREMENTA CCPR1L


;SAI DA INTERRUPO

Em DECREMENTA_CCPR1L, primeiramente testamos se o valor do


CCPR1L igual a 0, pois, se for, iremos sair da interrupo sem decrement-lo, caso contrrio seu
valor passaria para 255, acendendo o LED no mximo brilho e queremos que quando o LED apagar,
fique apagado:
DECREMENTA_CCPR1L
MOVLW
.0
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE
DECF
CCPR1L,F
RETFIE

;W = 0
;W = W XOR CCPRR1L
;CCPR1L = 0?
;SIM, SAI DA INTERRUPO
;NAO, DECREMENTA CCPR1L
;SAI DA INTERRUPO

Com isso conclumos a rotina de interrupo.


Na seo CONFIGURACAO DOS REGISTRADORES DE USO
ESPECFICO, vamos configurar o registrador OPTION_REG, para que o Timer 0 seja
incrementado pelo ciclo de instruo (bit 5 = 0), com prescaler de 1:128 (bits 3:0 = 0110):

157

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

;***********************************************************************************************
;

CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO


INICIO
BANCO_1
MOVLW
MOVWF

B'11010110'
OPTION_REG

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010110'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO COM PRESCALER DE 1:128

Vamos tambm configurar todos os pinos do PORTA como entradas:


MOVLW
MOVWF

B'11111111'
TRISA

;W = B'11111111'
;CONFIGURA PORTA COMO ENTRADA

Quanto ao PORTB, vamos configurar o pino RB3/CCP1 como sada, pois a


sada do sinal PWM, e os demais como entradas:
MOVLW
MOVWF

B'11110111'
TRISB

;W = B'11110111'
;CONFIGURA BR3/CCP1 COMO SADA E DEMAIS COMO ENTRADA

A seguir, escrevemos o nmero 255 no registrador PR2:


MOVLW
MOVWF

.255
PR2

;W = 255
;PR2 = 255

Passamos agora para os registradores do banco 0, onde mantemos as


configuraes do CMCON para que os pinos RA0 e RA1 possam ser usados como pinos de entrada, e
do INTCON para que a interrupo do Timer 0 esteja habilitada:
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF

;SELECIONA BANCO 0 DE MEMORIA


B'00000111'
CMCON
B'11100000'
INTCON

;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O


;HABILITA INTERRUPO DO TIMER 0

A seguir, configuramos o registrador T2CON para ativar o Timer 2 (bit2 = 1),


com prescaler de 1:16 (bit 1 = 1):
MOVLW
MOVWF

B'00000110'
T2CON

;ATIVA O TIMER 2, COM PRESCALER DE 1:16

Em seguida zeramos o CCPR1L para que quando o circuito for ligado o LED
esteja apagado:
CLRF

CCPR1L

;ZERA CCPR1L

Por fim, configuramos o registrador CCP1CON para habilitar o modo PWM,


setando os bits 3 e 2 desse registrador:

158

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

MOVLW
MOVWF

B'00001100'
CCP1CON

;W = B'00001100'
;HABILITA MODO PWM DO MODULO CCP

Com isso, conclumos a configurao dos registradores de uso especfico.


Em seguida, exclua a seo INICIALIZAO DAS VARIVEIS.
A seguir vem a rotina principal. Vamos chamar esta parte do programa de
ROTINA PARA AGUARDAR A INTERRUPO, afinal, no tem sentido cham-la de principal,
j que a rotina mais importante deste programa a de interrupo.
Aqui o programa ficar executando a instruo CLRWDT at que ocorra a
interrupo:
;**********************************************************************************************
;ROTINA PARA AGUARDAR A INTERRUPO
CLRWDT
GOTO

;LIMPA O WDT
;RETORNA UMA LINHA

$-1

;**********************************************************************************************

O programa est pronto, tendo ficado assm:


;***********************************************************************************************
;
PROGRAMA: DIMMER PARA LED
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>

;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
;

BITS DE CONFIGURAO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF &
_LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;

PAGINACAO DE MEMORIA
#DEFINE
#DEFINE

BANCO_0
BANCO_1

BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE

BOTAO_1
BOTAO_2

PORTA,0
PORTA,1

;BOTAO 1 LIGADO EM RA0


;BOTAO 2 LIGADO EM RA1

;***********************************************************************************************

159

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

;***********************************************************************************************
;
VETOR DE RESET
ORG

0X00
GOTO

INICIO

;ENDERECO INICIAL DE PROCESSAMENTO


;DESVIA PARA INICIO

;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG

0X04

;VETOR DAS INTERRUPES

BTFSS
RETFIE
BCF
MOVLW
MOVWF
BTFSS
GOTO
BTFSS
GOTO
RETFIE

INTCON,T0IF

;TMR0 ESTOUROU?
;NAO, SAI DA INTERRUPO
;SIM, APAGA O FLAG
;W = 108
;REINICIA TMR0
;BOTAO 1 EST PRESSIONADO?
;SIM
;NAO, BOTAO 2 EST PRESSIONADO?
;SIM
;NAO, SAI DA INTERRUPO

INTCON,T0IF
.108
TMR0
BOTAO_1
INCREMENTA_CCPR1L
BOTAO_2
DECREMENTA_CCPR1L

INCREMENTA_CCPR1L
MOVLW
.255
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE
INCF
CCPR1L,F
RETFIE

;W = 255
;W = W XOR CCPRR1L
;CCPR1L = 255?
;SIM, SAI DA INTERRUPO
;NAO, INCREMENTA CCPR1L
;SAI DA INTERRUPO

DECREMENTA_CCPR1L
MOVLW
.0
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE
DECF
CCPR1L,F
RETFIE

;W = 0
;W = W XOR CCPRR1L
;CCPR1L = 0?
;SIM, SAI DA INTERRUPO
;NAO, DECREMENTA CCPR1L
;SAI DA INTERRUPO

;************************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW

B'11010110'
OPTION_REG
B'11111111'
TRISA
B'11110111'
TRISB
.255
PR2
B'00000111'
CMCON
B'11100000'
INTCON
B'00000110'

;SELECIONA BANCO 1 DE MEMORIA


;W = B'11010110'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO COM PRESCALER DE 1:128

;W = B'11111111'
;CONFIGURA PORTA COMO ENTRADA
;W = B'11110111'
;CONFIGURA RB3/CCP1 COMO SADA E DEMAIS COMO ENTRADA
;W = 255
;PR2 = 255
;SELECIONA BANCO 0 DE MEMORIA
;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
;HABILITA INTERRUPO DO TIMER 0

160

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

MOVWF
CLRF
MOVLW
MOVWF

T2CON
CCPR1L
B'00001100'
CCP1CON

;ATIVA O TIMER 2, COM PRESCALER DE 1:16


;ZERA CCPR1L
;W = B'00001100'
;HABILITA MODO PWM DO MODULO CCP

;**********************************************************************************************
;
ROTINA PARA AGUARDAR A INTERRUPO
CLRWDT
GOTO

$-1

;LIMPA O WDT
;RETORNA UMA LINHA

;**********************************************************************************************
END

;FIM DO PROGRAMA

Vamos simular a execuo do programa.


No MPLAB, no menu Project, clique em Project Wizard....
Na janela Welcome, clique em Avanar.
Na janela Step One, selecione o PIC16F628A e clique em Avanar.
Na janela Step Two, clique em Avanar.
Na janela Step Three, clique em Browse. Na janela que se abre, em
Nome do arquivo, escreva: Dimmer para LED e clique em salvar e, na janela Step Three,
clique em Avanar.
Na janela Step Four, selecione o arquivo Dimmer para LED.asm, clique em
Add e depois clique em Avanar.
Na janela Summary, clique em Concluir.
No menu Project, clique em Build All.
Na janela que se abre, clique em Absolute.
Verifique se a mensagem BUILD SUCCEEDED foi exibida na janela
Output. Se no, confira o programa.
No menu Debugger, clique em Select Tool e depois em MPLAB SIM.
No menu Debugger, clique em Settings. Na aba Osc/Trace, digite 4 no
campo Processor Frequency e selecione MHz em Unit. Na aba Animation/Real Time Update,
selecione Enable Real Time watch updates e mova a barra toda para a esquerda (Fastest). Clique
em OK.
No menu File, clique em Open. Selecione e abra o arquivo Dimmer para
LED.asm.
No menu View, clique em Watch. Adicione o PORTB e o CCPR1L,
selecionando-os na lista ao lado do boto Add SFR e depois clicando nesse boto.
No menu Debugger, clique em Stimulus e depois em New Workbook.
Na coluna Pin/SFR, clique no campo em branco da primeira linha e selecione
o pino RA0. Na mesma linha, no campo em branco da coluna Action, selecione Set High. Repita
a operao na segunda linha, mas, selecionando Set Low.
Na terceira linha, selecione o pino RA1 e Set High e na quarta linha Set
Low para o mesmo pino, conforme figura 6 na prxima pgina.
Clique em Save. Escreva o nome Dimmer para LED e clique em Salvar.

161

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 6
No menu Window, selecione a janela do programa (Dimmer para LED.asm),
na lista da parte de baixo do menu, para visualiz-la.
Na barra de ferramentas do simulador, clique no boto Reset.
V clicando no boto Step Into at chegar na instruo CLRWDT.
Selecione a janela do Stimulus no menu Window. Na coluna Fire,
clique nos botes da primeira e terceira linhas para levar os pinos RA0 e RA1 para nvel alto,
simulando que os botes esto soltos.
Vamos medir o tempo entre uma interrupo e outra.
Volte para a janela do programa.
Insira um breakpoint na primeira instruo da rotina de interrupo, dando
um duplo clique na sua linha.
Clique no boto Run do simulador. O programa ir parar no breakpoint.
No menu Debugger, clique em StopWatch. Clique em Zero.
Clique novamente no boto Run. Quando o programa parar no breakpoint
novamente, volte para a janela do Stopwatch e repare que o tempo entre uma interrupo e outra
de cerca de 19 milissegundos, conforme queramos:

162

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 7

Agora vamos ver se o CCPR1L est sendo incrementado e decrementado


pelos botes.
Remova o breakpoint, dando outro duplo clique na linha da primeira
instruo da interrupo.
Posicione as janelas de forma a poder visualizar a janela Watch enquanto
clica nos botes do Stimulus:

163

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 8
Clique no boto Run do simulador.
No Stimulus, clique no boto da coluna Fire que leva o pino RA0 para
nvel baixo (Set Low) para simular que o boto 1 foi pressionado.
Observe que o CCPR1L foi incrementado at o valor 255.
Agora, clique no boto que leva o pino RA0 para o nvel alto, para simular
que o boto 1 foi solto.
Em seguida, clique no boto que leva o pino RA1 para nvel 0, simulando que
o boto 2 foi pressionado.
Observe que o CCPR1L foi decrementado at o valor 0 e l ficou.
Volte o pino RA1 para nvel alto, clicando no boto da terceira linha do
Stimulus.
Vamos medir o tempo que o boto 1 deve ficar pressionado para o CCPR1L ir
de 0 at 255.
Clique no boto Halt do simulador.
Insira um breakpoint na linha que contem a instruo RETFIE, que
executada quando o valor do CCPR1L for igual a 255:

164

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 9
Na janela do Stopwatch, clique em Zero.
Clique no boto que leva o pino RA0 para nvel baixo simulando que o boto
1 foi pressionado.
Clique no boto Run do simulador.
Quando o programa parar no breakpoint, veja, no Stopwatch que
transcorreu 4,84 segundos, conforme havamos projetado:

165

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED

Figura 10
Remova o breakpoint.
Clique no boto Run do simulador.
No Stimulus, volte o pino RA0 para nvel alto.
Repare que, quando o valor do CCPR1L igual a 255, o pino RB3 fica fixo
em nvel alto. Por outro lado, quando o valor do CCPR1L igual a 0, ele fica fixo em nvel baixo.
Com o valor do CCPR1L num ponto intermedirio, o estado do RB3 varia
entre 0 e 1, indicando que temos o sinal PWM nesse pino.
Grave o programa no microcontrolador, monte o circuito na protoboard e
comprove o seu funcionamento. muito interessante.
Se usarmos um rel de estado slido, ligado no pino RB3 podemos controlar
equipamentos de maior potncia, como por exemplo, lmpadas incandescentes, aquecedores, motores
eltricos, etc.
Aqui termina esta parte do tutorial. Espero que tenha sido til para voc. Na
prxima parte iremos desenvolver um frequencmetro. At l!

166

Você também pode gostar