Você está na página 1de 204

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

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

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 LED est aceso? Apaga LED


no sim

Indica o incio

Indica uma subrotina

3
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:

4
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

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

5
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.

6
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 1 Pisca LED

DATA_CP um recurso para proteger a memria de dados contra cpia.


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 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 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.

7
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

8
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 1 Pisca LED

variveis. Por esse motivo, minha forma preferida para defini-las com o uso da diretiva CBLOCK:
;**********************************************************************************************
; VARIAVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

DELAY_0 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO


DELAY_1 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
DELAY_2 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
ENDC ;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 intercal-
las 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
;***********************************************************************************************

9
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 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;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 ;SELECIONA BANCO 1 DE MEMORIA

MOVLW B'11111110' ;W = B'11111110'


MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS

BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

MOVLW B'00000111'
MOVWF 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 B'11111111'
MOVWF 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 B'00000111'

13
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 1 Pisca LED

MOVWF CMCON
So apenas esses os Registradores de Uso Especfico que precisamos
configurar nesse programa.

O prximo passo inicializar as variveis.


;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

MOVLW INI_DELAY_0 ;W = INI_DELAY_0


MOVWF DELAY_0 ;INICIALIZA DELAY_0
MOVLW INI_DELAY_1 ;W = INI_DELAY_1
MOVWF DELAY_1 ;INICIALIZA DELAY_1
MOVLW INI_DELAY_2 ;W = INI_DELAY_2
MOVWF 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.

14
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 1 Pisca LED

Vamos l!
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-las 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 isso, na prxima linha escrevemos: GOTO PRINCIPAL.
Isso 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 INI_DELAY_0
MOVWF 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 INI_DELAY_1
MOVWF DELAY_1
DECFSZ 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 INI_DELAY_2
MOVWF 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 ;ROTINA PRINCIPAL DO PROGRAMA

DECFSZ DELAY_0,F ;DECREMENTA DELAY_0. DELAY_0 = 0?


GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_0 ;SIM, W = INI_DELAY_0
MOVWF DELAY_0 ;REINICIALIZA DELAY_0
DECFSZ DELAY_1,F ;DECREMENTA DELAY_1. DELAY_1 = 0?
GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_1 ;SIM, W = INI_DELAY_1
MOVWF DELAY_1 ;REINICIALIZA DELAY_1
DECFSZ DELAY_2,F ;DECREMENTA DELAY_2. DELAY_2 = 0?
GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_2 ;SIM, W = INI_DELAY_2
MOVWF 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 LED ;testa o valor do bit 0 do PORTA


BSF LED ;valor = 0, acende o LED
BCF 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?

17
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 1 Pisca LED

Faremos assim:

BTFSS LED ;testa o valor do bit 0 do PORTA


GOTO ACENDE_LED ;valor = 0, desvia
BCF LED ;valor = 1, apaga o LED
GOTO PRINCIPAL ;desvia

ACENDE_LED
BSF LED ;ACENDE O LED
GOTO PRINCIPAL ;desvia

END ;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 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO


DELAY_1 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO
DELAY_2 ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO

ENDC ;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************
; 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

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

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES


RETFIE ;RETORNA

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;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 INI_DELAY_0 ;W = INI_DELAY_0


MOVWF DELAY_0 ;INICIALIZA DELAY_0
MOVLW INI_DELAY_1 ;W = INI_DELAY_1
MOVWF DELAY_1 ;INICIALIZA DELAY_1
MOVLW INI_DELAY_2 ;W = INI_DELAY_2
MOVWF DELAY_2 ;INICIALIZA DELAY_2

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

PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


DECFSZ DELAY_0,F ;DECREMENTA DELAY_0. DELAY_0 = 0?
GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_0 ;SIM, W = INI_DELAY_0
MOVWF DELAY_0 ;REINICIALIZA DELAY_0
DECFSZ DELAY_1,F ;DECREMENTA DELAY_1. DELAY_1 = 0?
GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_1 ;SIM, W = INI_DELAY_1
MOVWF DELAY_1 ;REINICIALIZA DELAY_1
DECFSZ DELAY_2,F ;DECREMENTA DELAY_2. DELAY_2 = 0?
GOTO PRINCIPAL ;NO
MOVLW INI_DELAY_2 ;SIM, W = INI_DELAY_2
MOVWF DELAY_2 ;REINICIALIZA DELAY_2
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO PRINCIPAL ;DESVIA
ACENDE_LED
BSF LED ;ACENDE O LED
GOTO PRINCIPAL ;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 BANCO_0 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 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 - Parte 2 Pisca LED II

CONT_EST_TMR0 ;USADO PARA CONTAR OS ESTOUROS DO TMR0

ENDC ;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 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA

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

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES


RETFIE ;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 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010100' ;W = B'11010100'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32
MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************
; INICIALIZACAO DA VARIAVEL

MOVLW INI_CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0


MOVWF 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 INI_TMR0 ;W = INI_TMR0
MOVWF 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 BANCO_0 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 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 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA

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

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES


RETFIE ;RETORNA

48
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 2 Pisca LED II

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010100' ;W = B'11010100'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32
MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;***********************************************************************************************
; INICIALIZACAO DA VARIAVEL

MOVLW INI_CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0


MOVWF CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0

;***********************************************************************************************
PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO PRINCIPAL ;NAO
BCF INTCON,T0IF ;SIM
MOVLW INI_TMR0 ;W = INI_TMR0
MOVWF TMR0 ;REINICIA TMR0
DECFSZ CONT_EST_TMR0,F ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
GOTO PRINCIPAL ;NAO
MOVLW INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO PRINCIPAL ;DESVIA
ACENDE_LED
BSF LED ;ACENDE O LED
GOTO PRINCIPAL ;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 BANCO_0 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 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 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
CONT_EST_TMR0 ;USADA PARA CONTAR OS ESTOUROS DO TMR0

ENDC ;FIM DO BLOCO DE MEMORIA

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

54
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 3 Pisca LED III

; CONSTANTES

INI_TMR0 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA

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

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;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 W_TEMP ;SALVA W EM W_TEMP


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;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 STATUS_TEMP,W ;W = SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;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 INI_TMR0 ;W = INI_TMR0
MOVWF 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 INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0

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


interrupo:
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO SAI_INT ;RETORNA DA INTERRUPCAO

ACENDE_LED
BSF LED ;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 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, SAIR DA INTERRUPO
BCF INTCON,T0IF ;SIM
MOVLW INI_TMR0 ;W = INI_TMR0
MOVWF TMR0 ;REINICIA TMR0
DECFSZ CONT_EST_TMR0,F ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
GOTO SAI_INT ;NAO
MOVLW INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA

57
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 3 Pisca LED III

GOTO ACENDE_LED ;VALOR = 0, DESVIA


BCF LED ;VALOR = 1, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO
ACENDE_LED
BSF LED ;ACENDE O LED

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

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

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 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010100' ;W = B'11010100'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32
MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS

MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;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 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************
; VARIVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
CONT_EST_TMR0 ;USADA PARA CONTAR OS ESTOUROS DO TMR0

ENDC ;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
; CONSTANTES

INI_TMR0 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA

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

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS

59
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 3 Pisca LED III

BTFSS INTCON,T0IF ;TMR0 ESTOUROU?


GOTO SAI_INT ;NAO, SAIR DA INTERRUPO
BCF INTCON,T0IF ;SIM
MOVLW INI_TMR0 ;W = INI_TMR0
MOVWF TMR0 ;REINICIA TMR0
DECFSZ CONT_EST_TMR0,F ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
GOTO SAI_INT ;NAO
MOVLW INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO

ACENDE_LED
BSF LED ;ACENDE O LED

SAI_INT
SWAPF STATUS_TEMP,W ;W = SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010100' ;W = B'11010100'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32
MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
; INICIALIZACAO DA VARIVEL

MOVLW INI_CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0


MOVWF CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0

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

PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


GOTO 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 ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


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

ENDC ;FIM DO BLOCO DE MEMORIA

;********************************************************************************************
A seguir, vamos criar as constantes para a inicializao das variveis
DB_BTA e DB_BTB:

;**********************************************************************************************
; CONSTANTES

INI_TMR0 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA
INI_DB_BTA EQU .255 ;VALOR QUE DB_BTA INICIA
INI_DB_BTB EQU .50 ;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 SOLTAR_BOTAO FLAGS,0 ;SE = 1 AGUARDA SOLTAR O BOTO


#DEFINE ESTADO_DO_LED FLAGS,1 ;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 INI_CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0


MOVWF CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0
CLRF FLAGS ;INICIALIZA FLAGS
MOVLW INI_DB_BTA ;W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
MOVLW INI_DB_BTB ;W = INI_DB_BTB
MOVWF 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 ;LIMPA O WDT


BTFSS SOLTAR_BOTAO ;AGUARDA SOLTAR O BOTAO?
GOTO TESTA_BOTAO ;NAO, DESVIA
BTFSS BOTAO ;SIM, O BOTO EST SOLTO?
GOTO PRINCIPAL ;NAO, DESVIA
BCF SOLTAR_BOTAO ;SIM, APAGA FLAG

TESTA_BOTAO
BTFSC BOTAO ;O BOTO EST PRESSIONADO?
GOTO REINC_CONT_DEB ;NO, DESVIA
DECFSZ DB_BTA,F ;SIM, DECREMENTA DB_BTA. DB_BTA = 0?
GOTO PRINCIPAL ;NAO, DESVIA
MOVLW INI_DB_BTA ;SIM, W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
DECFSZ DB_BTB,F ;DECREMENTA DB_BTB. DB_BTB = 0?
GOTO PRINCIPAL ;NAO, DESVIA
MOVLW INI_DB_BTB ;SIM, W = INI_DB_BTB
MOVWF DB_BTB ;INICIALIZA DB_BTB
BTFSS ESTADO_DO_LED ;LED EST PISCANDO?
GOTO PISCAR_O_LED ;NAO, DESVIA
BCF ESTADO_DO_LED ;SIM, APAGA O LED
BSF SOLTAR_BOTAO ;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO
GOTO PRINCIPAL ;DESVIA

PISCAR_O_LED
BSF ESTADO_DO_LED ;FAZ O LED PISCAR
BSF SOLTAR_BOTAO ;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO
GOTO PRINCIPAL ;DESVIA
REINC_CONT_DEB
MOVLW INI_DB_BTA ;W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
MOVLW INI_DB_BTB ;W = INI_DB_BTB

68
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 4 Pisca LED IV

MOVWF DB_BTB ;INICIALIZA DB_BTB


GOTO PRINCIPAL ;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 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, SAIR DA INTERRUPO
BCF INTCON,T0IF ;SIM
BTFSC ESTADO_DO_LED ;LED DEVER PISCAR?
GOTO CONT_INTERRUPCAO ;SIM, DESVIA
BCF LED ;NAO, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO

CONT_INTERRUPCAO
MOVLW INI_TMR0 ;W = INI_TMR0
MOVWF TMR0 ;REINICIA TMR0
DECFSZ CONT_EST_TMR0,F ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
GOTO SAI_INT ;NAO
MOVLW INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO

ACENDE_LED
BSF LED ;ACENDE O LED

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP

69
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 4 Pisca LED IV

MOVWF STATUS ;RECUPERA STATUS


SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;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 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;**********************************************************************************************
; VARIVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


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

ENDC ;FIM DO BLOCO DE MEMORIA

;**********************************************************************************************
; CONSTANTES

INI_TMR0 EQU .131 ;VALOR QUE TMR0 INICIA


INI_CONT_EST_TMR0 EQU .125 ;VALOR QUE CONT_EST_TMR0 INICIA
INI_DB_BTA EQU .255 ;VALOR QUE DB_BTA INICIA
INI_DB_BTB EQU .50 ;VALOR QUE DB_BTB INICIA

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

70
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 4 Pisca LED IV

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

;***********************************************************************************************
; ENTRADA

#DEFINE BOTAO PORTA,1 ;BOTAO LIGADO EM RA1

;***********************************************************************************************
; FLAGS

#DEFINE SOLTAR_BOTAO FLAGS,0 ;SE = 1 AGUARDA SOLTAR O BOTO


#DEFINE ESTADO_DO_LED FLAGS,1 ;SE = 1 LED PISCANDO

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, SAIR DA INTERRUPO
BCF INTCON,T0IF ;SIM
BTFSC ESTADO_DO_LED ;LED DEVER PISCAR?
GOTO CONT_INTERRUPCAO ;SIM, DESVIA
BCF LED ;NAO, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO

CONT_INTERRUPCAO
MOVLW INI_TMR0 ;W = INI_TMR0
MOVWF TMR0 ;REINICIA TMR0
DECFSZ CONT_EST_TMR0,F ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
GOTO SAI_INT ;NAO
MOVLW INI_CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0
MOVWF CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0
BTFSS LED ;TESTA O VALOR DO BIT 0 DO PORTA
GOTO ACENDE_LED ;VALOR = 0, DESVIA
BCF LED ;VALOR = 1, APAGA O LED
GOTO SAI_INT ;SAIR DA INTERRUPCAO

ACENDE_LED
BSF LED ;ACENDE O LED

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;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 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010100' ;W = B'11010100'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32
MOVLW B'11111110' ;W = B'11111110'
MOVWF TRISA ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
MOVLW B'11111111'
MOVWF TRISB ;TODOS OS PINOS DO PORTB COMO ENTRADAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

MOVLW INI_CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0


MOVWF CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0
CLRF FLAGS ;INICIALIZA FLAGS
MOVLW INI_DB_BTA ;W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
MOVLW INI_DB_BTB ;W = INI_DB_BTB
MOVWF DB_BTB ;INICIALIZA DB_BTB

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

PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


BTFSS SOLTAR_BOTAO ;AGUARDA SOLTAR O BOTAO?
GOTO TESTA_BOTAO ;NAO, DESVIA
BTFSS BOTAO ;SIM, O BOTO EST SOLTO?
GOTO PRINCIPAL ;NAO, DESVIA
BCF SOLTAR_BOTAO ;SIM, APAGA FLAG

TESTA_BOTAO
BTFSC BOTAO ;O BOTO EST PRESSIONADO?
GOTO REINC_CONT_DEB ;NO, DESVIA
DECFSZ DB_BTA,F ;SIM, DECREMENTA DB_BTA. DB_BTA = 0?
GOTO PRINCIPAL ;NAO, DESVIA
MOVLW INI_DB_BTA ;SIM, W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
DECFSZ DB_BTB,F ;DECREMENTA DB_BTB. DB_BTB = 0?
GOTO PRINCIPAL ;NAO, DESVIA
MOVLW INI_DB_BTB ;SIM, W = INI_DB_BTB
MOVWF DB_BTB ;INICIALIZA DB_BTB
BTFSS ESTADO_DO_LED ;LED EST PISCANDO?
GOTO PISCAR_O_LED ;NAO, DESVIA
BCF ESTADO_DO_LED ;SIM, APAGA O LED
BSF SOLTAR_BOTAO ;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO
GOTO PRINCIPAL ;DESVIA

72
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 4 Pisca LED IV

PISCAR_O_LED
BSF ESTADO_DO_LED ;FAZ O LED PISCAR
BSF SOLTAR_BOTAO ;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO
GOTO PRINCIPAL ;DESVIA

REINC_CONT_DEB
MOVLW INI_DB_BTA ;W = INI_DB_BTA
MOVWF DB_BTA ;INICIALIZA DB_BTA
MOVLW INI_DB_BTB ;W = INI_DB_BTB
MOVWF DB_BTB ;INICIALIZA DB_BTB
GOTO PRINCIPAL ;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 de-


bouncing, 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 ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
DB1_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

UNIDADE ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


DEZENA ;DEZENA DO NUMERO EXIBIDO NO DISPLAY

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 EQU .255 ;VALOR QUE DB1_BTA INICIA


INI_DB1_BTB EQU .20 ;VALOR QUE DB1_BTB INICIA
INI_DB2_BTA EQU .255 ;VALOR QUE DB2_BTA INICIA
INI_DB2_BTB EQU .20 ;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 DIGITO_1 PORTA,2 ;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


#DEFINE DIGITO_2 PORTA,3 ;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 BOTAO_1 PORTA,0 ;BOTAO 1 LIGADO EM RA0


#DEFINE BOTAO_2 PORTA,1 ;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 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

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

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 W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, SAIR DA INTERRUPO
BCF INTCON,T0IF ;SIM

A seguir, vamos verificar qual o dgito que est ativo, desativ-lo, e ativar o
outro:

BTFSS DIGITO_1 ;DIGITO 1 ESTA ATIVADO?


GOTO DESATIVA_DIGITO_2 ;NAO, DESVIA
BCF DIGITO_1 ;SIM, DESATIVA DIGITO 1
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_2 ;ATIVA DIGITO 2
GOTO COPIAR_UNIDADE ;DESVIA

DESATIVA_DIGITO_2
BCF DIGITO_2 ;DESATIVA DIGITO 2
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_1 ;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
b RB1
c RB2
d RB3
e RB4
f RB5
g 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
0 00111111
1 00000110
2 01011011
3 01001111
4 01100110
5 01101101
6 01111101
7 00000111
8 01111111
9 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 - Parte 5 Contador Crescente e Decrescente

01100110 01101101

01111101 00000111

91
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

01111111 01101111

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
1 00000001
2 00000010
3 00000011
4 00000100
5 00000101
6 00000110
7 00000111
8 00001000
9 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


0 00000000 00111111
1 00000001 00000110
2 00000010 01011011
3 00000011 01001111
4 00000100 01100110
5 00000101 01101101
6 00000110 01111101
7 00000111 00000111
8 00001000 01111111
9 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 .5 ;W = 5
ADDWF PCL,F ;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 W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, DESVIA
BCF INTCON,T0IF ;SIM, APAGA FLAG
BTFSS DIGITO_1 ;DIGITO 1 ESTA ATIVADO?
GOTO DESATIVA_DIGITO_2 ;NAO, DESVIA
BCF DIGITO_1 ;SIM, DESATIVA DIGITO 1
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_2 ;ATIVA DIGITO 2
GOTO COPIAR_UNIDADE ;DESVIA

DESATIVA_DIGITO_2
BCF DIGITO_2 ;DESATIVA DIGITO 2
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_1 ;ATIVA DIGITO 1
MOVF DEZENA,W ;W = DEZENA
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

COPIAR_UNIDADE
MOVF UNIDADE,W ;W = UNIDADE
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

CONVERTE_BINARIO_7_SEGMENTOS
ADDWF PCL,F ;PCL = PCL + W
RETLW B'00111111' ;W = 0

96
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

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

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;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 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010011' ;W = B'11010011'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16
MOVLW B'11110011' ;W = B'11110011'
MOVWF TRISA ;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
MOVLW B'10000000'
MOVWF TRISB ;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;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 FLAGS ;INICIALIZA FLAGS


MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
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
CLRF UNIDADE ;INICIALIZA UNIDADE
CLRF DEZENA ;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 ;LIMPA O WDT


CALL TRATA_BOTAO_1 ;CHAMA SUBROTINA
CALL TRATA_BOTAO_2 ;CHAMA SUBROTINA
GOTO PRINCIPAL ;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 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1?


GOTO TESTA_BOTAO_1 ;NAO, DESVIA
BTFSS BOTAO_1 ;SIM, O BOTO 1 EST SOLTO?

98
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

RETURN ;NAO, RETORNA


BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1
BTFSC BOTAO_1 ;O BOTO 1 EST PRESSIONADO?
GOTO REINC_CONT_DEB_1 ;NO, DESVIA
DECFSZ DB1_BTA,F ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB1_BTA ;SIM, W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
DECFSZ DB1_BTB,F ;DECREMENTA DB1_BTB. DB1_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB1_BTB ;SIM, W = INI_DB1_BTB
MOVWF 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 - Parte 5 Contador Crescente e Decrescente

BTFSS STATUS,Z ;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 UNIDADE ;SIM, UNIDADE = 0


INCF DEZENA,F ;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 .10 ;W = 10
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 10?
RETURN ;NAO, RETORNA
CLRF DEZENA ;SIM, DEZENA = 0
RETURN ;RETORNA

Com isso, conclumos a subrotina TRATA_BOTAO_1 que ficou assim:

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

TRATA_BOTAO_1

BTFSS SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1?


GOTO TESTA_BOTAO_1 ;NAO, DESVIA
BTFSS BOTAO_1 ;SIM, O BOTO 1 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1
BTFSC BOTAO_1 ;O BOTO 1 EST PRESSIONADO?
GOTO REINC_CONT_DEB_1 ;NO, DESVIA
DECFSZ DB1_BTA,F ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB1_BTA ;SIM, W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
DECFSZ DB1_BTB,F ;DECREMENTA DB1_BTB. DB1_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB1_BTB ;SIM, W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1

100
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

INCF UNIDADE,F ;INCREMENTA UNIDADE


MOVLW .10 ;W = 10
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 10?
RETURN ;NAO, RETORNA
CLRF UNIDADE ;SIM, UNIDADE = 0
INCF DEZENA,F ;INCREMENTA DEZENA
MOVLW .10 ;W = 10
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 10?
RETURN ;NAO, RETORNA
CLRF DEZENA ;SIM, DEZENA = 0
RETURN ;RETORNA

REINC_CONT_DEB_1
MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
RETURN ;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 SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2?


GOTO TESTA_BOTAO_2 ;NAO, DESVIA
BTFSS BOTAO_2 ;SIM, O BOTO 2 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2
BTFSC BOTAO_2 ;O BOTO 2 EST PRESSIONADO?
GOTO REINC_CONT_DEB_2 ;NO, DESVIA
DECFSZ DB2_BTA,F ;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB2_BTA ;SIM, W = INI_DB2_BTA
MOVWF DB2_BTA ;INICIALIZA DB2_BTA
DECFSZ DB2_BTB,F ;DECREMENTA DB2_BTB. DB2_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB2_BTB ;SIM, W = INI_DB2_BTB
MOVWF DB2_BTB ;INICIALIZA DB2_BTB
BSF SOLTAR_BOTAO_2 ;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 .255 ;W = 255
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF UNIDADE ;UNIDADE = 9

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


o seu valor for igual a 255:

DECF DEZENA,F ;DECREMENTA DEZENA


MOVLW .255 ;W = 255
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF DEZENA ;DEZENA = 9
RETURN ;RETORNA

Conclumos assim a subrotina TRATA_BOTAO_2:

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

TRATA_BOTAO_2

BTFSS SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2?


GOTO TESTA_BOTAO_2 ;NAO, DESVIA
BTFSS BOTAO_2 ;SIM, O BOTO 2 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2
BTFSC BOTAO_2 ;O BOTO 2 EST PRESSIONADO?
GOTO REINC_CONT_DEB_2 ;NO, DESVIA
DECFSZ DB2_BTA,F ;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB2_BTA ;SIM, W = INI_DB2_BTA
MOVWF DB2_BTA ;INICIALIZA DB2_BTA
DECFSZ DB2_BTB,F ;DECREMENTA DB2_BTB. DB2_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB2_BTB ;SIM, W = INI_DB2_BTB
MOVWF DB2_BTB ;INICIALIZA DB2_BTB
BSF SOLTAR_BOTAO_2 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
DECF UNIDADE,F ;DECREMENTA UNIDADE
MOVLW .255 ;W = 255
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 255?

102
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

RETURN ;NAO, RETORNA


MOVLW .9 ;SIM, W = 9
MOVWF UNIDADE ;UNIDADE = 9
DECF DEZENA,F ;DECREMENTA DEZENA
MOVLW .255 ;W = 255
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF DEZENA ;DEZENA = 9
RETURN ;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

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

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 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;***********************************************************************************************
; VARIVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
DB1_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

103
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

UNIDADE ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


DEZENA ;DEZENA DO NUMERO EXIBIDO NO DISPLAY

ENDC ;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
; CONSTANTES

INI_DB1_BTA EQU .255 ;VALOR QUE DB1_BTA INICIA


INI_DB1_BTB EQU .20 ;VALOR QUE DB1_BTB INICIA
INI_DB2_BTA EQU .255 ;VALOR QUE DB2_BTA INICIA
INI_DB2_BTB EQU .20 ;VALOR QUE DB2_BTB INICIA

;***********************************************************************************************
; SADAS

#DEFINE DIGITO_1 PORTA,2 ;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


#DEFINE DIGITO_2 PORTA,3 ;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

;***********************************************************************************************
; ENTRADAS

#DEFINE BOTAO_1 PORTA,0 ;BOTAO 1 LIGADO EM RA0


#DEFINE BOTAO_2 PORTA,1 ;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 W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, DESVIA
BCF INTCON,T0IF ;SIM, APAGA FLAG
BTFSS DIGITO_1 ;DIGITO 1 ESTA ATIVADO?
GOTO DESATIVA_DIGITO_2 ;NAO, DESVIA
BCF DIGITO_1 ;SIM, DESATIVA DIGITO 1
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_2 ;ATIVA DIGITO 2
GOTO COPIAR_UNIDADE ;DESVIA

DESATIVA_DIGITO_2
BCF DIGITO_2 ;DESATIVA DIGITO 2

104
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

CLRF PORTB ;TODOS OS BITS DO PORT B = 0


BSF DIGITO_1 ;ATIVA DIGITO 1
MOVF DEZENA,W ;W = DEZENA
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

COPIAR_UNIDADE
MOVF UNIDADE,W ;W = UNIDADE
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

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

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010011' ;W = B'11010011'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16
MOVLW B'11110011' ;W = B'11110011'
MOVWF TRISA ;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
MOVLW B'10000000'
MOVWF TRISB ;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

CLRF FLAGS ;INICIALIZA FLAGS


MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA

105
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

MOVLW INI_DB1_BTB ;W = INI_DB1_BTB


MOVWF DB1_BTB ;INICIALIZA DB1_BTB
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
CLRF UNIDADE ;INICIALIZA UNIDADE
CLRF DEZENA ;INICIALIZA DEZENA

;***********************************************************************************************
PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


CALL TRATA_BOTAO_1 ;CHAMA SUBROTINA
CALL TRATA_BOTAO_2 ;CHAMA SUBROTINA
GOTO PRINCIPAL ;DESVIA

;***********************************************************************************************
TRATA_BOTAO_1

BTFSS SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1?


GOTO TESTA_BOTAO_1 ;NAO, DESVIA
BTFSS BOTAO_1 ;SIM, O BOTO 1 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1
BTFSC BOTAO_1 ;O BOTO 1 EST PRESSIONADO?
GOTO REINC_CONT_DEB_1 ;NO, DESVIA
DECFSZ DB1_BTA,F ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB1_BTA ;SIM, W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
DECFSZ DB1_BTB,F ;DECREMENTA DB1_BTB. DB1_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB1_BTB ;SIM, W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
INCF UNIDADE,F ;INCREMENTA UNIDADE
MOVLW .10 ;W = 10
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 10?
RETURN ;NAO, RETORNA
CLRF UNIDADE ;SIM, UNIDADE = 0
INCF DEZENA,F ;INCREMENTA DEZENA
MOVLW .10 ;W = 10
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 10?
RETURN ;NAO, RETORNA
CLRF DEZENA ;SIM, DEZENA = 0
RETURN ;RETORNA

REINC_CONT_DEB_1
MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
RETURN ;RETORNA

106
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 5 Contador Crescente e Decrescente

;********************************************************************************************
TRATA_BOTAO_2

BTFSS SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2?


GOTO TESTA_BOTAO_2 ;NAO, DESVIA
BTFSS BOTAO_2 ;SIM, O BOTO 2 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2
BTFSC BOTAO_2 ;O BOTO 2 EST PRESSIONADO?
GOTO REINC_CONT_DEB_2 ;NO, DESVIA
DECFSZ DB2_BTA,F ;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB2_BTA ;SIM, W = INI_DB2_BTA
MOVWF DB2_BTA ;INICIALIZA DB2_BTA
DECFSZ DB2_BTB,F ;DECREMENTA DB2_BTB. DB2_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB2_BTB ;SIM, W = INI_DB2_BTB
MOVWF DB2_BTB ;INICIALIZA DB2_BTB
BSF SOLTAR_BOTAO_2 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
DECF UNIDADE,F ;DECREMENTA UNIDADE
MOVLW .255 ;W = 255
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF UNIDADE ;UNIDADE = 9
DECF DEZENA,F ;DECREMENTA DEZENA
MOVLW .255 ;W = 255
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF DEZENA ;DEZENA = 9
RETURN ;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 ;ENDERECO DA PRIMEIRA VARIVEL

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
DB1_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2
UNIDADE ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY
DEZENA ;DEZENA DO NUMERO EXIBIDO NO DISPLAY
ESC_EEPROM_A ;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
ESC_EEPROM_B ;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
LOCAL_DA_UNIDADE ;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 EQU .255 ;VALOR QUE DB1_BTA INICIA


INI_DB1_BTB EQU .8 ;VALOR QUE DB1_BTB INICIA
INI_DB2_BTA EQU .255 ;VALOR QUE DB2_BTA INICIA
INI_DB2_BTB EQU .8 ;VALOR QUE DB2_BTB INICIA
INI_ESC_EEPROM_A EQU .255 ;VALOR QUE ESC_EEPROM_A INICIA
INI_ESC_EEPROM_B EQU .2 ;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 - Parte 6 Contador II

#DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1, AGUARDA SOLTAR O BOTO 2


#DEFINE APAGAR_UNIDADE FLAGS,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

;***********************************************************************************************
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 5 0000 0101
1 0000 0001 6 0000 0110
2 0000 0010 7 0000 0111
3 0000 0011 8 0000 1000
4 0000 0100 9 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 2100 ;APONTA PARA O ENDEREO 00H DA EEPROM
DE B'01100000', .0 ;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 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW .254 ;W = 254
MOVWF EEADR ;INICIALIZA EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;INCREMENTA EEADR
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'11110000' ;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
XORLW B'01100000' ;W = W XOR 01100000
BTFSS STATUS,Z ;W = 01100000?
GOTO INICIALIZA_UNIDADE_E_DEZENA ;NAO
MOVF EEADR,W ;SIM, W = EEADR
MOVWF LOCAL_DA_UNIDADE ;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'00001111' ;W = W AND B'00001111'
MOVWF UNIDADE ;INICIALIZA UNIDADE
INCF EEADR,F ;INCREMENTA EEADR
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
MOVWF DEZENA ;INICIALIZA DEZENA
BANCO_0 ;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 ;INICIALIZA FLAGS


MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
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
MOVLW INI_ESC_EEPROM_A ;W = INI_ESC_EEPROM_A
MOVWF ESC_EEPROM_A ;INICIALIZA ESC_EEPROM_A
MOVLW INI_ESC_EEPROM_B ;W = INI_ESC_EEPROM_B
MOVWF ESC_EEPROM_B ;INICIALIZA ESC_EEPROM_B
BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA
MOVLW .254 ;W = 254
MOVWF EEADR ;INICIALIZA EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;INCREMENTA EEADR
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'11110000' ;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
XORLW B'01100000' ;W = W XOR 01100000
BTFSS STATUS,Z ;W = 01100000?
GOTO INICIALIZA_UNIDADE_E_DEZENA ;NAO
MOVF EEADR,W ;SIM, W = EEADR
MOVWF LOCAL_DA_UNIDADE ;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'00001111' ;W = W AND B'00001111'
MOVWF UNIDADE ;INICIALIZA UNIDADE
INCF EEADR,F ;INCREMENTA EEADR
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
MOVWF DEZENA ;INICIALIZA DEZENA
BANCO_0 ;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 ;LIMPA O WDT


CALL TRATA_BOTAO_1 ;CHAMA SUBROTINA
CALL TRATA_BOTAO_2 ;CHAMA SUBROTINA
CALL GRAVA_EEPROM ;CHAMA SUBROTINA
GOTO PRINCIPAL ;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 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1?


GOTO TESTA_BOTAO_1 ;NAO, DESVIA
BTFSS BOTAO_1 ;SIM, O BOTO 1 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1
BTFSC BOTAO_1 ;O BOTO 1 EST PRESSIONADO?
GOTO REINC_CONT_DEB_1 ;NO, DESVIA
DECFSZ DB1_BTA,F ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB1_BTA ;SIM, W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
DECFSZ DB1_BTB,F ;DECREMENTA DB1_BTB. DB1_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB1_BTB ;SIM, W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
INCF UNIDADE,F ;INCREMENTA UNIDADE
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
MOVLW .10 ;W = 10
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 10?
RETURN ;NAO, RETORNA
CLRF UNIDADE ;SIM, UNIDADE = 0
INCF DEZENA,F ;INCREMENTA DEZENA
MOVLW .10 ;W = 10
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 10?
RETURN ;NAO, RETORNA
CLRF DEZENA ;SIM, DEZENA = 0
RETURN ;RETORNA

123
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

REINC_CONT_DEB_1
MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
RETURN ;RETORNA

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

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


unidade ser decrementada:
;********************************************************************************************
TRATA_BOTAO_2

BTFSS SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2?


GOTO TESTA_BOTAO_2 ;NAO, DESVIA
BTFSS BOTAO_2 ;SIM, O BOTO 2 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2
BTFSC BOTAO_2 ;O BOTO 2 EST PRESSIONADO?
GOTO REINC_CONT_DEB_2 ;NO, DESVIA
DECFSZ DB2_BTA,F ;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB2_BTA ;SIM, W = INI_DB2_BTA
MOVWF DB2_BTA ;INICIALIZA DB2_BTA
DECFSZ DB2_BTB,F ;DECREMENTA DB2_BTB. DB2_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB2_BTB ;SIM, W = INI_DB2_BTB
MOVWF DB2_BTB ;INICIALIZA DB2_BTB
BSF SOLTAR_BOTAO_2 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
DECF UNIDADE,F ;DECREMENTA UNIDADE
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
MOVLW .255 ;W = 255
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF UNIDADE ;UNIDADE = 9
DECF DEZENA,F ;DECREMENTA DEZENA
MOVLW .255 ;W = 255
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF DEZENA ;DEZENA = 9
RETURN ;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 - Parte 6 Contador II

BTFSC APAGAR_UNIDADE ;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 ;SELECIONA BANCO 1 DE MEMRIA
MOVF LOCAL_DA_UNIDADE,W ;W = ENDEREO DA EEPROM ONDE EST GRAVADA A UNIDADE
MOVWF EEADR ;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 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;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 ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BANCO_0 ;SELECIONA O BANCO 0 DE MEMRIA
RETURN ;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 - Parte 6 Contador II

GRAVA_A_UNIDADE
BANCO_1 ;SELECIONA O BANCO 1 DE MEMRIA
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;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 .128 ;W = 128
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 128?
GOTO CONT_GRV_UNIDADE ;NAO, DESVIA
CLRF EEADR ;SIM, EEADR = 0

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


CONT_GRV_UNIDADE
MOVF UNIDADE,W ;W = UNIDADE
MOVWF EEDATA ;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 B'01100000' ;W = 01100000
IORWF EEDATA,F ;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 EECON1,WREN ;HABILITA ESCRITA NA EEPROM
BCF INTCON,GIE ;DESABILITA AS INTERRUPES
BTFSC INTCON,GIE ;BIT GIE EST ZERADO?
GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
MOVLW 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;EECON2 = AA HEXADECIMAL
BSF EECON1,WR ;INICIA A GRAVAO
BSF INTCON,GIE ;HABILITA INTERRUPES
A seguir, zeramos o flag GRAVAR_UNIDADE, setamos o flag
ESP_FIM_GRV_EEPROM e retornamos:

129
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

BCF GRAVAR_UNIDADE ;APAGA O FLAG


BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
RETURN ;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 ;SELECIONA O BANCO 1 DE MEMRIA
INCF EEADR,F ;INCREMENTA EEADR
A seguir, copiamos o valor da dezena apara o registrador EEDATA:
MOVF DEZENA,W ;W = DEZENA
MOVWF EEDATA ;EEDATA = DEZENA
Em seguida, escrevemos as instrues que realizam a gravao na EEPROM:
BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM
BCF INTCON,GIE ;DESABILITA AS INTERRUPES
BTFSC INTCON,GIE ;BIT GIE EST ZERADO?
GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
MOVLW 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;EECON2 = AA HEXADECIMAL
BSF EECON1,WR ;INICIA A GRAVAO
BSF INTCON,GIE ;HABILITA INTERRUPES

Aps, zeramos o flag GRAVAR_DEZENA e setamos os flags


ESP_FIM_GRV_EEPROM e CONF_GRV_EEPROM, retornando em seguida:
BCF GRAVAR_DEZENA ;APAGA O FLAG
BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BSF CONF_GRV_EEPROM ;SETA O FLAG PARA CONFERIR A GRAVAO DA EEPROM
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
RETURN ;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 ;SELECIONA O BANCO 1 DE MEMRIA
BSF EECON1,RD ;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, desviamos o programa para onde est a label
CONFERE_APAGAMENTO:
GOTO CONFERE_APAGAMENTO ;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 CONF_GRV_EEPROM ;APAGA FLAG
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

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 ;DECREMENTA EEADR
DECF EEADR,F ;DECREMENTA EEADR
DECF EEADR,F ;DECREMENTA EEADR
MOVLW .254 ;W = 254
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 254?
GOTO CONT_CONFERENCIA ;NAO, DESVIA
MOVLW .126 ;SIM, W = 126
MOVWF EEADR ;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 ;INICIA LEITURA
MOVF EEDATA,W ;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 STATUS,Z ;LOCALIDADE ANTERIOR DA UNIDADE FOI APAGADO CORRETAMENTE?
GOTO CONFERE_UNIDADE ;SIM
BCF CONF_GRV_EEPROM ;NAO, APAGA FLAG
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
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 - Parte 6 Contador II

CONFERE_UNIDADE
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;INCREMENTA EEADR
MOVLW .128 ;W = 128
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 128?
GOTO CONT_CONF_UNIDADE ;NAO, DESVIA
CLRF EEADR
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 ;INICIA LEITURA
MOVF UNIDADE,W ;W = UNIDADE
IORLW B'01100000' ;W = W OR B'01100000'
XORWF EEDATA,W ;W = W XOR EEDATA
BTFSC STATUS,Z ;VALOR DA UNIDADE FOI GRAVADO CORRETAMENTE?
GOTO GRAVACAO_CORRETA ;SIM
BCF CONF_GRV_EEPROM ;NAO, APAGA FLAG
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

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 2100 ;APONTA PARA O ENDEREO 00H DA EEPROM
DE B'01100000', .0 ;ESCREVE O NMERO BINRIO 01100000 NO ENDEREO 00H DA EEPROM
;E O NMERO DECIMAL 0 NA LOCALIDADE 01h

;**********************************************************************************************
; 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

;***********************************************************************************************
; VARIVEIS

CBLOCK 0X70 ;ENDERECO PRIMEIRA VARIVEL

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
DB1_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2

UNIDADE ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY


DEZENA ;DEZENA DO NUMERO EXIBIDO NO DISPLAY
ESC_EEPROM_A ;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
ESC_EEPROM_B ;CONTA O TEMPO DE ESPERA DO FIM DA ESCRITA NA EEPROM
LOCAL_DA_UNIDADE ;CONTEM O ENDEREO DA EEPROM ONDE EST SALVO O VALOR DA UNIDADE

ENDC ;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
; CONSTANTES

INI_DB1_BTA EQU .255 ;VALOR QUE DB1_BTA INICIA


INI_DB1_BTB EQU .8 ;VALOR QUE DB1_BTB INICIA
INI_DB2_BTA EQU .255 ;VALOR QUE DB2_BTA INICIA
INI_DB2_BTB EQU .8 ;VALOR QUE DB2_BTB INICIA
INI_ESC_EEPROM_A EQU .255 ;VALOR QUE ESC_EEPROM_A INICIA
INI_ESC_EEPROM_B EQU .2 ;VALOR QUE ESC_EEPROM_B INICIA
;***********************************************************************************************
; SADAS

#DEFINE DIGITO_1 PORTA,2 ;SE = 1, DIGITO 1 DO DISPLAY ATIVADO


#DEFINE DIGITO_2 PORTA,3 ;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

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

134
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

; ENTRADAS

#DEFINE BOTAO_1 PORTA,0 ;BOTAO 1 LIGADO EM RA0


#DEFINE BOTAO_2 PORTA,1 ;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
#DEFINE APAGAR_UNIDADE FLAGS,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 W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSS INTCON,T0IF ;TMR0 ESTOUROU?
GOTO SAI_INT ;NAO, DESVIA
BCF INTCON,T0IF ;SIM, APAGA FLAG
BTFSS DIGITO_1 ;DIGITO 1 ESTA ATIVADO?
GOTO DESATIVA_DIGITO_2 ;NAO, DESVIA
BCF DIGITO_1 ;SIM, DESATIVA DIGITO 1
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_2 ;ATIVA DIGITO 2
GOTO COPIAR_UNIDADE ;DESVIA

DESATIVA_DIGITO_2
BCF DIGITO_2 ;DESATIVA DIGITO 2
CLRF PORTB ;TODOS OS BITS DO PORT B = 0
BSF DIGITO_1 ;ATIVA DIGITO 1
MOVF DEZENA,W ;W = DEZENA
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

COPIAR_UNIDADE
MOVF UNIDADE,W ;W = UNIDADE
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA
MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO
GOTO SAI_INT ;DESVIA

135
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

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

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010011' ;W = B'11010011'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16
MOVLW B'11110011' ;W = B'11110011'
MOVWF TRISA ;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
MOVLW B'10000000'
MOVWF TRISB ;CONFIGURA O PINO RB7 COMO ENTRADA E DEMAIS COMO SAIDAS
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0

;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

CLRF FLAGS ;INICIALIZA FLAGS


MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
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
MOVLW INI_ESC_EEPROM_A ;W = INI_ESC_EEPROM_A
MOVWF ESC_EEPROM_A ;INICIALIZA ESC_EEPROM_A
MOVLW INI_ESC_EEPROM_B ;W = INI_ESC_EEPROM_B
MOVWF ESC_EEPROM_B ;INICIALIZA ESC_EEPROM_B
BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA
MOVLW .254 ;W = 254
MOVWF EEADR ;INICIALIZA EEADR
INICIALIZA_UNIDADE_E_DEZENA
INCF EEADR,F ;INCREMENTA EEADR

136
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

INCF EEADR,F ;INCREMENTA EEADR


BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'11110000' ;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
XORLW B'01100000' ;W = W XOR 01100000
BTFSS STATUS,Z ;W = 01100000?
GOTO INICIALIZA_UNIDADE_E_DEZENA ;NAO
MOVF EEADR,W ;SIM, W = EEADR
MOVWF LOCAL_DA_UNIDADE ;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
MOVF EEDATA,W ;SIM, W = VALOR DA LOCALIDADE DA EEPROM
ANDLW B'00001111' ;W = W AND B'00001111'
MOVWF UNIDADE ;INICIALIZA UNIDADE
INCF EEADR,F ;INCREMENTA EEADR
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
MOVWF DEZENA ;INICIALIZA DEZENA
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

;***********************************************************************************************
PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


CALL TRATA_BOTAO_1 ;CHAMA SUBROTINA
CALL TRATA_BOTAO_2 ;CHAMA SUBROTINA
CALL GRAVA_EEPROM ;CHAMA SUBROTINA
GOTO PRINCIPAL ;DESVIA

;***********************************************************************************************
TRATA_BOTAO_1

BTFSS SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1?


GOTO TESTA_BOTAO_1 ;NAO, DESVIA
BTFSS BOTAO_1 ;SIM, O BOTO 1 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1
BTFSC BOTAO_1 ;O BOTO 1 EST PRESSIONADO?
GOTO REINC_CONT_DEB_1 ;NO, DESVIA
DECFSZ DB1_BTA,F ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB1_BTA ;SIM, W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
DECFSZ DB1_BTB,F ;DECREMENTA DB1_BTB. DB1_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB1_BTB ;SIM, W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1
INCF UNIDADE,F ;INCREMENTA UNIDADE
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
MOVLW .10 ;W = 10
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 10?
RETURN ;NAO, RETORNA
CLRF UNIDADE ;SIM, UNIDADE = 0

137
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

INCF DEZENA,F ;INCREMENTA DEZENA


MOVLW .10 ;W = 10
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 10?
RETURN ;NAO, RETORNA
CLRF DEZENA ;SIM, DEZENA = 0
RETURN ;RETORNA

REINC_CONT_DEB_1
MOVLW INI_DB1_BTA ;W = INI_DB1_BTA
MOVWF DB1_BTA ;INICIALIZA DB1_BTA
MOVLW INI_DB1_BTB ;W = INI_DB1_BTB
MOVWF DB1_BTB ;INICIALIZA DB1_BTB
RETURN ;RETORNA

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

TRATA_BOTAO_2

BTFSS SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2?


GOTO TESTA_BOTAO_2 ;NAO, DESVIA
BTFSS BOTAO_2 ;SIM, O BOTO 2 EST SOLTO?
RETURN ;NAO, RETORNA
BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2
BTFSC BOTAO_2 ;O BOTO 2 EST PRESSIONADO?
GOTO REINC_CONT_DEB_2 ;NO, DESVIA
DECFSZ DB2_BTA,F ;SIM, DECREMENTA DB2_BTA. DB2_BTA = 0?
RETURN ;NAO,RETORNA
MOVLW INI_DB2_BTA ;SIM, W = INI_DB2_BTA
MOVWF DB2_BTA ;INICIALIZA DB2_BTA
DECFSZ DB2_BTB,F ;DECREMENTA DB2_BTB. DB2_BTB = 0?
RETURN ;NAO, RETORNA
MOVLW INI_DB2_BTB ;SIM, W = INI_DB2_BTB
MOVWF DB2_BTB ;INICIALIZA DB2_BTB
BSF SOLTAR_BOTAO_2 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 2
DECF UNIDADE,F ;DECREMENTA UNIDADE
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
MOVLW .255 ;W = 255
XORWF UNIDADE,W ;W = W XOR UNIDADE
BTFSS STATUS,Z ;UNIDADE = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF UNIDADE ;UNIDADE = 9
DECF DEZENA,F ;DECREMENTA DEZENA
MOVLW .255 ;W = 255
XORWF DEZENA,W ;W = W XOR DEZENA
BTFSS STATUS,Z ;DEZENA = 255?
RETURN ;NAO, RETORNA
MOVLW .9 ;SIM, W = 9
MOVWF DEZENA ;DEZENA = 9
RETURN ;RETORNA

138
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

EINC_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

;**********************************************************************************************
GRAVA_EEPROM

BTFSC ESP_FIM_GRV_EEPROM ;AGUARDA O FIM DA GRAVACAO NA EEPROM?


GOTO TESTA_FIM_DA_GRAVACAO ;SIM
BTFSC CONF_GRV_EEPROM ;NAO, CONFERIR A GRAVAO?
GOTO CONFERE_DEZENA ;SIM
BTFSC APAGAR_UNIDADE ;NAO, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE?
GOTO APAGA_UNIDADE_ANTERIOR ;SIM
BTFSC GRAVAR_UNIDADE ;NAO, GRAVAR UNIDADE?
GOTO GRAVA_A_UNIDADE ;SIM
BTFSC GRAVAR_DEZENA ;NAO, GRAVAR DEZENA?
GOTO GRAVA_A_DEZENA ;SIM
RETURN ;NAO

APAGA_UNIDADE_ANTERIOR
BANCO_1 ;SELECIONA BANCO 1 DE MEMRIA
MOVF LOCAL_DA_UNIDADE,W ;W = ENDEREO DA EEPROM ONDE EST GRAVADA A UNIDADE
MOVWF EEADR ;EEADR RECEBE ENDERECO
CLRF EEDATA ;EEDATA = 0
BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM
BCF INTCON,GIE ;DESABILITA AS INTERRUPES
BTFSC INTCON,GIE ;BIT GIE EST ZERADO?
GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
MOVLW 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;EECON = AA HEXADECIMAL
BSF EECON1,WR ;INICIA A GRAVAO
BSF INTCON,GIE ;HABILITA INTERRUPES
BCF APAGAR_UNIDADE ;APAGA O FLAG
BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BANCO_0 ;SELECIONA O BANCO 0 DE MEMRIA
RETURN ;RETORNA

GRAVA_A_UNIDADE
BANCO_1 ;SELECIONA O BANCO 1 DE MEMRIA
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;INCREMENTA EEADR
MOVLW .128 ;W = 128
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 128?
GOTO CONT_GRV_UNIDADE ;NAO, DESVIA
CLRF EEADR ;SIM, EEADR = 0
CONT_GRV_UNIDADE
MOVF UNIDADE,W ;W = UNIDADE
MOVWF EEDATA ;EEDATA = UNIDADE
MOVLW B'01100000' ;W = 01100000
IORWF EEDATA,F ;EEDATA = EEDATA OR 01100000
BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM
BCF INTCON,GIE ;DESABILITA AS INTERRUPES

139
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 6 Contador II

BTFSC INTCON,GIE ;BIT GIE EST ZERADO?


GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
MOVLW 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;EECON2 = AA HEXADECIMAL
BSF EECON1,WR ;INICIA A GRAVAO
BSF INTCON,GIE ;HABILITA INTERRUPES
BCF GRAVAR_UNIDADE ;APAGA O FLAG
BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
RETURN ;RETORNA

GRAVA_A_DEZENA
BANCO_1 ;SELECIONA O BANCO 1 DE MEMRIA
INCF EEADR,F ;INCREMENTA EEADR
MOVF DEZENA,W ;W = DEZENA
MOVWF EEDATA ;EEDATA = DEZENA
BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM
BCF INTCON,GIE ;DESABILITA AS INTERRUPES
BTFSC INTCON,GIE ;BIT GIE EST ZERADO?
GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA
MOVLW 0x55 ;W = NUMERO 55 HEXADECIMAL
MOVWF EECON2 ;EECON2 = 55 HEXADECIMAL
MOVLW 0xAA ;W = NUMERO AA HEXADECIMAL
MOVWF EECON2 ;EECON2 = AA HEXADECIMAL
BSF EECON1,WR ;INICIA A GRAVAO
BSF INTCON,GIE ;HABILITA INTERRUPES
BCF GRAVAR_DEZENA ;APAGA O FLAG
BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
BSF CONF_GRV_EEPROM ;SETA O FLAG PARA CONFERIR A GRAVAO DA EEPROM
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
RETURN ;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 - Parte 6 Contador II

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

CONFERE_DEZENA
BANCO_1 ;SELECIONA O BANCO 1 DE MEMRIA
BSF EECON1,RD ;INICIA LEITURA
MOVF DEZENA,W ;W = DEZENA
XORWF EEDATA,W ;W = W XOR EEDATA
BTFSC STATUS,Z ;VALOR DA DEZENA FOI GRAVADO CORRETAMENTE?
GOTO CONFERE_APAGAMENTO ;SIM
BCF CONF_GRV_EEPROM ;NAO, APAGA FLAG
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

CONFERE_APAGAMENTO
DECF EEADR,F ;DECREMENTA EEADR
DECF EEADR,F ;DECREMENTA EEADR
DECF EEADR,F ;DECREMENTA EEADR
MOVLW .254 ;W = 254
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 254?
GOTO CONT_CONFERENCIA ;NAO, DESVIA
MOVLW .126 ;SIM, W = 126
MOVWF EEADR ;EEADR = 126
CONT_CONFERENCIA
BSF EECON1,RD ;INICIA LEITURA
MOVF EEDATA,W ;W = VALOR DA LOCALIDADE DA EEPROM
BTFSC STATUS,Z ;LOCALIDADE ANTERIOR DA UNIDADE FOI APAGADO CORRETAMENTE?
GOTO CONFERE_UNIDADE ;SIM
BCF CONF_GRV_EEPROM ;NAO, APAGA FLAG
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

CONFERE_UNIDADE
INCF EEADR,F ;INCREMENTA EEADR
INCF EEADR,F ;INCREMENTA EEADR
MOVLW .128 ;W = 128
XORWF EEADR,W ;W = W XOR EEADR
BTFSS STATUS,Z ;EEADR = 128?
GOTO CONT_CONF_UNIDADE ;NAO, DESVIA
CLRF EEADR ;SIM, EEADR = 0
CONT_CONF_UNIDADE
BSF EECON1,RD ;INICIA LEITURA
MOVF UNIDADE,W ;W = UNIDADE
IORLW B'01100000' ;W = W OR B'01100000'
XORWF EEDATA,W ;W = W XOR EEDATA
BTFSC STATUS,Z ;VALOR DA UNIDADE FOI GRAVADO CORRETAMENTE?
GOTO GRAVACAO_CORRETA ;SIM
BCF CONF_GRV_EEPROM ;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 instru-
o 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, aumen-
tar 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 ter-
mina quando o sinal vai para nvel baixo.
O sinal PWM do PIC16F628A pode ter uma resoluo de at 10 bits, depen-
dendo 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. Divi-
dindo 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 milisse-
gundos.
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 registra-
dor CCP1CON. Nessa combinao, o registrador CCPR1L representa os 8 bits mais significativos:

Bit 9 Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CCP1CON CCP1CON
CCPR1L Bit 5 Bit 4

Tabela 1

Se escrevermos o valor 0, o sinal ficar o tempo todo em nvel baixo. Se es-


crevermos 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 milisse-
gundo) 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

0 0 0 1 1 0 0 1 1 0
Bit 9 Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CCP1CON CCP1CON
CCPR1L Bit 5 Bit 4

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 du-
rao 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 es-


crito 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 n-


mero 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 au-


mentar 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 se-
gundos para que o brilho atinja o mximo. Esse tambm ser o tempo que o boto 2 dever ser man-
tido pressionado para que o LED apague, partindo do brilho mximo.
Como vimos, possvel definir 1024 valores diferentes para o tempo de dura-
o 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 vari-
ao suave no brilho. Dividindo 5 segundos por 256, obtemos 0,01953125 segundo, ou seja, aproxi-
madamente 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 ci-
clos 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 ca-
da 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 mes-
mo, 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 BOTAO_1 PORTA,0 ;BOTAO 1 LIGADO EM RA0


#DEFINE BOTAO_2 PORTA,1 ;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 INTCON,T0IF ;TMR0 ESTOUROU?


RETFIE ;NAO, SAI DA INTERRUPO
BCF INTCON,T0IF ;SIM, APAGA O FLAG

A seguir, escrevemos o nmero 108 no registrador TMR0:

MOVLW .108 ;W = 108


MOVWF TMR0 ;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 pro-


grama para onde esta a label INCREMENTA_CCPR1L:

BTFSS BOTAO_1 ;BOTAO 1 EST PRESSIONADO?


GOTO INCREMENTA_CCPR1L ;SIM

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


o programa para onde est a label DECREMENTA_CCPR1L:

BTFSS BOTAO_2 ;NAO, BOTAO 2 EST PRESSIONADO?


GOTO DECREMENTA_CCPR1L ;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 ;W = 255
XORWF CCPR1L,W ;W = W XOR CCPRR1L
BTFSC STATUS,Z ;CCPR1L = 255?
RETFIE ;SIM, SAI DA INTERRUPO

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


samos da interrupo:

INCF CCPR1L,F ;NAO, INCREMENTA CCPR1L


RETFIE ;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 ;W = 0
XORWF CCPR1L,W ;W = W XOR CCPRR1L
BTFSC STATUS,Z ;CCPR1L = 0?
RETFIE ;SIM, SAI DA INTERRUPO
DECF CCPR1L,F ;NAO, DECREMENTA CCPR1L
RETFIE ;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 ;SELECIONA BANCO 1 DE MEMORIA


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

Vamos tambm configurar todos os pinos do PORTA como entradas:


MOVLW B'11111111' ;W = B'11111111'
MOVWF TRISA ;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 B'11110111' ;W = B'11110111'
MOVWF TRISB ;CONFIGURA BR3/CCP1 COMO SADA E DEMAIS COMO ENTRADA

A seguir, escrevemos o nmero 255 no registrador PR2:

MOVLW .255 ;W = 255


MOVWF PR2 ;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 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;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 B'00000110'
MOVWF 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 B'00001100' ;W = B'00001100'


MOVWF CCP1CON ;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 ;LIMPA O WDT


GOTO $-1 ;RETORNA UMA LINHA

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

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 BANCO_0 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA


#DEFINE BANCO_1 BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;***********************************************************************************************
; ENTRADAS

#DEFINE BOTAO_1 PORTA,0 ;BOTAO 1 LIGADO EM RA0


#DEFINE BOTAO_2 PORTA,1 ;BOTAO 2 LIGADO EM RA1

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

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

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES

BTFSS INTCON,T0IF ;TMR0 ESTOUROU?


RETFIE ;NAO, SAI DA INTERRUPO
BCF INTCON,T0IF ;SIM, APAGA O FLAG
MOVLW .108 ;W = 108
MOVWF TMR0 ;REINICIA TMR0
BTFSS BOTAO_1 ;BOTAO 1 EST PRESSIONADO?
GOTO INCREMENTA_CCPR1L ;SIM
BTFSS BOTAO_2 ;NAO, BOTAO 2 EST PRESSIONADO?
GOTO DECREMENTA_CCPR1L ;SIM
RETFIE ;NAO, SAI DA INTERRUPO

INCREMENTA_CCPR1L
MOVLW .255 ;W = 255
XORWF CCPR1L,W ;W = W XOR CCPRR1L
BTFSC STATUS,Z ;CCPR1L = 255?
RETFIE ;SIM, SAI DA INTERRUPO
INCF CCPR1L,F ;NAO, INCREMENTA CCPR1L
RETFIE ;SAI DA INTERRUPO

DECREMENTA_CCPR1L
MOVLW .0 ;W = 0
XORWF CCPR1L,W ;W = W XOR CCPRR1L
BTFSC STATUS,Z ;CCPR1L = 0?
RETFIE ;SIM, SAI DA INTERRUPO
DECF CCPR1L,F ;NAO, DECREMENTA CCPR1L
RETFIE ;SAI DA INTERRUPO

;************************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'11010110' ;W = B'11010110'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO COM PRESCALER DE 1:128
MOVLW B'11111111' ;W = B'11111111'
MOVWF TRISA ;CONFIGURA PORTA COMO ENTRADA
MOVLW B'11110111' ;W = B'11110111'
MOVWF TRISB ;CONFIGURA RB3/CCP1 COMO SADA E DEMAIS COMO ENTRADA
MOVLW .255 ;W = 255
MOVWF PR2 ;PR2 = 255
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0
MOVLW B'00000110'

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

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


CLRF CCPR1L ;ZERA CCPR1L
MOVLW B'00001100' ;W = B'00001100'
MOVWF CCP1CON ;HABILITA MODO PWM DO MODULO CCP

;**********************************************************************************************
; ROTINA PARA AGUARDAR A INTERRUPO

CLRWDT ;LIMPA O WDT


GOTO $-1 ;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
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Parte 8
Frequencmetro

Nesta parte do tutorial, iremos montar um frequencmetro capaz de medir


frequncias entre 1 Hz e 9.999 Hz, com resoluo de 1 Hz, exibindo o valor da frequncia num
display de LED de quatro dgitos.
Trata-se de uma montagem didtica, cujo objetivo conhecer o modo Capture
do mdulo CCP do PIC16F628A, bem como, saber como realizar operaes de subtrao com
registradores.
Como fonte do sinal, cuja frequncia ser medida, iremos utilizar um circuito
composto por um C.I. LM555N.
O esquema completo pode ser visto na figura abaixo.

Figura 1

POT1 um potencimetro linear de 100 k, onde podemos variar a frequncia


do sinal. Trocando o capacitor C2, mudamos a escala da frequncia. Valores obtidos nos testes:

10 F 1 Hz a 40 Hz
1 F 16 Hz a 460 Hz
100 nF 150 Hz a 4.100 Hz
10 nF 1.400 Hz a 9.999 Hz

167
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Utilizaremos o modo Capture do mdulo CCP do PIC16F628A para medir


a frequncia do sinal. Esse modo funciona da seguinte forma:
Quando ocorre uma mudana de nvel no pino RB3/CCP1 (que deve estar
configurado como entrada) o valor do registrador TMR1H copiado para o registrador CCPR1H e o
valor do registrador TMR1L copiado para o registrador CCPR1L. TMR1H e TMR1L so os
registradores do Timer 1. Vale relembrar o funcionamento do Timer 1:
O Timer 1 um circuito do microcontrolador que incrementa o par de
registradores TMR1L e TMR1H a partir do ciclo de instruo ou 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.
Quando o Timer 1 incrementado, esse incremento ocorre no TMR1L, cujo
valor pode chegar at 255. No prximo incremento ele estoura, isto , volta a 0, e o TMR1H
incrementado. O TMR1H, cujo valor tambm pode chegar a 255, ir estourar no incremento de n.
65.536 (256 x 256). Assim, esse par de registradores pode ser incrementado at o valor decimal de
65.535.
O Timer 1 possui um prescaler que pode ser configurado para 1:1, 1:2, 1:4 ou
1:8.
Para usar o modo Capture do mdulo CCP, o Timer 1 deve estar
configurado para ser incrementado ou a partir do ciclo de instruo ou a partir de um sinal externo
sincronizado com o oscilador principal do microcontrolador. Esse sinal externo no o sinal cuja
frequncia ser medida, mas sim, um sinal de frequncia conhecida. No nosso frequencmetro, iremos
configurar o Timer 1 para que ele seja incrementado pelo ciclo de instruo, cujo perodo de 1
microssegundo, j que a frequncia de oscilao de 4 MHz.
O Timer 1 incrementado continuamente. Quando o mdulo CCP detecta
uma mudana de nvel no pino CCP1, ele realiza a cpia dos valores dos registradores.
O mdulo CCP pode ser configurado para que a cpia ocorra todas as vezes
que houver mudana de nvel no pino CCP1, sendo que podemos escolher se a mudana a ser
detectada ser de nvel baixo para alto ou de alto para baixo. Tambm podemos configur-lo para que
essa cpia ocorra a cada 4 ou ainda a cada 16 mudanas, mas, somente de nvel baixo para alto. No
nosso projeto, iremos configur-lo para que efetue a cpia a cada mudana de nvel baixo para alto.
Conhecendo-se o intervalo de tempo entre cada incremento do Timer 1 e o
nmero de incrementos que ocorreram entre dois processos de cpia, pode-se calcular o tempo entre
as duas cpias, o que equivale ao perodo do sinal, e, a partir da, calcula-se a sua frequncia.
Para calcular o nmero de incrementos, subtrai-se os valores que o Timer 1
apresentava nas duas cpias.
Para calcular o perodo do sinal, multiplicamos o nmero de incrementos
pelo intervalo de tempo entre cada incremento, que de 0,000001 segundo (ciclo de instruo do
oscilador interno de 4 MHz). O resultado o perodo do sinal, em segundos.
Para encontrarmos a frequncia, calculamos o seu inverso:

1
Frequncia do sinal =
nmero de incrementos x 0,000001

168
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Simplificando essa frmula obtemos:

1 1 1
Frequncia do sinal = x
nmero de incrementos 0,000001

Frequncia do sinal = 1 x 1.000.000


nmero de incrementos

1.000.000
Frequncia do sinal =
nmero de incrementos

Portanto, para obtermos a frequncia do sinal, em Hz, devemos dividir o


nmero 1.000.000 (decimal) pelo nmero de incrementos do Timer 1 ocorridos entre as duas cpias
dos registradores.
Queremos que o nosso frequencmetro tenha uma resoluo de 1 Hz, isto ,
que ele seja capaz de distinguir duas frequncias cuja diferena seja de apenas 1 Hz.
O perodo de uma frequncia de 1 Hz de 1 segundo e, portanto, o Timer 1
ser incrementado 1.000.000 de vezes entre duas cpias consecutivas dos registradores. Para uma
frequncia de 2 Hz, cujo perodo de 500 milissegundos, o Timer 1 ser incrementado 500.000 vezes.
Assim, no comeo da escala, no haver problemas para distinguir frequncias separadas por 1 Hz,
pois, a diferena entre o nmero de incrementos grande.
medida que a frequncia do sinal aumenta, a diferena entre o nmero de
incrementos para duas frequncias separadas por 1 Hz diminui. Por exemplo, o perodo de uma
frequncia de 998 Hz de 1,002 milissegundo, portanto o Timer 1 ser incrementado 1.002 vezes
durante esse perodo. O perodo de uma frequncia de 999 Hz de 1,001 milissegundo e, assim, o
Timer 1 ser incrementado 1.001 vezes durante esse perodo. At aqui ainda possvel diferenciar
frequncias de 1 Hz de diferena.
A partir da o nmero de incrementos do Timer 1 passa a ser o mesmo para
duas frequncias prximas. Por exemplo, para uma frequncia de 1.195 Hz, cujo perodo de 836,8
microssegundos, o nmero de incrementos do Timer 1 de 836 e para uma frequncia de 1.196 Hz,
cujo perodo de 836,1 microssegundos, o nmero de incrementos tambm de 836. Portanto, o
frequencmetro no conseguir distinguir essas frequncias.
Uma forma de resolver esse problema efetuar o clculo da frequncia depois
de um determinado nmero de ciclos do sinal, pois o Timer 1 ter sido incrementado mais vezes,
voltando a apresentar diferena entre a quantidade de incrementos para duas frequncias prximas.
No fim da escala, onde a situao pior, a frequncia de 9.998 Hz tem um
perodo de 100,02 microssegundos, enquanto a frequncia de 9.999 Hz tem um perodo de 100,01
microssegundos.

169
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

A diferena entre os perodos das duas de 0,01 microssegundo. Isto significa


que, aps 100 ciclos do sinal, teremos uma diferena de 1 incremento do Timer 1 para essas duas
frequncias. Veja:
Durante 100 ciclos do sinal de frequncia de 9.998 Hz, o Timer 1 ser
incrementado 10.002 vezes, enquanto que durante 100 ciclos do sinal de frequncia de 9.999 Hz ele
ter sido incrementado 10.001 vezes.
Mas, no podemos esperar 100 ciclos para frequncias baixas, pois, demorar
muito tempo para o frequencmetro medi-las. Para uma frequncia de 1 Hz, por exemplo, 100 ciclos
correspondem a 100 segundos!
Vimos que at 1.000 Hz, o nmero de incrementos para duas frequncias
separadas de 1 Hz ainda era diferente. Ento, iremos aguardar 100 ciclos somente para frequncias
maiores que 1.000 Hz.
O nmero de incrementos do Timer 1 durante 1 ciclo do sinal de uma
frequncia de 1.000 Hz igual a 1.000. Portanto, no nosso programa, quando o nmero de
incrementos do Timer 1 entre a 1 e a 2 cpia dos valores dos registradores for maior do que 1.000,
indicando que a frequncia menor do que 1.000 Hz, vamos efetuar o clculo imediatamente, caso
contrrio, vamos aguardar 100 ciclos do sinal e efetuar o clculo com base no nmero de incrementos
ocorridos entre a 1 e a 101 cpias.
Nesse ltimo caso, a frmula para calcular a frequncia muda para:

100.000.000
Frequncia do sinal =
nmero de incrementos

Pois, o nmero de incrementos referente a 100 ciclos do sinal.


No nosso programa teremos trs rotinas de interrupo: a do Timer 0, a do
Timer 1 e a do mdulo CCP.
Na rotina de interrupo do Timer 0, iremos controlar os dgitos do display.
Na do Timer 1, iremos contar o nmero de estouros desse timer que ocorreram entre as cpias dos
registradores, necessrio para o clculo do nmero de incrementos. Na interrupo do mdulo CCP,
iremos calcular o nmero de incrementos.
A frequncia do sinal ser calculada na rotina principal do programa.
No MPLAB, abra o arquivo Contador.asm da parte 5 deste tutorial e salve-o
com o nome Frequencimetro.asm.
Na seo VARIAVEIS, exclua DB1_BTA, DB1_BTB, DB2_BTA e
DB2_BTB e crie as seguintes variveis: CENTENA, MILHAR, REG1A, REG2A, REG1B, REG2B,
REG3B, REG1C, REG2C, REG3C, DISP_DELAY, CAPTURA, MILHAO_1, MILHAO_2,
MILHAO_3, MILHAO_4, UNI_TEMP, DEZ_TEMP, CEN_TEMP, MIL_TEMP:

;***********************************************************************************************
; VARIVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
UNIDADE ;UNIDADE DA FREQUNCIA

170
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

DEZENA ;DEZENA DA FREQUNCIA


CENTENA ;CENTENA DA FREQUNCIA
MILHAR ;MILHAR DA FREQUNCIA
REG1A ;REGISTRADOR MENOS SIGNIFICATIVO DA 1 CAPTURA
REG2A ;REGISTRADOR MAIS SIGNIFICATIVO DA 1 CAPTURA
REG1B ;REGISTRADOR MENOS SIGNIFICATIVO DA 2 CAPTURA
REG2B ;REGISTRADOR MAIS SIGNIFICATIVO DA 2 CAPTURA
REG3B ;REGISTRADOR QUE CONTA OS ESTOUROS DO TIMER 1
REG1C ;REGISTRADOR MENOS SIGNIFICATIVO DO N DE INCREMENTOS
REG2C ;REGISTRADOR INTERMEDIRIO DO N DE INCREMENTOS
REG3C ;REGISTRADOR MAIS SIGNIFICATIVO DO N DE INCREMENTOS
DISP_DELAY ;CONTA 250 MS ENTRE EXIBIES DA FREQUNCIA
CAPTURA ;CONTA AS CAPTURAS DO MDULO CCP
MILHAO_1 ;PRIMEIRO REGISTRADOR DO NMERO 1.000.000
MILHAO_2 ;SEGUNDO REGISTRADOR DO NMERO 1.000.000
MILHAO_3 ;TERCEIRO REGISTRADOR DO NMERO 1.000.000
MILHAO_4 ;QUARTO REGISTRADOR DO NMERO 100.000.000
UNI_TEMP ;REGISTRADOR TEMPORRIO DA UNIDADE
DEZ_TEMP ;REGISTRADOR TEMPORRIO DA DEZENA
CEN_TEMP ;REGISTRADOR TEMPORRIO DA CENTENA
MIL_TEMP ;REGISTRADOR TEMPORRIO DO MLHAR

ENDC ;FIM DO BLOCO DE MEMORIA

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

Exclua a seo CONSTANTES.


Na seo SAIDAS, defina a label DIG_UNI para o RA0, que ser o dgito da
unidade, DIG_DEZ para o RA1, que ser o dgito da dezena, DIG_CEN para o RA2, que ser o
dgito da centena e DIG_MIL para o RA3, que ser o dgito do milhar, SEG_A para o RB0, SEG_B
para o RB1, SEG_C para o RB2, SEG_D para o RB4, SEG_E para o RB5, SEG_F para o RB6 e
SEG_G para o RB7 (teremos de controlar individualmente os segmentos do display, j que o pino
RB3 a entrada do sinal:

;***********************************************************************************************
; SADAS

#DEFINE DIG_UNI PORTA,0 ;SE = 1, DIGITO DA UNIDADE ATIVADO


#DEFINE DIG_DEZ PORTA,1 ;SE = 1, DIGITO DA DEZENA ATIVADO
#DEFINE DIG_CEN PORTA,2 ;SE = 1, DIGITO DA CENTENA ATIVADO
#DEFINE DIG_MIL PORTA,3 ;SE = 1, DIGITO DO MILHAR ATIVADO
#DEFINE SEG_A PORTB,0 ;SEGMENTO A DO DISPLAY
#DEFINE SEG_B PORTB,1 ;SEGMENTO B DO DISPLAY
#DEFINE SEG_C PORTB,2 ;SEGMENTO C DO DISPLAY
#DEFINE SEG_D PORTB,4 ;SEGMENTO D DO DISPLAY
#DEFINE SEG_E PORTB,5 ;SEGMENTO E DO DISPLAY
#DEFINE SEG_F PORTB,6 ;SEGMENTO F DO DISPLAY
#DEFINE SEG_G PORTB,7 ;SEGMENTO G DO DISPLAY

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

Exclua a seo ENTRADAS.


Na seo FLAGS, defina CALCULAR_FREQ para o bit 0, CEM_MILHOES
para o bit 1 e ATUALIZA_DISP para o bit 2:

171
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;***********************************************************************************************
; FLAGS

#DEFINE CALCULAR_FREQ FLAGS,0 ;SE = 1 A FREQUENCIA PODE SER CALCULADA


#DEFINE CEM_MILHOES FLAGS,1 ;SE = 100.000.000/N. DE INCREMENTOS
#DEFINE ATUALIZA_DISP FLAGS,2 ;SE = 1, ATUALIZAR VALOR DO DISPLAY

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

Na rotina de interrupo, primeiramente temos de testar qual das trs


interrupes ocorreu.
Para verificar se a interrupo foi a do Timer 0, devemos testar o bit T0IF do
registrador INTCON. Para a do Timer 1, o bit TMR1IF do registrador PIR1. Para a do mdulo CCP, o
bit CCP1IF tambm do registrador PIR1. Portanto, a rotina de interrupo comea assim:

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

ORG 0X04 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSC INTCON,T0IF ;INTERRUPO DO TIMER 0?
GOTO INT_TIMER_0 ;SIM
BTFSC PIR1,TMR1IF ;NO, INTERRUPO DO TIMER 1?
GOTO INT_TIMER_1 ;SIM
BTFSC PIR1,CCP1IF ;NO, INTERRUPO DO MDULO CCP?
GOTO INT_CCP ;SIM
GOTO SAI_INT ;NO, SAI DA INTERRUPO

O prescaler do Timer 0 ser configurado para 8:1. Assim, ele ir gerar uma
interrupo a cada 2,048 milissegundos (0,000001 x 256 x 8). No intervalo entre cada interrupo do
Timer 0, apenas um dos dgitos estar ativo. A cada interrupo, desativaremos o dgito que estiver
ativo e ativaremos o prximo. Com isso, cada dgito ficar ativado por 2,048 milissegundos e
desativado por 6,144 milissegundos, num perodo total de 8,192 milissegundos, o que corresponde a
uma frequncia de 122 Hz.
Na rotina de interrupo do Timer 0, primeiramente apagamos o flag TMR0IF:

INT_TIMER_0

BCF INTCON,T0IF ;APAGA FLAG

O frequencmetro estar constantemente medindo a frequncia do sinal. Como,


a frequncia do sinal poder variar e, para que no tenhamos o efeito desagradvel da rpida e
repetida alterao do valor mostrado no display, vamos atualiz-lo a cada cerca de 0,5 segundo.
Para isso, a cada interrupo do Timer 0, decrementamos a varivel
DISP_DELAY. Quando o seu valor chegar a 0, setamos o flag ATUALIZA_DISP:

172
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

DECFSZ DISP_DELAY,F ;DECREMENTA DISP_DELAY. DISP_DELAY = 0?


GOTO TESTA_DIG_ATIVO ;NO
BSF ATUALIZA_DISP ;SIM, SETA FLAG

A seguir, testamos qual dgito est ativado:


TESTA_DIG_ATIVO
BTFSC DIG_MIL ;DGITO DO MILHAR EST ATIVADO?
GOTO CONT_DIG_CEN ;SIM
BTFSC DIG_CEN ;NO, DGITO DA CENTENA EST ATIVADO?
GOTO CONT_DIG_DEZ ;SIM
BTFSC DIG_DEZ ;NO, DGITO DA DEZENA EST ATIVADO?
GOTO CONT_DIG_UNI ;SIM
GOTO CONT_DIG_MIL ;NAO

Se for o dgito do milhar, desativamo-lo, apagamos os segmentos, ativamos o


dgito da centena, copiamos o valor da centena para o W e desviamos o programa para a subrotina de
converso de binrio para 7 segmentos:
CONT_DIG_CEN
BCF DIG_MIL ;DESATIVA DGITO DO MILHAR
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_CEN ;ATIVA DGITO DA CENTENA
MOVF CENTENA,W ;COPIA CENTENA PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA

Repare que estamos controlando cada segmento do display individualmente,


diferentemente do que fizemos nos programas das parte 5 e 6 deste tutorial, pois, o PORTB no
exclusivo dos displays (RB3 a entrada do sinal).
Procedimento semelhante feito para os outros dgitos:

CONT_DIG_DEZ
BCF DIG_CEN ;DESATIVA DGITO DA CENTENA
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_DEZ ;ATIVA DGITO DA DEZENA
MOVF DEZENA,W ;COPIA DEZENA PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA

CONT_DIG_UNI
BCF DIG_DEZ ;DESATIVA DGITO DA DEZENA
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO

173
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BCF SEG_E ;APAGA SEGMENTO


BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_UNI ;ATIVA DGITO DA UNIDADE
MOVF UNIDADE,W ;COPIA UNIDADE PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA
CONT_DIG_MIL
BCF DIG_UNI ;DESATIVA DGITO DA UNIDADE
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_MIL ;ATIVA DGITO DA MILHAR
MOVF MILHAR,W ;COPIA MILHAR PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA

Na subrotina de converso de binrio para 7 segmentos, primeiramente


somamos ao registrador PCL o valor que est no registrador W. Em seguida, o programa ir pular um
nmero de linhas igual ao valor do W, caindo numa instruo GOTO que o direcionar para uma
sequncia de instrues que ativam os segmentos que formam o nmero a ser mostrado, saindo da
interrupo ao final:

CONV_BIN_7_SEG
ADDWF PCL,F ;PCL = PCL + W
GOTO NUM_ZERO ;W = 0
GOTO NUM_UM ;W = 1
GOTO NUM_DOIS ;W = 2
GOTO NUM_TRES ;W = 3
GOTO NUM_QUATRO ;W = 4
GOTO NUM_CINCO ;W = 5
GOTO NUM_SEIS ;W = 6
GOTO NUM_SETE ;W = 7
GOTO NUM_OITO ;W = 8
GOTO NUM_NOVE ;W = 9
NUM_ZERO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_UM
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_DOIS
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

174
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

NUM_TRES
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_QUATRO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_CINCO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_SEIS
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_SETE
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_OITO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT
NUM_NOVE
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

Assim, conclumos a rotina de interrupo do Timer 0.


O clculo da frequncia do sinal ser feito a partir do nmero de incrementos
que ocorreram no Timer 1 entre as duas capturas do mdulo CCP (entre a 1 e a 2 quando o nmero
de incrementos maior do que 1000, caso contrrio, entre a 1 e a 101 ).
Para calcularmos o nmero de incrementos, iremos subtrair os valores que o
Timer 1 apresentava nas duas capturas.

175
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Quando falamos em valor do Timer 1 estamos nos referindo ao valor formado


pelos registradores TMR1H e TMR1L. Ento, esses dois registradores de 8 bits equivalem a um de 16
bits:

TMR1H TMR1L Timer 1


+ =
11111111 11111111 1111111111111111

Para obtermos o valor decimal do Timer 1 a partir dos valores decimais dos
registradores, multiplicamos o valor do TMR1H por 256 e somamos ao valor do TMR1L.
Por exemplo, se o valor decimal do TMR1H 35 e o valor decimal do
TMR1L 23, o valor decimal do Timer 1 igual a 35 x 256 + 23 = 8983.
Para calcularmos os valores decimais dos registradores a partir do valor
decimal do Timer 1, dividimos o valor decimal do Timer 1 por 256. A parte inteira da diviso o
valor do TMR1H. A seguir, multiplicamos a parte decimal por 256 e obtemos o valor do TMR1L.
Por exemplo, se o valor decimal do Timer 1 de 8983, dividindo esse valor
por 256, obtemos 35,08984375. Portanto, TMR1H = 35. Multiplicando 0,08984375 por 256, obtemos
23, que o valor do TMR1L.
No nosso projeto, o Timer 1 ser incrementado continuamente. Quando
ocorrer uma captura, ele estar com um valor qualquer entre 0 e 65.535.
Vamos supor que na primeira captura, o valor do Timer 1 seja igual a 34.328
(TMR1H = 134 e TMR1L = 24) e que na segunda captura, o valor do Timer 1 seja igual a 43.436
(TMR1H = 169 e TMR1L = 172).
Se calcularmos a diferena entre esses dois valores, obtemos 9.108. Ento, o
Timer 1 teria sido incrementado esse nmero de vezes entre as duas capturas. Mas, tambm pode ser
que ele tenha sido incrementado 74.644 vezes. Isso porque ele pode ter estourado entre as duas
capturas. Partindo do valor 34.328, com 31.208 incrementos ele ir estourar (65.536 34.328).
Somando 31.208 com 43.436, obtemos que ele foi incrementado 74.644 vezes.
Para sabermos se o Timer 1 estourou entre as capturas, usaremos a varivel
REG3B, que iremos incrementar a cada vez que o Timer 1 estourar. Essa varivel ser como se fosse
o terceiro registrador do Timer1.
Assim, no haver dvida quanto ao nmero de incrementos que ocorreram
no Timer 1 entre as duas capturas, pois, poderemos contar at 16.777.215 incrementos, sendo que o
nmero mximo de incrementos ser de 1.000.000 quando a frequncia do sinal for de 1 Hz.
Para obtermos o valor decimal do Timer 1 a partir do valor decimal desses
trs registradores, multiplicamos o valor do REG3B por 65.536, o valor do TMR1H por 256 e
somamos os resultados ao valor do TMR1L.
No exemplo anterior, onde na 2 captura, TMR1H = 169 e TMR1L = 172, se o
REG3 for igual a 1, teremos o seguinte valor para o Timer 1: 1 x 65536 + 169 x 256 + 172 = 108.972.
Subtraindo o valor do Timer 1 na 1 captura, que era igual a 34.328, obtemos 74.644.
A rotina de interrupo do Timer 1 consiste em apagar o flag TMR1IF e
incrementar a varivel REG3B:
INT_TIMER_1

BCF PIR1,TMR1IF ;APAGA FLAG


INCF REG3B ;INCREMENTA REG3B
GOTO SAI_INT ;SAI DA INTERRUPO

176
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Na rotina de interrupo do mdulo CCP iremos os calcular o nmero de


incrementos que ocorreram no Timer 1 durante o perodo do sinal.
O processo de clculo do nmero de incrementos consistir nas seguintes
etapas:
a) Na 1 captura do mdulo CCP, copiamos o valor do registrador CCPR1L
para a varivel REG1A e o valor do registrador CCPR1H para a varivel REG2A. Lembre-se que na
captura, o mdulo CCP copia o valor do registrador TMR1H para o registrador CCPR1H e o valor do
registrador TMR1L para o registrador CCPR1L. Portanto, teremos o valor do Timer 1 na 1 captura
salvo em REG2A e REG1A.
b) Na 2 captura, copiamos o valor do registrador CCPR1L para a varivel
REG1B e o do registrador CCPR1H para a varivel REG2B.
Nesse momento, temos em REG2A e REG1A, o valor do Timer 1 no
momento da 1 captura e em REG3B, REG2B e REG1B, o valor do Timer 1 no momento da 2
captura.
No precisamos de uma varivel REG3A, porque a varivel REG3B serve
apenas para registrarmos os estouros que ocorreram no Timer 1 entre as duas capturas.
c) Efetuamos o clculo da diferena entre os valores do Timer 1 na 1 e na 2
captura para encontrar o nmero de incrementos.
d) Se o nmero de incrementos for maior do que 1.000, podemos calcular a
frequncia, caso contrrio, aguardamos a 101 captura, quando, ento, copiamos o valor do
registrador CCPR1L para a varivel REG1B e o do registrador CCPR1H para a varivel REG2B e
efetuamos o clculo do nmero de incrementos e depois poderemos calcular a frequncia.
Para indicar que a frequncia pode ser calculada, iremos setar o flag
CALCULAR_FREQ.
Comeamos por apagar o flag CCP1IF:

INT_CCP
CLRF PIR1,CCP1IF ;APAGA FLAG

Em seguida, precisamos saber se a interrupo referente 1 captura.


Incrementamos a varivel CAPTURA e testamos se o seu valor igual a 1. Se for, tratar-se- da 1
captura:

INCF CAPTURA,F ;INCREMENTA CAPTURA


MOVLW .1 ;W = 1
XORWF CAPTURA,W ;W = CAPTURA XOR 1
BTFSC STATUS,Z ;CAPTURA = 1?
GOTO PRIMEIRA_CAPTURA ;SIM

Na subrotina PRIMEIRA_CAPTURA, copiamos o valor do registrador


CCPR1L para o REG1A e o do CCPR1H para o REG2A, zeramos o REG3B e samos da interrupo:

PRIMEIRA_CAPTURA
MOVF CCPR1L,W ;W = CCPR1L
MOVWF REG1A ;REG1A = CCPR1L
MOVF CCPR1H,W ;W = CCPR1H
MOVWF REG2A ;REG2A = CCPR1H
CLRF REG3B ;REG3B = 0
GOTO SAI_INT ;SAI DA INTERRUPO

177
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Na prxima interrupo do mdulo CCP, a varivel CAPTURA ser


incrementada novamente e seu valor ser igual a 2, o que significar que a 2 captura, ento
desviamos para a subrotina CALC_INC:

MOVLW .2 ;NO, W = 2
XORWF CAPTURA,W ;W = CAPTURA XOR 2
BTFSC STATUS,Z ;CAPTURA = 2?
GOTO CALC_INC ;SIM

Na subrotina CALC_INC, copiamos o valor do registrador CCPR1L para a


varivel REG1B e o do CCPR1H para a varivel REG2B:

CALC_INC
MOVF CCPR1L,W ;W = CCPR1L
MOVWF REG1B ;REG1B = CCPR1L
MOVF CCPR1H,W ;W = CCPR1H
MOVWF REG2B ;REG2B = CCPR1H

Nesse momento, nos registradores REG2A e REG1A, temos o valor do Timer


1 na 1 captura e nos registradores REG3B, REG2B e REG1B, o seu valor na 2 captura e devemos
calcular a diferena entre esses valores.
Portanto, temos de efetuar uma operao de subtrao entre um nmero
formado por 3 registradores de 8 bits e outro formado por 2 registradores de 8 bits:

REG3B REG2B REG1B -


REG2A REG1A
=

Os passos para efetuar essa operao so semelhantes aos realizados numa


operao de subtrao no sistema decimal.
Por exemplo, para subtrair o nmero 32 do nmero 164, primeiramente
subtramos os algarismos menos significativos, ou seja, as unidades:

1 6 4 -
0 3 2
2 =

A seguir, subtramos os prximos algarismos em ordem de significncia, as


dezenas:
1 6 4 -
0 3 2
3 2 =

Por fim, subtramos as centenas:

1 6 4 -
0 3 2
1 3 2 =

178
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Com registradores, fazemos a mesma coisa; subtramos os registradores


menos significativos (REG1B REG1A), depois os prximos (REG2B REG2A) e assim por diante.
Mas, a coisa complica um pouco quando o algarismo a ser subtrado menor,
como, por exemplo, na operao 192 65:

1 9 2 -
0 6 5
=

Nesse caso, para subtrair a unidade, temos de decrementar a dezena e somar


10 unidade:

1 9 2 -
1 8 12
0 6 5
7 =

Depois, subtramos a dezena:

1 9 2 -
1 8 12
0 6 5
2 7 =

E, finalmente a centena:

1 9 2 -
1 8 12
0 6 5
1 2 7 =

Se, ao precisar decrementar a dezena, o seu valor for igual a 0, teremos de


decrementar a centena, somar 10 dezena, decrement-la, e somar 10 unidade, como por exemplo,
na operao 102 34:

1 0 2 -
0 3 4
=

179
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

1 0 2 -
0 10 2
0 3 4
=

1 0 2 -
0 10 2
0 9 12
0 3 4
8 =

1 0 2 -
0 10 2
0 9 12
0 3 4
6 8 =

1 0 2 -
0 10 2
0 9 12
0 3 4
0 6 8 =

Ao subtrair registradores, para sabermos se o nmero subtrado era maior,


verificamos se o resultado da subtrao foi negativo. Para sabermos se o registrador que foi
decrementado era igual a 0, testamos se o seu valor se tornou igual a 255.
O fluxograma a seguir mostra a sequncia de operaes que faremos.

180
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

REG1B -
REG1A

RESULTADO RESULTADO
POSITIVO NEGATIVO

REG2B - DECREMENTA
REG2A REG2B

RESULTADO RESULTADO
REG2B 255 REG2B = 255
POSITIVO NEGATIVO

OPERAO DECREMENTA REG2B - DECREMENTA


CONCLUDA REG3B REG2A REG3B

OPERAO RESULTADO RESULTADO REG2B -


CONCLUDA POSITIVO NEGATIVO REG2A

OPERAO DECREMENTA RESULTADO RESULTADO


CONCLUDA REG3B POSITIVO NEGATIVO

OPERAO OPERAO DECREMENTA


CONCLUDA CONCLUDA REG3B

OPERAO
CONCLUDA

Figura 2

181
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Comeamos subtraindo os registradores menos significativos, ou seja,


fazemos REG1B REG1A:
MOVF REG1A,W ;W = REG1A
SUBWF REG1B,F ;REG1B = REG1B - REG1A

A instruo SUBWF REG1B,F subtrai o valor de W, que igual a REG1A,


do valor de REG1B e salva o resultado no prprio REG1B.
O resultado poder ser positivo, se REG1B > REG1A ou negativo, se REG1B
< REG1A.
Para sabermos se o resultado foi positivo ou negativo, testamos o bit C do
registrador STATUS, que ser igual a 0 se o resultado for negativo.
Se o resultado for positivo, desviamos para a subrotina SEG_SUB, onde
iremos fazer REG2B REG2A. Se o resultado for negativo, decrementamos o REG2B e, em seguida,
testamos se o seu valor igual a 255:

BTFSC STATUS,C ;RESULTADO NEGATIVO?


GOTO SEG_SUB ;NO
DECF REG2B,F ;SIM, DECREMENTA REG2B
MOVLW .255 ;W = 255
XORWF REG2B,W ;W = REG2B XOR 255
BTFSS STATUS,Z ;REG2B = 255?

Se o valor de REG2B for diferente de 255, desviamos para a subrotina


SEG_SUB, caso contrrio, decrementamos REG3B e, a seguir, entramos na subrotina SEG_SUB,
onde fazemos REG2B REG2A e testamos se o resultado negativo:

GOTO SEG_SUB ;NO


DECF REG3B,F ;SIM, DECREMENTA REG3B
SEG_SUB
MOVF REG2A,W ;W = REG2A
SUBWF REG2B,F ;REG2B = REG2B - REG2A
BTFSC STATUS,C ;RESULTADO NEGATIVO?

Se o resultado for positivo, o processo de subtrao terminou, caso contrrio,


decrementamos o registrador REG3B e estar concluda a subtrao:

BTFSC STATUS,C ;RESULTADO NEGATIVO?


GOTO TST_NR_INC ;NO, OPERAO CONCLUDA
DECF REG3B,F ;SIM, DECREMENTA REG3B

Nesse momento, os registradores REG3B, REG2B e REG1B contm o valor


do resultado da subtrao, ou seja, o nmero de incrementos que o Timer 1 sofreu entre a 1 e a 2
capturas. Agora temos de verificar se este valor maior do que 1.000.
Quando o nmero de incrementos igual a 1.000, REG2B = 3 e REG1B =
232 (3 x 256 + 232 = 1000).
Portanto, se o valor de REG2B for maior do que 3 o nmero de incrementos
ser maior do que 1.000.
Se RG2B for igual a 3, REG1B ter de ser maior do que 232 para que o
nmero de incrementos seja maior do que 1.000.

182
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Primeiramente, verificamos se REG2B maior do que 3, copiando seu valor


para W e executando a instruo SUBLW .3 Essa instruo efetua a operao 3 W e salva o
resultado no W.:

TST_NR_INC
MOVF REG2B,W ;W = REG2B
SUBLW .3 ;W = 3 REG2B

A seguir, verificamos qual foi o resultado. Se REG2B for igual ou menor do


que 3, o resultado ser positivo. Nesse caso, desviamos para a subrotina TST_MENOR_3:
BTFSC STATUS,C ;REG2B MAIOR DO QUE 3?
GOTO TST_MENOR_3 ;NAO

Se REG2B for maior do que 3, o resultado ser negativo, indicando que o


nmero de incrementos maior do que 1.000, o que quer dizer que a frequncia pode ser calculada.
Para indicar isso, setamos o flag CALCULAR_FREQ. Primeiramente, zeramos a varivel
CAPTURA, para que a prxima seja novamente a 1.:
CLRF CAPTURA ;SIM, CAPTURA = 0

O clculo da frequncia, que feito na rotina principal, demora um certo


tempo. Por isso, a seguir, testamos se o flag CALCULAR_FREQ est setado, pois, se estiver, o
clculo iniciado com os valores da captura anterior ainda no foi concludo. Nesse caso, samos da
interrupo, ou seja, os valores dessa captura sero desprezados:

BTFSC CALCULAR_FREQ ;FREQUNCIA SENDO CALCULADA?


GOTO SAI_INT ;SIM, SAI DA INTERRUPO

Se o flag no estiver setado, desviamos para a subrotina COPIA_NR_INC :


GOTO COPIA_NR_INC ;NAO, DESVIA

Nessa subrotina, copiamos os valores das variveis REG1B, REG2B e


REG3B para as variveis REG1C, REG2C e REG3C, setamos o flag CALCULAR_FREQ e samos
da interrupo:
COPIA_NR_INC
MOVF REG1B,W ;W = REG1B
MOVWF REG1C ;REG1C = REG1B
MOVF REG2B,W ;W = REG2B
MOVWF REG2C ;REG2C = REG2B
MOVF REG3B,W ;W = REG3B
MOVWF REG3C ;REG3C = REG3B
BSF CALCULAR_FREQ ;SETA FLAG
GOTO SAI_INT ;SAI DA INTERRUPO

Na subrotina TST_MENOR_3, testamos se REG2B menor do que 3,


efetuando a operao 2 REG2B. Se ele for menor do que 3, o resultado ser positivo. Nesse caso, o
nmero de incrementos menor do que 1.000, e, ento, iremos aguardar a 101 captura e, por isso,
samos da interrupo:

183
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

TST_MENOR_3
MOVF REG2B,W ;W = REG2B
SUBLW .2 ;W = 2 REG2B
BTFSC STATUS,C ;REG2B MENOR DO QUE 3?
GOTO SAI_INT ;SIM

Se o resultado da operao anterior foi negativo, significa que REG2B igual


3. Nesse caso, testamos o valor do REG1B para ver se maior do que 232:

MOVF REG1B,W ;NO, W = REG1B


SUBLW .232 ;W = 232 REG1B
BTFSC STATUS,C ;REG1B MAIOR DO QUE 232?

Caso REG1B seja igual ou menor do que 232, o resultado ser positivo, o que
indica que o nmero de incrementos menor do que 1.000 e, por isso, samos da interrupo:

GOTO SAI_INT ;NAO

Se REG1B for maior do que 232, o resultado ser negativo, o que significa
que o nmero de incrementos maior do que 1.000, ento, zeramos a varivel CAPTURA, e testamos
se o flag CALCULAR_FREQ est setado:

CLRF CAPTURA ;SIM, CAPTURA = 0


BTFSC CALCULAR_FREQ ;FREQUNCIA SENDO CALCULADA?

Se estiver, samos da interrupo, caso contrrio, desviamos para a subrotina


COPIA_NR_INC:
GOTO SAI_INT ;SIM, SAI DA INTERRUPO
GOTO COPIA_NR_INC ;NAO, DESVIA

Quando o nmero de incrementos entre a 1 e a 2 captura menor do que


1.000, temos de aguardar a 101 captura. Por isso, havamos sado da interrupo. Na prxima vez
que ocorrer uma interrupo do mdulo CCP, aps passar pelos testes com os valores 1 e 2, testamos
se o seu valor igual a 101. Se no for, samos da interrupo. Quando o valor da varivel
CAPTURA for igual a 101, setamos o flag CEM_MILHOES e desviamos para a subrotina
CALC_INC:
MOVLW .101 ;NO, W = 101
XORWF CAPTURA,W ;W = CAPTURA XOR 101
BTFSS STATUS,Z ;CAPTURA = 101?
GOTO SAI_INT ;NAO, SAI DA INTERRUPO
BSF CEM_MILHOES ;SIM, SETA FLAG
GOTO CALC_INC ;DESVIA

Com isso, conclumos a rotina de interrupo do mdulo CCP.

184
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Na subrotina SAI_INT, recuperamos os registradores W e STATUS:

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

Vamos agora para a rotina principal do programa, onde iremos efetuar o


clculo da frequncia.
Nos registradores REG3C, REG2C e REG1C, temos o nmero de
incrementos. Para calcular a frequncia do sinal, devemos dividir 1.000.000 (decimal) ou
100.000.000 (decimal) por esse nmero, conforme ele seja maior ou menor do que 1.000.
No PIC16F628A, no existe uma instruo que efetue a diviso, porm, uma
diviso nada mais que uma sequncia de subtraes. Por exemplo, o resultado da diviso de 12 por
3 igual a 4. Nessa operao, 12 o dividendo, 3 o divisor e 4 o quociente.
Repare que 12 3 = 9; 9 3 = 6; 6 3 = 3; 3 3 = 0
Ou seja, partindo do nmero 12, foi possvel subtrair 4 vezes o nmero 3.
Para efetuar uma diviso, contamos quantas vezes possvel subtrair o divisor
do dividendo. Aps cada subtrao, incrementamos uma varivel. Quando no for mais possvel
subtrair, a diviso terminou e teremos, na varivel, o valor do resultado da diviso, ou seja, o
quociente.
No nosso programa, o resultado da diviso o valor da frequncia. Esse valor
dever constar nas variveis MILHAR, CENTENA, DEZENA e UNIDADE, para ser exibido no
display. Como o processo de diviso ir demorar certo tempo e para no atrapalhar a exibio dos
nmeros no display, vamos utilizar as variveis intermedirias MIL_TEMP, CEN_TEMP,
DEZ_TEMP e UNI_TEMP, que iremos incrementar a cada subtrao.
A cada subtrao iremos incrementar a varivel UNI_TEMP, que quando
atingir o valor 10, ser zerada e incrementaremos a varivel DEZ_TEMP e assim por diante. Quando
a diviso terminar, copiaremos os valores para as variveis MILHAR, CENTENA, DEZENA e
UNIDADE.
De quantas variveis vamos precisar para formar o nmero 100.000.000?
Com 1 varivel podemos ter 256 valores de 0 a 255. Com 2 variveis
podemos ter 65.536 valores (256 x 256) de 0 at 65.535. Com 3 variveis podemos ter 16.777.216
valores (256 x 256 x 256) de 0 at 16.777.215. Com 4 variveis podemos ter 4.294.967.296 valores
(256 x 256 x 256 x 256) de 0 at 4.294.967.295.
Ento, fica claro que precisamos de 4 variveis para formar o nmero
100.000.000.
Essas variveis sero: MILHAO_1, MILHAO_2 E MILHAO_3 e
MILHAO_4, sendo essa ltima a mais significativa.
Para escrevermos nessas variveis o nmero 100.000.000, fazemos
MILHAO_4 = 5, MILHAO_3 = 245, MILHAO_2 = 255 e MILHAO_1 = 0.
O processo para chegarmos a esses valores o seguinte:
Cada unidade da varivel MILHAO_1 vale 1 no valor formado pelas quatro.
Cada unidade de MILHAO_2 vale 256 (1 x 256). Cada unidade de MILHAO_3 vale 65.536. Cada
unidade de MILHAO_4 vale 16.777.216.

185
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Comeamos dividindo 100.000.000 por 16.777.216, obtendo


5,9604644775390625, cuja parte inteira (5) o valor da varivel mais significativa (MILHAO_4).
Em seguida, multiplicamos a parte decimal (0,9604644775390625) por 16.777.216, obtendo
16.113.920. A seguir, dividimos esse valor por 65.536, obtendo 245,87890625, cuja parte inteira (245)
o valor de MILHAO_3. Em seguida multiplicamos a parte decimal (0,87890625) por 65.536,
obtendo 57.600. Depois, dividimos esse valor por 256, obtendo 225, que o valor de MILHAO_2. Se
houvesse uma parte decimal, multiplic-la-amos por 256 para obtermos o valor de MILHAO_1.
O processo inverso, para achar o valor formado pelas quatro variveis mais
fcil: multiplicamos o valor de MILHAO_4_e por 16.777.216, multiplicamos o valor de MILHAO_3
por 65.536, multiplicamos o valor de MILHAO_2 por 256 e somamos os resultados ao valor de
MILHAO_1 (5 x 16.777.216 + 245 x 65.536 + 225 x 256 + 0 = 100.000.000).
O processo para escrevermos o nmero 1.000.000 o mesmo, onde
encontraremos os seguintes valores: MILHAO_4 = 0, MILHAO_3 = 15, MILHAO_2 = 66 e
MILHAO_1 = 64.
Primeiramente, limpamos o WDT com a instruo CLRWDT. A Seguir,
testamos o flag CALCULAR_FREQ para verificar se devemos iniciar o clculo. Se ele estiver zerado,
voltamos para o incio da rotina PRINCIPAL, ficando em loop:
;***********************************************************************************************
PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


BTFSS CALCULAR_FREQ ;CALCULAR A FREQUNCIA?
GOTO PRINCIPAL ;NO

Se ele estiver setado, testamos o flag CEM_MILHOES, para verificar se


iremos dividir 1.000.000 ou 100.000.000 pelo nmero de incrementos, e, conforme o caso, iniciamos
os registradores com os valores devidos. No caso de 100.000.000, apagamos o flag CEM_MILHOES:

BTFSC CEM_MILHOES ;SIM, DIVIDIR 1.000.000 OU 100.000.000?


GOTO DIV_CEM_MILHOES ;100.000.000
MOVLW .64 ;1.000.000. W = 64
MOVWF MILHAO_1 ;MILHAO_1 = 64
MOVLW .66 ;W = 66
MOVWF MILHAO_2 ;MILHAO_2 = 66
MOVLW .15 ;W = 15
MOVWF MILHAO_3 ;MILHAO_3 = 15
CLRF MILHAO_4 ;MILHAO_4 = 0
GOTO INICIA_DIVISAO
DIV_CEM_MILHOES
BCF CEM_MILHOES ;APAGA FLAG
CLRF MILHAO_1 ;MILHAO_1 = 0
MOVLW .225 ;W = 225
MOVWF MILHAO_2 ;MILHAO_2 = 225
MOVLW .245 ;W = 245
MOVWF MILHAO_3 ;MILHAO_3 = 245
MOVLW .5 ;W = 5
MOVWF MILHAO_4 ;MILHAO_3 = 4

Vamos comear a diviso, lembrando que o nmero de incrementos o valor


formado pelos registradores REG3C, REG2C e REG1C.
Primeiramente zeramos as variveis temporrias:

186
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

INICIA_DIVISAO
CLRF UNI_TEMP ;UNI_TEMP = 0
CLRF DEZ_TEMP ;DEZ_TEMP = 0
CLRF CEN_TEMP ;CEN_TEMP = 0
CLRF MIL_TEMP ;MIL_TEMP = 0

A seguir, escrevemos a label CICLO_DE_SUBTRACAO.


No comeo dessa subrotina ser executada a instruo CLRWDT, pois, o
processo de clculo da frequncia demorar mais do que o tempo que o WDT leva para estourar.
CICLO_DE_SUBTRACAO
CLRWDT ;LIMPA O WDT

Em seguida, subtramos os registradores menos significativos, ou seja,


fazemos MILHAO_1 REG1C:

MOVF REG1C,W ;W = REG1C


SUBWF MILHAO_1,F ;MILHAO_1 = MILHAO_1 - REG1C

A seguir verificamos qual foi o resultado. Se foi positivo, desviamos o


programa para onde est a label SEG_DIV_1, onde iremos subtrair os prximos registradores, ou seja,
MILHAO_2 REG2C. Se o resultado foi negativo, decrementamos MILHAO_2, e, a seguir,
testamos se o seu valor igual a 255:

BTFSC STATUS,C ;RESULTADO NEGATIVO?


GOTO SEG_DIV_1 ;NO
DECF MILHAO_2,F ;SIM, DECREMENTA MILHAO_2
MOVLW .255 ;W = 255
XORWF MILHAO_2,W ;W = MILHAO_2 XOR 255
BTFSS STATUS,Z ;MILHAO_2 = 255?

Se o valor de MILHAO_2 for diferente de 255, desviamos para SEG_DIV_1,


caso contrrio, decrementamos MILHAO_3 e verificamos se o seu valor igual a 255:

GOTO SEG_DIV_1 ;NAO


DECF MILHAO_3,F ;SIM, DECREMENTA MILHAO_3
MOVLW .255 ;W = 255
XORWF MILHAO_3,W ;W = MILHAO_3 XOR 255
BTFSS STATUS,Z ;MILHAO_3 = 255?

Se o valor de MILHAO_3 for diferente de 255, desviamos para SEG_DIV_1,


caso contrrio, decrementamos MILHAO_4 e verificamos se o seu valor igual a 255:

GOTO SEG_DIV_1 ;NAO


DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?

Se o valor de MILHAO_4 for igual a 255, a diviso terminou. Caso contrrio,


entramos na subrotina SEG_DIV_1, onde fazemos MILHAO_2 REG2C:

187
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

GOTO DIVISAO_TERMINOU ;SIM


SEG_DIV_1
MOVF REG2C,W ;W = REG2C
SUBWF MILHAO_2,F ;MILHAO_2 = MILHAO_2 - REG2C

A seguir, verificamos qual foi o resultado. Se foi positivo, desviamos para


SEG_DIV_2, onde iremos subtrair os prximos registradores, ou seja, faremos MILHAO_3
REG3C. Se o resultado foi negativo, decrementamos MILHAO_3 e, em seguida, verificamos se o seu
valor igual a 255:

BTFSC STATUS,C ;RESULTADO NEGATIVO?


GOTO SEG_DIV_2 ;NO
DECF MILHAO_3,F ;SIM, DECREMENTA MILHAO_3
MOVLW .255 ;W = 255
XORWF MILHAO_3,W ;W = MILHAO_3 XOR 255
BTFSS STATUS,Z ;MILHAO_3 = 255?

Se o valor de MILHAO_3 for diferente de 255, desviamos para SEG_DIV_2,


caso contrrio, decrementamos MILHAO_4 e verificamos se o seu valor igual a 255:
GOTO SEG_DIV_2 ;NO
DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?

Se o valor de MILHAO_4 for igual a 255, a diviso terminou. Caso contrrio,


entramos na subrotina SEG_DIV_2, onde fazemos MILHAO_3 REG3C:
GOTO DIVISAO_TERMINOU ;SIM
SEG_DIV_2
MOVF REG3C,W ;NAO, W = REG3C
SUBWF MILHAO_3,F ;MILHAO_3 = MILHAO_3 - REG3C

A seguir, verificamos se o resultado foi negativo. Se foi positivo, a subtrao


foi possvel e, ento, desviamos para INC_UNI_TEMP, onde iremos incrementar a varivel
UNI_TEMP. Se o resultado foi negativo, decrementamos MILHAO_4 e verificamos se o seu valor
igual a 255:

BTFSC STATUS,C ;RESULTADO NEGATIVO?


GOTO INC_UNI_TEMP ;NAO
DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?

Se o valor de MILHAO_4 for igual a 255, a diviso terminou, caso contrrio, foi
possvel efetuar a diviso e ento entramos na subrotina INC_UNI_TEMP:

GOTO DIVISAO_TERMINOU ;SIM


INC_UNI_TEMP

188
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Nesta subrotina, incrementamos UNI_TEMP e verificamos se o seu valor igual


a 10. Se for diferente de 10, desviamos para CICLO_DE_SUBTRACAO para efetuarmos outra
subtrao:
INCF UNI_TEMP,F ;INCREMENTA UNI_TEMP
MOVLW .10 ;W = 10
XORWF UNI_TEMP,W ;W = UNI_TEMP XOR 10
BTFSS STATUS,Z ;UNI_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO

Se o valor de UNI_TEMP for igual a 10, zeramos essa varivel e


incrementamos a varivel DEZ_TEMP. Aps increment-la, testamos se o seu valor igual a 10. Se
no for, desviamos para CICLO_DE_SUBTRACAO. Se for, zeramo-la e assim por diante at a
varivel MIL_TEMP:

CLRF UNI_TEMP ;SIM, UNI_TEMP = 0


INCF DEZ_TEMP,F ;INCREMENTA DEZ_TEMP
MOVLW .10 ;W = 10
XORWF DEZ_TEMP,W ;W = DEZ_TEMP XOR 10
BTFSS STATUS,Z ;DEZ_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF DEZ_TEMP ;SIM, DEZ_TEMP = 0
INCF CEN_TEMP,F ;INCREMENTA CEN_TEMP
MOVLW .10 ;W = 10
XORWF CEN_TEMP,W ;W = CEN_TEMP XOR 10
BTFSS STATUS,Z ;CEN_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF CEN_TEMP ;SIM, CEN_TEMP = 0
INCF MIL_TEMP,F ;INCREMENTA MIL_TEMP

Depois de incrementar a varivel MIL_TEMP, testamos se o seu valor igual


a 10. Se o valor de MIL_TEMP for diferente de 10, desviamos para CICLO_DE_SUBTRACAO. Se
for igual a 10, zeramo-la, e, em seguida, desviamos para DIVISAO_TERMINOU:

MOVLW .10 ;W = 10
XORWF MIL_TEMP,W ;W = MIL_TEMP XOR 10
BTFSS STATUS,Z ;MIL_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF MIL_TEMP ;SIM, MIL_TEMP = 0
GOTO DIVISAO_TERMINOU

Na subrotina DIVISAO_TERMINOU, primeiramente zeramos o flag


CALCULAR_FREQ:
DIVISAO_TERMINOU
BCF CALCULAR_FREQ ;APAGA FLAG

A seguir, testamos o flag ATUALIZA_DISP. Se esse flag estiver apagado,


significa que no hora de atualizar o display e, portanto, voltamos para o incio da rotina
PRINCIPAL:

189
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BTFSS ATUALIZA_DISP ;ATUALIZAR O DISPLAY?


GOTO PRINCIPAL ;NO

Se ele estiver setado, zeramo-lo, copiamos os valores das variveis


intermedirias e voltamos para o incio da rotina PRINCIPAL:
BCF ATUALIZA_DISP ;SIM, APAGA FLAG
MOVF UNI_TEMP,W ;W = UNI_TEMP
MOVWF UNIDADE ;UNIDADE = UNI_TEMP
MOVF DEZ_TEMP,W ;W = DEZ_TEMP
MOVWF DEZENA ;DEZENA = DEZ_TEMP
MOVF CEN_TEMP,W ;W = CEN_TEMP
MOVWF CENTENA ;CENTENA = CEN_TEMP
MOVF MIL_TEMP,W ;W = MIL_TEMP
MOVWF MILHAR ;MILHAR = MIL_TEMP
GOTO PRINCIPAL

Por fim, encerramos o programa:

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

Na seo CONFIGURAO DOS REGISTRADORES DE USO


ESPECFICO, vamos configurar o registrador OPTION_REG para que o prescaler do Timer 0 seja
de 8:1:

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'10000010' ;W = B'10000010'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:8

Configuramos o registrador TRISA para que os pinos RA0, RA1, RA2 e RA3
sejam sadas e os demais entradas e o TRISB para que o pino RB3 seja entrada e os demais sadas:

MOVLW B'11110000' ;W = B'11110000'


MOVWF TRISA ;CONFIGURA RA0, RA1, RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
MOVLW B'00001000'
MOVWF TRISB ;CONFIGURA O PINO RB3 COMO ENTRADA E DEMAIS COMO SAIDAS

Configuramos o registrador PIE1 para habilitamos as interrupes do Timer 1


e do mdulo CCP:

MOVLW B'00000101'
MOVWF PIE1 ;HABILITA AS INTERRUPES DO TIMER 1 E DO MDULO CCP

190
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Em seguida, liberamos os pinos RA0 a RA3 do mdulo comparador,


configurando o registrador CMCON e habilitamos a interrupo do Timer 0, no registrador INTCON:

BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA


MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'
MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0

A seguir, ligamos o Timer 1 com prescaler de 1:1 configurando o registrador


T1CON:

MOVLW B'00000001'
MOVWF T1CON ;HABILITA TIMER 1 COM PRESCALER DE 1:1

Finalmente, configuramos o registrador CCP1CON para habilitar o modo


capture do mdulo CCP para que efetue uma captura a cada mudana de nvel baixo para alto no
pino RB3:

MOVLW B'00000101'
MOVWF CCP1CON ;HABILITA MODO CAPTURE A CADA MUDANA DE BAIXO PARA ALTO

Essas configuraes constam no datasheet do PIC16F628A, nas sees que


tratam do Timer 0, Mdulo Comparador, PORTA, PORTB, Timer 1 e Mdulo CCP.
Na seo INICIALIZAO DA VARIVEIS, inicializamos as variveis
FLAGS, UNIDADE, DEZENA, CENTENA e MILHAR, REG3B com o valor 0.

;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

CLRF FLAGS ;INICIALIZA FLAGS


CLRF UNIDADE ;INICIALIZA UNIDADE
CLRF DEZENA ;INICIALIZA DEZENA
CLRF CENTENA ;INICIALIZA CENTENA
CLRF MILHAR ;INICIALIZA MILHAR
CLRF REG3B ;INICIALIZA REG3B
CLRF CAPTURA ;INICIALIZA CAPTURA

Com isso, o programa est concludo, tendo ficado assim:

;***********************************************************************************************
; PROGRAMA: FREQUENCIMETRO
; 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

191
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;**********************************************************************************************
; 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

;***********************************************************************************************
; VARIVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

W_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


STATUS_TEMP ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS
FLAGS ;REGISTRADOR DE FLAGS
UNIDADE ;UNIDADE DA FREQUNCIA
DEZENA ;DEZENA DA FREQUNCIA
CENTENA ;CENTENA DA FREQUNCIA
MILHAR ;MILHAR DA FREQUNCIA
REG1A ;REGISTRADOR MENOS SIGNIFICATIVO DA 1 CAPTURA
REG2A ;REGISTRADOR MAIS SIGNIFICATIVO DA 1 CAPTURA
REG1B ;REGISTRADOR MENOS SIGNIFICATIVO DA 2 CAPTURA
REG2B ;REGISTRADOR MAIS SIGNIFICATIVO DA 2 CAPTURA
REG3B ;REGISTRADOR QUE CONTA OS ESTOUROS DO TIMER 1
REG1C ;REGISTRADOR MENOS SIGNIFICATIVO DO N DE INCREMENTOS
REG2C ;REGISTRADOR INTERMEDIRIO DO N DE INCREMENTOS
REG3C ;REGISTRADOR MAIS SIGNIFICATIVO DO N DE INCREMENTOS
DISP_DELAY ;CONTA 250 MS ENTRE EXIBIES DA FREQUNCIA
CAPTURA ;CONTA AS CAPTURAS DO MDULO CCP
MILHAO_1 ;PRIMEIRO REGISTRADOR DO NMERO 1.000.000
MILHAO_2 ;SEGUNDO REGISTRADOR DO NMERO 1.000.000
MILHAO_3 ;TERCEIRO REGISTRADOR DO NMERO 1.000.000
MILHAO_4 ;QUARTO REGISTRADOR DO NMERO 100.000.000
UNI_TEMP ;REGISTRADOR TEMPORRIO DA UNIDADE
DEZ_TEMP ;REGISTRADOR TEMPORRIO DA DEZENA
CEN_TEMP ;REGISTRADOR TEMPORRIO DA CENTENA
MIL_TEMP ;REGISTRADOR TEMPORRIO DO MLHAR

ENDC ;FIM DO BLOCO DE MEMORIA

;***********************************************************************************************
; SADAS

#DEFINE DIG_UNI PORTA,0 ;SE = 1, DIGITO DA UNIDADE ATIVADO


#DEFINE DIG_DEZ PORTA,1 ;SE = 1, DIGITO DA DEZENA ATIVADO
#DEFINE DIG_CEN PORTA,2 ;SE = 1, DIGITO DA CENTENA ATIVADO
#DEFINE DIG_MIL PORTA,3 ;SE = 1, DIGITO DO MILHAR ATIVADO
#DEFINE SEG_A PORTB,0 ;SEGMENTO A DO DISPLAY
#DEFINE SEG_B PORTB,1 ;SEGMENTO B DO DISPLAY
#DEFINE SEG_C PORTB,2 ;SEGMENTO C DO DISPLAY
#DEFINE SEG_D PORTB,4 ;SEGMENTO D DO DISPLAY
#DEFINE SEG_E PORTB,5 ;SEGMENTO E DO DISPLAY
#DEFINE SEG_F PORTB,6 ;SEGMENTO F DO DISPLAY
#DEFINE SEG_G PORTB,7 ;SEGMENTO G DO DISPLAY

192
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;***********************************************************************************************
; FLAGS

#DEFINE CALCULAR_FREQ FLAGS,0 ;SE = 1 A FREQUENCIA PODE SER CALCULADA


#DEFINE CEM_MILHOES FLAGS,1 ;SE = 100.000.000/N. DE INCREMENTOS
#DEFINE ATUALIZA_DISP FLAGS,2 ;SE = 1, ATUALIZAR VALOR DO DISPLAY

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

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

ORG 0X04 ;VETOR DAS INTERRUPES

MOVWF W_TEMP ;SALVA W


SWAPF STATUS,W ;W = SWAP EM STATUS
BANCO_0 ;CHAVEIA PARA BANCO 0 DE MEMORIA
MOVWF STATUS_TEMP ;SALVA STATUS
BTFSC INTCON,T0IF ;INTERRUPO DO TIMER 0?
GOTO INT_TIMER_0 ;SIM
BTFSC PIR1,TMR1IF ;NO, INTERRUPO DO TIMER 1?
GOTO INT_TIMER_1 ;SIM
BTFSC PIR1,CCP1IF ;NO, INTERRUPO DO MDULO CCP?
GOTO INT_CCP ;SIM
GOTO SAI_INT

INT_TIMER_0
BCF INTCON,T0IF ;APAGA FLAG
DECFSZ DISP_DELAY,F ;DECREMENTA DISP_DELAY. DISP_DELAY = 0?
GOTO TESTA_DIG_ATIVO ;NO
BSF ATUALIZA_DISP ;SIM, SETA FLAG
TESTA_DIG_ATIVO
BTFSC DIG_MIL ;DGITO DO MILHAR EST ATIVADO?
GOTO CONT_DIG_CEN ;SIM
BTFSC DIG_CEN ;NO, DGITO DA CENTENA EST ATIVADO?
GOTO CONT_DIG_DEZ ;SIM
BTFSC DIG_DEZ ;NO, DGITO DA DEZENA EST ATIVADO?
GOTO CONT_DIG_UNI ;SIM
GOTO CONT_DIG_MIL ;NAO

CONT_DIG_CEN
BCF DIG_MIL ;DESATIVA DGITO DO MILHAR
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_CEN ;ATIVA DGITO DA CENTENA
MOVF CENTENA,W ;COPIA CENTENA PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA

193
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

CONT_DIG_DEZ
BCF DIG_CEN ;DESATIVA DGITO DA CENTENA
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_DEZ ;ATIVA DGITO DA DEZENA
MOVF DEZENA,W ;COPIA DEZENA PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA
CONT_DIG_UNI
BCF DIG_DEZ ;DESATIVA DGITO DA DEZENA
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_UNI ;ATIVA DGITO DA UNIDADE
MOVF UNIDADE,W ;COPIA UNIDADE PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA
CONT_DIG_MIL
BCF DIG_UNI ;DESATIVA DGITO DA UNIDADE
BCF SEG_A ;APAGA SEGMENTO
BCF SEG_B ;APAGA SEGMENTO
BCF SEG_C ;APAGA SEGMENTO
BCF SEG_D ;APAGA SEGMENTO
BCF SEG_E ;APAGA SEGMENTO
BCF SEG_F ;APAGA SEGMENTO
BCF SEG_G ;APAGA SEGMENTO
BSF DIG_MIL ;ATIVA DGITO DA MILHAR
MOVF MILHAR,W ;COPIA MILHAR PARA O W
GOTO CONV_BIN_7_SEG ;CHAMA SUBROTINA

CONV_BIN_7_SEG
ADDWF PCL,F ;PCL = PCL + W
GOTO NUM_ZERO ;W = 0
GOTO NUM_UM ;W = 1
GOTO NUM_DOIS ;W = 2
GOTO NUM_TRES ;W = 3
GOTO NUM_QUATRO ;W = 4
GOTO NUM_CINCO ;W = 5
GOTO NUM_SEIS ;W = 6
GOTO NUM_SETE ;W = 7
GOTO NUM_OITO ;W = 8
GOTO NUM_NOVE ;W = 9

NUM_ZERO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
GOTO SAI_INT

194
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

NUM_UM
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_DOIS
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_TRES
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_QUATRO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_CINCO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_SEIS
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_SETE
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_OITO
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_E ;ACENDE SEGMENTO

195
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BSF SEG_F ;ACENDE SEGMENTO


BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

NUM_NOVE
BSF SEG_A ;ACENDE SEGMENTO
BSF SEG_B ;ACENDE SEGMENTO
BSF SEG_C ;ACENDE SEGMENTO
BSF SEG_D ;ACENDE SEGMENTO
BSF SEG_F ;ACENDE SEGMENTO
BSF SEG_G ;ACENDE SEGMENTO
GOTO SAI_INT

INT_TIMER_1

BCF PIR1,TMR1IF ;APAGA FLAG


INCF REG3B ;INCREMENTA REG3B
GOTO SAI_INT ;SAI DA INTERRUPO

INT_CCP

CLRF PIR1,CCP1IF ;APAGA FLAG


INCF CAPTURA,F ;INCREMENTA CAPTURA
MOVLW .1 ;W = 1
XORWF CAPTURA,W ;W = CAPTURA XOR 1
BTFSC STATUS,Z ;CAPTURA = 1?
GOTO PRIMEIRA_CAPTURA ;SIM
MOVLW .2 ;NO, W = 2
XORWF CAPTURA,W ;W = CAPTURA XOR 2
BTFSC STATUS,Z ;CAPTURA = 2?
GOTO CALC_INC ;SIM
MOVLW .101 ;NO, W = 101
XORWF CAPTURA,W ;W = CAPTURA XOR 101
BTFSS STATUS,Z ;CAPTURA = 101?
GOTO SAI_INT ;NAO, SAI DA INTERRUPO
BSF CEM_MILHOES ;SIM, SETA FLAG
GOTO CALC_INC

PRIMEIRA_CAPTURA
MOVF CCPR1L,W ;W = CCPR1L
MOVWF REG1A ;REG1A = CCPR1L
MOVF CCPR1H,W ;W = CCPR1H
MOVWF REG2A ;REG2A = CCPR1H
CLRF REG3B ;REG3B = 0
GOTO SAI_INT ;SAI DA INTERRUPO

CALC_INC
MOVF CCPR1L,W ;W = CCPR1L
MOVWF REG1B ;REG1B = CCPR1L
MOVF CCPR1H,W ;W = CCPR1H
MOVWF REG2B ;REG2B = CCPR1H
MOVF REG1A,W ;W = REG1A
SUBWF REG1B,F ;REG1B = REG1B - REG1A
BTFSC STATUS,C ;RESULTADO NEGATIVO?
GOTO SEG_SUB ;NO
DECF REG2B,F ;SIM, DECREMENTA REG2B
MOVLW .255 ;W = 255
XORWF REG2B,W ;W = REG2B XOR 255

196
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BTFSS STATUS,Z ;REG2B = 255?


GOTO SEG_SUB ;NO
DECF REG3B,F ;SIM, DECREMENTA REG3B
SEG_SUB
MOVF REG2A,W ;W = REG2A
SUBWF REG2B,F ;REG2B = REG2B - REG2A
BTFSC STATUS,C ;RESULTADO NEGATIVO?
GOTO TST_NR_INC ;NO
DECF REG3B,F ;SIM, DECREMENTA REG3B

TST_NR_INC
MOVF REG2B,W ;W = REG2B
SUBLW .3 ;W = 3 REG2B
BTFSC STATUS,C ;REG2B MAIOR DO QUE 3?
GOTO TST_MENOR_3 ;NAO
CLRF CAPTURA ;SIM, CAPTURA = 0
BTFSC CALCULAR_FREQ ;FREQUNCIA SENDO CALCULADA?
GOTO SAI_INT ;SIM, SAI DA INTERRUPO
GOTO COPIA_NR_INC ;NAO, DESVIA
TST_MENOR_3
MOVF REG2B,W ;W = REG2B
SUBLW .2 ;W = 2 REG2B
BTFSC STATUS,C ;REG2B MENOR DO QUE 3?
GOTO SAI_INT ;SIM, SAI DA INTERRUPO
MOVF REG1B,W ;NO, W = REG1B
SUBLW .232 ;W = 232 REG1B
BTFSC STATUS,C ;REG1B MAIOR DO QUE 232?
GOTO SAI_INT ;NO, SAI DA INTERRUPO
CLRF CAPTURA ;SIM, CAPTURA = 0
BTFSC CALCULAR_FREQ ;FREQUNCIA SENDO CALCULADA?
GOTO SAI_INT ;SIM, SAI DA INTERRUPO
GOTO COPIA_NR_INC ;NAO, DESVIA

SAI_INT
SWAPF STATUS_TEMP,W ;SWAP EM STATUS_TEMP
MOVWF STATUS ;RECUPERA STATUS
SWAPF W_TEMP,F ;SWAP EM W_TEMP
SWAPF W_TEMP,W ;RECUPERA W
RETFIE ;RETORNA DA INTERRUPO

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA


MOVLW B'10000010' ;W = B'10000010'
MOVWF OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:8
MOVLW B'11110000' ;W = B'11110000'
MOVWF TRISA ;CONFIGURA RA0, RA1, RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
MOVLW B'00001000'
MOVWF TRISB ;CONFIGURA O PINO RB3 COMO ENTRADA E DEMAIS COMO SAIDAS
MOVLW B'00000101'
MOVWF PIE1 ;HABILITA AS INTERRUPES DO TIMER 1 E DO MDULO CCP
BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA
MOVLW B'00000111'
MOVWF CMCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O
MOVLW B'11100000'

197
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

MOVWF INTCON ;HABILITA INTERRUPO DO TIMER 0


MOVLW B'00000001'
MOVWF T1CON ;HABILITA TIMER 1 COM PRESCALER DE 1:1
MOVLW B'00000101'
MOVWF CCP1CON ;HABILITA MODO CAPTURE A CADA MUDANA DE BAIXO PARA ALTO

;***********************************************************************************************
; INICIALIZACAO DAS VARIAVEIS

CLRF FLAGS ;INICIALIZA FLAGS


CLRF UNIDADE ;INICIALIZA UNIDADE
CLRF DEZENA ;INICIALIZA DEZENA
CLRF CENTENA ;INICIALIZA CENTENA
CLRF MILHAR ;INICIALIZA MILHAR
CLRF REG3B ;INICIALIZA REG3B
CLRF CAPTURA ;INICIALIZA CAPTURA

;***********************************************************************************************
PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA

CLRWDT ;LIMPA O WDT


BTFSS CALCULAR_FREQ ;CALCULAR A FREQUNCIA?
GOTO PRINCIPAL ;NO
BTFSC CEM_MILHOES ;SIM, DIVIDIR 1.000.000 OU 100.000.000?
GOTO DIV_CEM_MILHOES ;100.000.000
MOVLW .64 ;1.000.000. W = 64
MOVWF MILHAO_1 ;MILHAO_1 = 64
MOVLW .66 ;W = 66
MOVWF MILHAO_2 ;MILHAO_2 = 66
MOVLW .15 ;W = 15
MOVWF MILHAO_3 ;MILHAO_3 = 15
CLRF MILHAO_4 ;MILHAO_4 = 0
GOTO INICIA_DIVISAO
DIV_CEM_MILHOES
BCF CEM_MILHOES ;APAGA FLAG
CLRF MILHAO_1 ;MILHAO_1 = 0
MOVLW .225 ;W = 225
MOVWF MILHAO_2 ;MILHAO_2 = 225
MOVLW .245 ;W = 245
MOVWF MILHAO_3 ;MILHAO_3 = 245
MOVLW .5 ;W = 5
MOVWF MILHAO_4 ;MILHAO_3 = 4

INICIA_DIVISAO
CLRF UNI_TEMP ;UNI_TEMP = 0
CLRF DEZ_TEMP ;DEZ_TEMP = 0
CLRF CEN_TEMP ;CEN_TEMP = 0
CLRF MIL_TEMP ;MIL_TEMP = 0

CICLO_DE_SUBTRACAO
CLRWDT ;LIMPA O WDT
MOVF REG1C,W ;W = REG1C
SUBWF MILHAO_1,F ;MILHAO_1 = MILHAO_1 - REG1C
BTFSC STATUS,C ;RESULTADO NEGATIVO?
GOTO SEG_DIV_1 ;NO
DECF MILHAO_2,F ;SIM, DECREMENTA MILHAO_2
MOVLW .255 ;W = 255
XORWF MILHAO_2,W ;W = MILHAO_2 XOR 255

198
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BTFSS STATUS,Z ;MILHAO_2 = 255?


GOTO SEG_DIV_1 ;NAO
DECF MILHAO_3,F ;SIM, DECREMENTA MILHAO_3
MOVLW .255 ;W = 255
XORWF MILHAO_3,W ;W = MILHAO_3 XOR 255
BTFSS STATUS,Z ;MILHAO_3 = 255?
GOTO SEG_DIV_1 ;NAO
DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?
GOTO DIVISAO_TERMINOU ;SIM
SEG_DIV_1
MOVF REG2C,W ;W = REG2C
SUBWF MILHAO_2,F ;MILHAO_2 = MILHAO_2 - REG2C
BTFSC STATUS,C ;RESULTADO NEGATIVO?
GOTO SEG_DIV_2 ;NO
DECF MILHAO_3,F ;SIM, DECREMENTA MILHAO_3
MOVLW .255 ;W = 255
XORWF MILHAO_3,W ;W = MILHAO_3 XOR 255
BTFSS STATUS,Z ;MILHAO_3 = 255?
GOTO SEG_DIV_2 ;NO
DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?
GOTO DIVISAO_TERMINOU ;SIM
SEG_DIV_2
MOVF REG3C,W ;NAO, W = REG3C
SUBWF MILHAO_3,F ;MILHAO_3 = MILHAO_3 - REG3C
BTFSC STATUS,C ;RESULTADO NEGATIVO?
GOTO INC_UNI_TEMP ;NAO
DECF MILHAO_4,F ;SIM, DECREMENTA MILHAO_4
MOVLW .255 ;W = 255
XORWF MILHAO_4,W ;W = MILHAO_4 XOR 255
BTFSC STATUS,Z ;MILHAO_4 = 255?
GOTO DIVISAO_TERMINOU ;SIM
INC_UNI_TEMP
INCF UNI_TEMP,F ;INCREMENTA UNI_TEMP
MOVLW .10 ;W = 10
XORWF UNI_TEMP,W ;W = UNI_TEMP XOR 10
BTFSS STATUS,Z ;UNI_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF UNI_TEMP ;SIM, UNI_TEMP = 0
INCF DEZ_TEMP,F ;INCREMENTA DEZ_TEMP
MOVLW .10 ;W = 10
XORWF DEZ_TEMP,W ;W = DEZ_TEMP XOR 10
BTFSS STATUS,Z ;DEZ_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF DEZ_TEMP ;SIM, DEZ_TEMP = 0
INCF CEN_TEMP,F ;INCREMENTA CEN_TEMP
MOVLW .10 ;W = 10
XORWF CEN_TEMP,W ;W = CEN_TEMP XOR 10
BTFSS STATUS,Z ;CEN_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF CEN_TEMP ;SIM, CEN_TEMP = 0
INCF MIL_TEMP,F ;INCREMENTA MIL_TEMP
MOVLW .10 ;W = 10

199
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

XORWF MIL_TEMP,W ;W = MIL_TEMP XOR 10


BTFSS STATUS,Z ;MIL_TEMP = 10?
GOTO CICLO_DE_SUBTRACAO ;NO
CLRF MIL_TEMP ;SIM, MIL_TEMP = 0
GOTO DIVISAO_TERMINOU

DIVISAO_TERMINOU
BCF CALCULAR_FREQ ;APAGA FLAG
BTFSS ATUALIZA_DISP ;ATUALIZAR O DISPLAY?
GOTO PRINCIPAL ;NO
BCF ATUALIZA_DISP ;SIM, APAGA FLAG
MOVF UNI_TEMP,W ;W = UNI_TEMP
MOVWF UNIDADE ;UNIDADE = UNI_TEMP
MOVF DEZ_TEMP,W ;W = DEZ_TEMP
MOVWF DEZENA ;DEZENA = DEZ_TEMP
MOVF CEN_TEMP,W ;W = CEN_TEMP
MOVWF CENTENA ;CENTENA = CEN_TEMP
MOVF MIL_TEMP,W ;W = MIL_TEMP
MOVWF MILHAR ;MILHAR = MIL_TEMP
GOTO PRINCIPAL

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

Vamos simular a execuo do programa.


Crie o projeto com o Project Wizard e monte-o.
O procedimento para a criao e montagem de um projeto foi descrito em
detalhes nas outras partes deste tutorial.
No menu View, clique em Watch e adicione os seguintes registradores de
uso especfico (SFR): PORTA, PORTB, TMR0, TMR1, CCPR1L e CCPR1H e as seguintes variveis
(SYMBOL): CAPTURA, FLAGS, REG1A, REG2A, REG1B, REG2B, REG3B, MILHAO_1,
MILHAO_2, MILHAO_3, MILHAO_4, UNI_TEMP, DEZ_TEMP, CEN_TEMP, MIL_TEMP,
UNIDADE, DEZENA, CENTENA, MILHAR.
No menu Debugger em Select Tool, selecione o MPLAB SIM.
No menu Debugger 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 ajuste para Fastest.
Clique no boto Reset da barra de ferramentas do simulador.
Primeiramente vamos acompanhar a execuo do programa at ele entrar na
rotina principal. Para isso, v clicando no boto Step Into.
Quando o programa estiver no loop da rotina principal, vamos conferir a
rotina de interrupo. Adicione um breakpoint na primeira linha da rotina de interrupo.
Clique no boto Run.
Quando o programa parar no breakpoint, v clicando no boto Step Into.
Repare que se trata da interrupo do Timer 0 e que a subrotina executada a de controle do dgito do
milhar.
Depois que o programa sair da interrupo, clique novamente no boto Run
e observe que agora a subrotina que ser executada a de controle do dgito da centena.
Depois que o programa sair da interrupo, abra a janela do Stop Watch no
menu Debugger.
Clique novamente no boto Run e observe que o tempo entre as
interrupes do Timer 0 de 2 milisegundos, como planejado.

200
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Desta vez a subrotina executada a de controle do dgito da dezena, a


prxima a da unidade e depois novamente a do milhar.
Estando a rotina de interrupo do Timer 0 aparentemente funcionando bem,
vamos simular a aplicao de um sinal no pino RB3.
No menuDebugger, em Stimulus, clique em New Workbook.
Na aba Clock Stimulus, na coluna Label, d um nome qualquer ao sinal,
por exemplo, Teste. Na coluna Pin, selecione o RB3. Na coluna Initial, selecione Low, Nas
colunas Low Cyc, High Cyc escreva 833. Configure a coluna Begin, para At Start e a coluna
End para Never. Clique em Save e d um nome qualquer, por exemplo Frequencmetro. Em
seguida, clique em Apply:

Figura 3

Com essa configurao, o pino RB3 ficar alternando de nvel a cada 833
ciclos de instruo, ou seja, a cada 833 microssegundos, o que corresponde a um sinal de frequncia
de 600 Hz. Ou seja, estamos simulando que um sinal de 600 Hz est presente no pino RB3.
Remova o breakpoint do incio da rotina de interrupo e insira um na
primeira instruo da rotina de interrupo do mdulo CCP (BCF PIR1,CCP1IF).
Clique no boto Run.
Quando a simulao parar no breakpoint, v clicando no boto Step Into.
Repare que executada a subrotina da primeira captura.
Clique no boto Run novamente.
Quando a simulao parar no breakpoint, repare que, por ser a 2 captura,
executada a subrotina CALC_INC. Depois, em TST_NR_INC, verificado que o nmero de
incrementos maior do que 1.000, e, ento, o flag para calcular a frequncia setado.

201
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Ao retornar para a rotina PRINCIPAL, como o flag CALCULAR_FREQ est


setado, o clculo da frequncia comea.
Insira um breakpoint na linha da primeira instruo da subrotina
DIVISAO_TERMINOU.
Clique no boto Run.
Quando a simulao parar no breakpoint, confira, no Watch, que
CEN_TEMP = 6, DEZ_TEMP = 0 e UNI_TEMP = 0, confirmando que a frequncia foi calculada
corretamente:

Figura 4

Para a frequncia de 600 Hz, o clculo foi feito com base no nmero de
incrementos entre a 1 e a 2 capturas.
Vamos testar com um sinal de 3.012 Hz, cujo perodo de 332
microssegundos. Sendo maior do que 1.000 Hz, o clculo ser feito com base no nmero de
incrementos entre a 1 e a 101 capturas.
No Stimulus, na aba Clock Stimulus, mude o valor das colunas Low
Cyc e High Cyc para 166, valor, em microssegundos, de meio ciclo da frequncia de 3.012 Hz e
clique em Save e em Apply.
Clique no boto Reset da barra de ferramentas do simulador.
Insira um breakpoint na linha da primeira istruo da rotina de interrupo do
mdulo CCP.
Clique no boto Run.

202
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Quando a simulao parar no breakpoint, v clicando em Step Into e repare


que executada a subrotina da 1 captura.
Clique novamente em Run.
Repare que, por ser a 2 captura executada a subrotina CALC_INC. A
seguir, na subrotina TST_NR_INC, verificado que o nmero de incrementos menor do que 1.000.
A partir de agora o programa ir esperar at que o valor da varivel
CAPTURA seja igual a 101.
Para agilizar, remova o breakpoint do comeo da rotina de interrupo do
mdulo CCP e insira um na primeira linha da subrotina CALC_INC.
Clique no boto Run.
Quando a simulao parar no breakpoint, j ser a 101 captura.
V clicando em Step Into. Quando a simulao voltar para a rotina
principal, o clculo da frequncia ir comear. Repare que desta vez, ser usado o nmero
100.000.000.
Verifique se o breakpoint da primeira linha da subrotina
DIVISAO_TERMINOU ainda est l. Se no, insira-o.
Clique no boto Run.
Quando a simulao parar no breakpoint, confira, no Watch, que o valor da
frequncia de 3012 Hz, conforme esperado:

Figura 5

203
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Se quiser, faa testes com outros valores de frequncia, lembrando de clicar


no boto Reset do simulador depois de trocar o valor no Clock Stimulus.
Agora s gravar o programa no microcontrolador e testar numa protoboard.
A figura abaixo mostra o circuito indicando uma frequncia de 136 Hz,
enquanto o multmetro indica 138 Hz:

Figura 6

Aqui termina a parte 8 do tutorial. Espero que ela tenha sido til para voc.
Na 9 parte, vamos usar o PIC16F628A para controlar um LED RGB, onde
iremos gerar 3 sinais PWM por software. At l.

204

Você também pode gostar