Sie sind auf Seite 1von 56

Introdução

Este tutorial foi feito para as pessoas que têm a eletrônica como diversão e
desejam aprender a utilizar microcontroladores em seus projetos.
Também sou um entusiasta da eletrônica 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 fórum de Eletrônica 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 frequência de aproximadamente 1 Hz.
Vamos utilizar o microcontrolador PIC16F628A, um dos modelos mais
usados hoje em dia.

Figura 1

Os microcontroladores precisam de um sinal de clock para funcionarem,


mas muitos modelos possuem a alternativa de usar um circuito oscilador interno para gerar este
sinal. Este é o caso do PIC16F628A , onde podemos escolher a frequência de 48 Khz ou a de 4
MHz.
A configuração do oscilador interno como fonte do sinal de clock e a sua
frequência são 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 tensão de alimentação
pode ser de 3V até 5,5V, sendo que com 3V, a frequência máxima do sinal de clock é de 10 MHz
enquanto que a partir de 4,5V é de 20Mhz.
Vamos utilizar um regulador de tensão LM7805 para fornecer uma tensão de
5V a partir de 9V.
Além do LM7805 e do PIC16F628A iremos utilizar um LED e um resistor
para limitar sua corrente, que serão ligados diretamente no pino do PIC, já que ele tem a capacidade
de fornecer a corrente necessária 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
saída: 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 saída, é do tipo open
drain, ou seja, a carga conectada a este pino deve estar ligada ao positivo da alimentação.
É possível 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
características do pino atendem às nossas necessidades.
No nosso circuito precisaremos de um pino que possa ser usado como saída
e, portando, temos 15 à nossa disposição. Podemos escolher qualquer um deles, por exemplo, o
RA0.
Portanto, o esquema do circuito ficou assim:

Figura 2

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


que iremos gravar no PIC.
O fluxograma é uma representação gráfica de como o programa se comporta
conforme as possíveis situações.
Com o fluxograma, fica mais fácil escrever o programa.
Eis o fluxograma do nosso programa:
Início

Configuração
dos registradores

Inicialização das
variáveis

Passou 0,5
segundo? não

sim

Acende LED LED está aceso? Apaga LED


não sim

Indica o início

Indica uma subrrotina

Indica uma decisão

Indica acesso a um dispositivo de I/O

.
Agora podemos começar a escrever o programa utilizando o software
MPLAB IDE da Microchip.
Faça o download do MPLAB IDE do site da Microchip e instale em seu
computador. A última versão disponível 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 extensão .asm. Por exemplo: Pisca LED.asm.

Figura 3

Primeiramente vamos criar um cabeçalho onde irá constar o nome do


programa, sua versão, o nome do autor e a data de conclusão, ficando assim:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************
Tudo o que for digitado na linha após ponto e vírgula será ignorado pelo
MPLAB na hora da montagem do código, portanto, todas as anotações e comentários tem que vir
precedidos de ponto e vírgula.
Repare no ponto e vírgula no início de cada linha que faz com que o
MPLAB ignore o que está escrito após.
Em seguida vamos incluir no nosso programa o arquivo padrão de
definições do PIC16F628A, usando a diretiva #INCLUDE:
;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************
#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A
;***********************************************************************************************

Repare que antes de #INCLUDE <P16F628A.INC> não há ponto e vírgula


e portanto o MPLAB irá executar este comando.
Observe que foi deixado um espaço a partir da margem esquerda. Isto
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 comentário “ARQUIVO PADRAO
MICROCHIP PARA O PIC16F628A” há ponto e vírgula, pois, não queremos que o MPLAB leve
em consideração o que está escrito, pois trata-se de um comentário (não faz parte do programa).
Repare que após digitar #INCLUDE a cor da letra ficou azul, O MPLAB faz
isto sempre que reconhece o termo como uma diretiva. Isto ajuda a perceber quando escrevemos a
diretiva de forma errada, pois, aí ela não ficará azul.
No arquivo P16F628A.INC é onde constam, além do modelo do
microcontrolador, as correspondências entre os nomes dos registradores e as respectivas posições
que eles ocupam na memória de dados, bem como, entre os nomes de cada bit e sua posição no
registrador, entre outras informações, como tamanho e endereços válidos da memória e bits de
configuração.
O que ocorre é que, para facilitar a vida do programador, as localidades da
memória de dados, ou seja, os registradores, recebem nomes.
Quando o MPLAB vai traduzir o programa para a linguagem de máquina ele
usa estas correspondências.
Se você quiser ver o arquivo P16F628A.INC, localize-o na pasta MPASM
Suite que é uma subpasta da pasta Microchip, criada no diretório onde foi instalado o MPLAB IDE.

O próximo passo é ajustar os Bits de Configuração, também conhecidos por


“fusíveis” ou “fuses”. Isto é feito com a diretiva __CONFIG.

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************
#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A
;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF &


_BOREN_OFF & _LVP_OFF & _CP_OFF & DATA_CP_OFF

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

São 2 (dois) “underlines” antes do CONFIG, seguido de espaço e em


seguida das expressões antecedidas de 1 “underline” separadas pelo símbolo “&” entre espaços.
Nos Bits de Configuração selecionamos o tipo de oscilador que será usado e
se os seguintes recursos serão ativados: WDT (Watch Dog Timer), PWRTE (Power-up Timer),
MCLRE (Master Clear Enable), BOREN (Brown-out Reset), LVP (Low Voltage Program),
DATA_CP (proteção da memória de dados), CP (proteção da memória de programa).
As opções para seleção do oscilador são:

_LP_OSC : Cristal de frequência até cerca de 1MHz ligado entre os pinos


OSI e OSO.
_XT_OSC : Cristal de frequência de cerca de 1MHz a 4 MHz ligado entre
os pinos OSI e OSO.
_HS_OSC : Cristal de frequência 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, porém com saída do


sinal de clock no pino CLKOUT (¼ da frequência) para fins de sincronização 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, porém com saída do sinal
de clock no pino CLKOUT (¼ da frequência) para fins de sincronização de hardware externo.

No nosso caso, escolhemos a opção _INTOSC_OSC_NOCLKOUT, ou seja,


oscilador interno sem saída do sinal.
O WDT (Watch Dog Timer) é um recurso que reinicia o microcontrolador,
se acaso o programa travar.
Vamos habilitar este recuso e por isso escrevemos _WDT_ON.
Se não quiséssemos ativar o recurso escreveríamos _WDT_OFF.
O PWRTE (Power-up Timer) é um circuito que mantém o microcontrolador
em reset por 72 ms após a alimentação ser ligada para que dê tempo do oscilador estabilizar.
Vamos habilitar também este recurso e por isso escrevemos _PWRTE_ON.
O MCLRE (Master Clear Enable) se estiver ativado, reserva o pino MCLR
para a função de reset do microcontrolador.
Este recurso não nos interessa e por isto o deixamos desligado, escrevendo
_MCLRE_OFF.
O BOREN (Brown-out reset) é um recurso que monitora a tensão de
alimentação e quando ela cai abaixo de 4,5V, provoca o reset.
Este recuso também não nos interessa e por isto escrevemos
_BOREN_OFF.
O LVP (Low Voltage Program) é um recurso que permite que o
microcontrolador seja gravado sem a necessidade de aplicar uma tensão de cerca de 13V no pino
VPP (veremos sobre gravação do PIC no momento oportuno).
Esta função não nos interessa e por isto escrevemos _LVP_OFF.
DATA_CP é um recurso para proteger a memória de dados contra cópia.
CP é um recurso para proteger a memória de programa contra cópias.
Estes recursos interessam a quem fabrica aparelhos eletrônicos e quer evitar
engenharia reversa.
Estes recursos não nos interessam, e por isto escrevemos _CP_OFF &
DATA_CP_OFF.
O próximo passo é definir “labels” para a comutação dos bancos de
memória de dados.
Fazemos isto utilizando a diretiva #DEFINE desta forma:
;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

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

A memória 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 o valor dos bits RP0 e RP1do registrador STATUS, para selecionarmos 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, não necessitaremos de acessar os
bancos 3 e 4, pois, os Registradores de Uso Específico que neles se encontram também estão nos
bancos 0 ou 1 e nós não iremos precisar das posições destinadas a Registradores de Uso Geral que
lá se encontram, pois, nos bastará os disponíveis 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 instrução BCF STATUS,RP0.
BANCO_0 é o que chamamos de “label” e poderia ser outra palavra de sua
preferência.
A instrução 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.
Nós também usamos a diretiva #DEFINE para que onde houver a palavra
BANCO_1 o microcontrolador execute a instrução BSF STATUS,RP0.
A instrução BSF serve para fazer o valor de um determinado bit igual a 1.
Desta forma, fica mais fácil de fazer a comutação entre os bancos de
memória, pois, basta escrever a palavra BANCO_0, para que o banco 0 da memória de dados seja
selecionado e a palavra BANCO_1, para o banco 1.
Repare que após digitar BCF e BSF, a cor da letra ficou azul e em negrito. O
MPLAB faz isto com qualquer termo reconhecido como uma instrução. Isto nos ajuda a perceber se
escrevermos uma instrução de forma errada.
Figura 4

O próximo passo é definir as variáveis que iremos utilizar em nosso


programa.
Uma variável é um Registrador de Uso Geral, ou seja, é uma das posições da
memória 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
variáveis. Por este motivo, minha forma preferida para defini-las é com o uso da diretiva CBLOCK:
;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************;
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 expressão 0X20 após a diretiva CBLOCK indica o endereço na memória


de dados que assumirá a primeira variável definida (DELAY_0).
Este endereço 0X20, está em formato hexadecimal. Veja, na figura 4, que
este endereço (lá representado por 20h) é o primeiro, no banco 0, que podemos usar como
Registrador de Uso Geral.
Repare que ele termina no endereço 7F, totalizando 96 localidades de
memória neste banco.
Os que forem criados do endereço 70 até o 7F serão espelhados nos outros
bancos, permitindo que possam ser acessados sem necessidade de selecionar o banco.
No banco 1 temos outras 80 posições e no banco 2 mais 48.
Portanto, no PIC16F628A temos um total de 224 posições de memória
(registradores) que podemos usar para armazenar valores. Ou seja, podemos criar até 224 variáveis.
Voltando a falar da diretiva CBLOCK, após relacionar os nomes das nossas
variáveis, encerramos a diretiva com ENDC.
Desta forma, definimos o endereço 0X20 para DELAY_0, 0X21 para
DELAY_1 e 0X22 para DELAY_2.
Se, posteriormente quisermos adicionar outras variáveis, podemos, inclusive
intercalar no meio, sem problemas.
Há outras formas de definir variáveis, através das diretivas #DEFINE e
EQU, mas, creio que a mais prática seja através da diretiva CBLOCK.

O próximo passo é definir as constantes.


Constantes são valores numéricos que utilizaremos durante o programa.
Por exemplo, uma determinada variável pode precisar ser reiniciada sempre
com o mesmo valor. Este valor é uma constante.
No nosso programa, as variáveis DELAY_0, DELAY_1 c DELAY_2 serão
reiniciadas cada qual com valores que serão sempre os mesmos.
Estes valores serão definidos depois que fizermos a rotina principal do
programa, por isso, os valores que vamos escrever agora serão alterados depois.
Para definir as constantes, usamos a diretiva EQU:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************;
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
;
************************************************************************************************
Com isto, no momento em que o MPLAB for montar o programa, onde estiver
escrito INI_DELAY_0, ele irá substituir esta expressão pelo valor 255 (decimal); INI_DELAY_1
por 50 e INI_DELAY_2 por 13.
A vantagem de fazer isto é que se por acaso constatarmos que os valores para
aquelas variáveis não estavam satisfatórios, basta alterá-los ali, não precisando alterar em todas as
linhas do programa onde forem feitas reinicializações das variáveis.
À propósito, vamos falar de como representar, no nosso programa, os valores
numéricos, usando o número 10 como exemplo.
Quando estivermos nos referindo ao número 10 do sistema decimal, escreveremos
assim: D'10' ou ainda .10
Se for o numero 10 do sistema binário (2 do sistema decimal), escreveremos
assim: B'10'
Se for o número 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.

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************;
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
;
************************************************************************************************
; SAÍDA

#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, no programa, aparecer a palavra LED, o MPLAB saberá que
se trata do bit 0 do registrador PORTA.
Os registradores associados aos pinos de I/O são o PORTA e o PORTB.
O próprio nome do pino já nos diz qual é o registrador e qual é 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
Quando um pino estiver configurado como entrada (veremos mais a frente
como se faz a configuração dos pinos como entradas ou saídas) o nível lógico presente nele poderá
ser verificado fazendo-se a leitura do valor do bit correspondente. Se o valor do bit é igual a 1,
então o nível lógico no pino é alto e vice-versa.
Por exemplo, suponhamos que o pino RB2 esteja configurado como entrada.
Para sabermos qual é o seu nível lógico, fazemos a leitura do bit 2 do
registrador PORTB (veremos no momento oportuno como verificar o nível lógico de um bit).
Para o pino RA6, lemos o bit 6 do PORTA e assim por diante.
Se o pino estiver configurado como saída e quisermos levar o nível de saída
deste pino para alto, fazemos o seu bit correspondente igual a 1. Para levar o pino para nível baixo,
fazemos o valor do bit correspondente igual a 0, ou seja, controlando o valor do bit controlamos o
pino.
O próximo passo é o vetor de reset.

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************
;**********************************************************************************************
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
;
************************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

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

Após a inicialização e depois de um reset, o microcontrolador executa a


instrução que estiver no endereço 0X00 da memória de programa.
Em seguida ele irá executar a instrução presente no endereço 0X01, depois
0X02 e assim por diante.
A diretiva ORG, indica em qual endereço da memória de programa deverá
ser escrita a instrução seguinte. No nosso programa, a instrução GOTO INICIO ocupará o endereço
0X00 da memória de programa, ou seja, será a primeira instrução executada pelo microcontrolador.
O microcontrolador, ao executar esta instrução desvia para o endereço da
memória de programa ocupado pela instrução que estiver após a label INICIO.
Mas, porque fazer este desvio?
Os microcontroladores possuem um recurso muito útil chamado Interrupção,
que é a interrupção da execução do programa devido a um evento provocado por um periférico do
microcontrolador configurado para isto. Periféricos são os circuitos presentes no microcontrolador
que fazem funções específicas, como contadores, gerador de sinal PWM, comparadores, etc...
Quando uma interrupção ocorre, o microcontrolador executa a instrução
presente no endereço 0X04 da memória de programa (no caso do PIC16F628A).
Este é o motivo de fazermos um desvio logo no endereço 0X00. Este desvio
será para depois do fim da rotina de interrupção.
Como neste programa não iremos utilizar o recurso da interrupção, iremos
escrever no nosso programa a instrução RETFIE no endereço 0X04 para que se, por acaso, ocorrer
uma interrupção indesejada, o programa possa retornar para o ponto de onde foi desviado.
Em outra parte deste tutorial falaremos detalhadamente sobre interrupções.
O próximo passo é configurar os Registradores de Uso Específico.

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************;
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
;
************************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

;***********************************************************************************************
;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA

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


MOVWF TRISA ;CONFIGURA RA0 COMO SAÍDA 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, ou seja, aqui começa o programa.
Nesta parte do programa devemos configurar todos os Registradores de Uso
Específico que estejam envolvidos com os recursos do microcontrolador que iremos utilizar.
Por exemplo, se formos utilizar o TIMER 0, teremos que configurar o
registrador relacionado a ele. Se formos utilizar o módulo 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 responsável por definir cada pino do PORTA como
entrada ou saída.
Aqui também há uma relação 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 atribuído o valor 0 para o bit, o pino é configurado como saída e se
for atribuído o valor 1, o pino é configurado como entrada. Memorize esta regra.
Veja a figura 4. Observe que o registrador TRISA está no banco 1.
Para termos acesso a este registrador precisamos selecionar o banco 1
escrevendo BANCO_1 (label que definimos para isto).
Os demais pinos não serão utilizados e não precisamos configurá-los, mas
aqui vai uma dica:
Configure como entrada os pinos que não estiverem sendo utilizados, pois,
se estiverem configurados como saída 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 impedância e não tem problema se forem ligados diretamente no VDD e
VSS.
O pino RA0 será configurado como saída e os demais pinos do PORTA
como entrada, então, precisamos escrever o número binário 11111110 no registrador TRISA (os bits
em um registrador estão na seguinte ordem: bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0).
Não existe uma instrução para escrever diretamente um número num
registrador do PIC16F628A.
No microcontrolador existe um registrador chamado de W (work).
Quando queremos escrever um número num registrador, primeiramente
devemos escrever este número no registrador W.
Fazemos isto com a instrução MOVLW, desta forma:
MOVLW B'11111110'
Com isto, escreve-se no registrador W o número binário 11111110.
O nome das instruções foram criados de forma a lembrar a sua função.
No caso da instrução MOVLW, MOV vem de mover. L vem de literal. A
instrução MOVLW, move um número para o registrador W. Reparou na correspondência? (move L
para W).
Com o número já escrito no registrador W, podemos escrever este número
no registrador TRISA, usando a instrução MOVWF, assim:
MOVWF TRISA
A instrução MOVWF move o que estiver no registrador W para o
registrador escrito após a instrução, no caso o TRISA.
Melhor dizendo, o conteúdo do registrador W é copiado para o TRISA, pois,
depois de executada a instrução, o registrador W continua com o mesmo valor que estava antes.
Pronto, configuramos o pino RA0 para funcionar como saída 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 e saída:
MOVLW B'11111111'
MOVWF TRISB

Nos PIC16F628A, bem como noutros modelos de microcontroladores, a


maioria dos pinos são compartilhados por mais de um recurso do microcontrolador.
É o caso do pino RA0 que estamos utilizando.
Além dele ser um pino que podemos usar como entrada ou saída de sinal,
também é um dos pinos de entrada do módulo comparador.
O módulo comparador é um circuito do PIC16F628A que funciona como
um CI comparador de tensão.
Na inicialização do PIC16F628A, os pinos RA0, RA1, RA2 e RA3, estão
vinculados ao módulo comparador de tensão e, por isto, para que possamos utilizar algum destes
pinos como pino de entrada ou saída de sinal, precisamos configurar o registrador CMCON.
O registrador CMCON, está no banco 0 de memória, conforme você pode
ver na figura 4 e, então, 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 ficarão disponíveis
para serem usados como entrada ou saída e se os valores destes mesmos bits forem 1, 1 e 1, os pinos
RA0, RA1, RA2 e RA3 ficaram disponíveis.
No nosso caso qualquer das duas alternativas serve, pois, só iremos usar o
pino RA0.
Então, vamos escrever o valor B'00000111' no registador CMCON:

MOVLW B'00000111'
MOVWF CMCON

São apenas estes os Registradores de Uso Específico que precisamos


configurar neste nosso programa.

O próximo passo é inicializar as variáveis.


;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************;
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
;
************************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA
;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA

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


MOVWF TRISA ;CONFIGURA RA0 COMO SAÍDA 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 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 variáveis é escrever nestes registradores os valores que eles
devem ter na inicialização do programa.
Nós criamos 3 variáveis: DELAY_0, DELAY_1 e DELAY_2.
A variável 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.
Nós criamos constantes para estes 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 isto, quando escrevemos MOVLW INI_DELAY_0, o registrador W
assume o valor 255, ocorrendo o mesmo para os outros dois valores.

O próximo passo é a rotina principal do programa.

Nosso programa aguarda que passe 0,5 segundo e testa o LED para ver se
está aceso ou apagado. Se estiver aceso, apaga e se estiver apagado, acende, voltando a aguardar 0,5
segundo para testar o LED novamente.
Há mais de uma forma de contar este tempo de 0,5 segundo. Neste
programa vamos fazer isto decrementando os valores de variáveis. No próximo programa iremos
fazer de outra forma mais eficiente.
Nossa rotina irá decrementar a variável DELAY_0 até que ela chegue ao
valor 0.
Quando DELAY_0 chega ao valor 0, ela é reiniciada e a variável DELAY_1
é decrementada.
Quando DELAY_1 chega a 0, ela é reiniciada e a variável DELAY_2 é
decrementada.
Quando DELAY_2 chegar a 0 terá passado aproximadamente 0,5 segundo.

A maioria das instruções no PIC16F628A são executadas em 1 ciclo de


instrução, sendo 1 ciclo de instrução igual a 4 ciclos do sinal de clock. Algumas instruções são
executadas em 2 ciclos de instrução, entre elas GOTO e CALL.
Neste projeto, estamos utilizando o oscilador interno numa frequência de 4
MHz e, portando, o ciclo do sinal de clock é de 250 nanosegundos (1/4.000.000). Sendo assim, o
ciclo de instrução é de 1 microssegundo.
Durante a simulação, iremos medir o tempo gasto até que DELAY_2 chegue
a 0, para então definirmos os valores definitivos das variáveis, pois, os valores que definimos são
uma estimativa.
Vamos lá!
Repare que a primeira coisa que escrevemos foi a label PRINCIPAL.
Toda vez que quisermos que o programa volte a este ponto escreveremos:
GOTO PRINCIPAL. (goto em Inglês significa vá para).
Há um certo preconceito a respeito da instrução GOTO. Algumas pessoas
dizem que se deve evitar usar esta instrução.
O que se deve evitar é usá-la desnecessariamente.
Sempre que for necessário usar esta instrução use-a sem medo. Ela foi feita
para ser usada!
A primeira instrução é DECFSZ DELAY_0,F
Esta instrução decrementa o valor de DELAY_0 e, após, verifica se o valor
ficou igual a 0.
Repare na letra F após o DELAY_0. Ela indica que o registrador será
decrementado e o resultado será gravado nele próprio, ou seja, supondo que o valor de DELAY_0
fosse 255, então, 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 após decrementar DELAY_0, o seu valor for igual a 0, a próxima linha
do programa será pulada, se não, a próxima linha será executada.
Repare no nome desta instrução: DEC vem de decrementar, F, o registrador
que será decrementado, S, da palavra skip (neste caso, pular, em Inglês) e Z de zero. DECFSZ =
decrementa o registrador F e pula a próxima linha se o resultado for zero.
Se você procurar fazer estas associações entre o nome das instruções e sua
função, irá memorizá-las mais facilmente.
Voltando ao nosso programa, se o resultado da operação for diferente de
zero, a próxima linha do programa será executada.
O que precisamos que ocorra quando a variável DELAY_0 ainda não
chegou a 0?
Precisamos que ela continue a ser decrementada até que o seu valor seja
igual a 0.
Por isto, na próxima linha escrevemos: GOTO PRINCIPAL.
Isto faz com que a variável DELAY_0 seja decrementada novamente até que
seu valor chegue a 0, quando, então, a linha após a instrução DECFSZ será pulada.
Neste momento em que DELAY_0 chega a zero, nós iremos reiniciá-la.
Fazemos isto, da mesma forma que fizemos para escrever o seu valor, na
parte de Inicialização das Variáveis:

MOVLW INI_DELAY_0
MOVWF DELAY_0

Após reinicializar DELAY_0, vamos decrementar DELAY_1 e testar se seu


valor chegou a 0:
DECFSZ DELAY_1,F

Se o seu valor não for igual a 0, o programa deverá voltar para decrementar
DELAY_0 e por isto, usamos a mesma instrução de antes:
GOTO PRINCIPAL

Porém, 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 não 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 prática isto fica bem simples.


Recapitulando: DELAY_0 é decrementada até que seu valor chegue a 0,
quando, então, DELAY_1 é decrementada. Quando DELAY_1 chega a 0, DELAY_2 é
decrementada. Quando DELAY_2 chega a 0, a contagem de tempo chegou ao fim.
Com os valores que escrevemos provisoriamente nestas variáveis,
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 cálculos, 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 instrução em
1 microssegundo.
Quando formos fazer a simulação da execução do programa, iremos medir o
tempo que demorou para DELAY_2 zerar e então, faremos os ajustes nos valores das variáveis, para
que este tempo seja de aproximadamente 0,5 segundo.

Nosso programa até o momento está assim:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /2011
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

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

;***********************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA

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


MOVWF TRISA ;CONFIGURA RA0 COMO SAÍDA 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 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

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


GOTO PRINCIPAL ;NÃO
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 ;NÃO
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 ;NÃO
MOVLW INI_DELAY_2 ;SIM, W = INI_DELAY_2
MOVWF DELAY_2 ;REINICIALIZA DELAY_2

Agora que passou o tempo de 0,5 segundo, devemos testar o LED para ver
se ele está aceso ou apagado.
O LED estará aceso se o pino RA0 estiver em nível alto e apagado se estiver
em nível 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 instruções: BTFSS E BTFSC.
BTFSS testa o bit e pula a próxima 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 próxima 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 serão usadas.
Neste nosso programa não faz diferença e, portanto, vamos escolher
BTFSS:

BTFSS LED

Você se lembra de que nós definimos a label LED para o bit 0 do registrador
PORTA. Portanto, quando escrevemos esta instrução, é aquele bit que será testado.
Vamos supor que o valor do bit seja igual a 1 e, neste caso, a próxima linha
do programa será pulada.
Se o valor do bit 0 do PORTA é igual a 1, significa que o LED está aceso e,
então, 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 instrução
BCF.

BCF LED

Com isto o LED irá apagar.


Mas, se quando testamos o bit 0 do PORTA com a instrução BTFSS, o valor
do bit era igual a 0, então, a próxima linha do programa seria executada.
Sendo o valor do bit 0 do PORTA igual a 0, significa que o LED está
apagado e, então, precisamos acendê-lo.
Para isto usamos a instrução BSF para fazer o valor do bit 0 do PORTA
igual a 1:
BSF LED

Com isso acendemos o LED.


Então, 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 instrução BSF LED e
em seguida executa a instrução BCF LED, ou seja, o LED é aceso e apagado em seguida. Como
faremos para resolver isto?
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, ele desviará para onde está
escrito ACENDE_LED, executando a instrução BSF LED.
Repare que depois de acender ou de apagar o LED ele desvia para o começo
da rotina principal, onde, começará novamente a decrementar as rotinas.
Com isto chegamos ao fim do nosso programa.
Devemos indicar o fim do programa ao MPLAB através da diretiva END.
Lembre-se de que nós ativamos o WDT nos bits de configuração.
O WDT é um circuito que reinicia o microcontrolador caso o programa
trave.
Ele é um contador que é incrementado continuamente e quando atinge o
valor máximo, provoca o reset do microcontrolador.
Em algum ponto do nosso programa deveremos escrever a instrução
CLRWDT, que reinicia o contador do WDT toda vez que é executada.
Caso o programa trave, esta instrução não será executada, provocando o
reset do microcontrolador.
É assim que o WDT funciona.
Vamos escrevê-la no começo da rotina principal:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A


;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

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

;***********************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

INICIO

BANCO_1 ;SELECIONA BANCO 1 DE MEMORIA

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


MOVWF TRISA ;CONFIGURA RA0 COMO SAÍDA 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 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 ;NÃO
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 ;NÃO
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 ;NÃO
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 próximo passo é simular a execução do programa para vermos se ele


se comporta como esperamos.
No menu “Project”, clique em “Project Wizard”.
Na janela que se abre clique em “Avançar”:
Figura 5

Na janela seguinte (“Step One”), selecione o PIC16F628A e clique em


“Avançar”.

Figura 6
Na próxima janela (“Step Two”), clique em “Avançar”:

Figura 7

Na próxima 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”.

Figura 9

Em seguida clique em “Avançar”

Figura 10
Na janela seguinte (“Step Four”), selecione o arquivo .asm, clique em
“Add” e em seguida clique em “Avançar”:

Figura 11

Na janela seguinte (“Symmary”), clique em concluir:

Figura 12
No menu “Project”, clique em “Build All”. Na janela que se abre, selecione
“Absolute”:

Figura 13

A seguir, expanda a janela chamada “Output”:

Figura 14
A mensagem “BUILD SUCCEEDED”, confirma que não ocorreu nenhum
erro na compilação.

Com isto, nós já temos disponível 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 execução 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
instrução presente naquela linha do programa (linha 56), não 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”.
Aparecerão os números das linhas à esquerda.
Vá na linha 56 e veja que o registrador em questão é o TRISA, que está no
banco 1. Repare que nós selecionamos este banco antes e, por isto, não precisamos nos preocupar.
O mesmo ocorre para a mensagem da linha 58.

Agora vamos à simulação:

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”.
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”.
Faça o mesmo para DELAY_1 e DELAY_2.

Figura 16

Em “Add SFR” adicionamos os Registradores de Uso Específico que


queremos visualizar, enquanto em “Add Symbol” adicionamos as variáveis por nós 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 botões do
simulador.
Aponte o mouse para cada botão para ver seus nomes. São eles: “Run”,
“Halt”, “Animate”, “Step Into”, “Step Over”, “Reset” e “Breakpoints”.

Figura 18

Clique no botão “Reset”.


O cursor vai para a linha 46 onde está a instrução GOTO INICIO.
Esta é a posição 0X00 da memória de programa, e, portanto é a instrução
contida nesta posição que o microcontrolador irá executar em primeiro lugar, quando for ligado ou
ressetado.
Repare que apareceu uma seta verde do lado esquerdo:

Figura 19
Esta seta indica qual instrução está para ser executada.
Clique no botão “Step Into”.
Este botão executa uma instrução a cada vez que é pressionado.
A instrução GOTO INICIO foi executada e, portanto, o programa foi
desviado para a linha após a label INICIO.
Clique novamente em “Step Into”.
Agora, a instrução 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 informações podem ser vistas nesta 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 endereço na memória de
programa onde está a instrução 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 botão “Step Into” e acompanhando a simulação da
execução do programa.
Após ser executada a instrução MOVWF DELAY_0, no menu “Window”
escolha a janela “Watch” e repare que a variável 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 botão “Step Into” e veja que após a instrução
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 após a label PRINCIPAL, pois, executa a instrução
GOTO PRINCIPAL.
Se continuar clicando em “Step Into”, você poderá acompanhar a variável
DELAY_0 sendo decrementada.
Ela irá ser decrementada até chegar no valor 0, quando, então, o programa
irá pular a linha com a instrução GOTO PRINCIPAL.
Para agilizar, na janela “Watch”, dê um duplo clique no valor da variável
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 instrução GOTO PRINCIPAL é pulada, sendo executadas as instruções
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 três para 1.
Clicando em “Step Into” veremos que agora DELAY_2 chega a 0, é
reiniciada e o programa irá executar a instrução 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, então, é
desviado para a instrução após a label ACENDE_LED, onde é executada a instrução BSF LED.
Em seguida ele volta para PRINCIPAL.
Visualiza 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 variáveis.
Vamos agilizar, alterando o valor das três variáveis para 1.
Desta vez no teste do bit ele verifica que o valor é 1 e executa a instrução
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 variável DELAY_2
chegar a 0 é de aproximadamente 500 milissegundos.
Dê um duplo clique na linha que contêm a instrução BTFSS LED.
Você verá que aparece uma letra B dentro de um círculo vermelho,
conforme a figura abaixo:

Figura 21
Você acaba de inserir um Breakpoint. O programa será interrompido toda
vez que encontrar um Breakpoint ativo.
Clique no botão “Reset” da barra de ferramentas do simulador e depois vá
clicando em “Step Into” até chegar na linha onde está a instrução CLRWDT.
No menu “Debugger”, clique em “StopWatch”.
Eis a janela do “StopWatch”:

Figura 22

Nesta janela, clique no botão “Zero”.


Volte para a janela do programa, selecionando-a no menu “Window” e
clique no botão “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 instrução 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”):
Figura 23

Ou seja, está demorando 665 milissegundos para que a variável DELAY_2


chegue a 0, mas, nós queremos que demore 500 milissegundos.
Vamos medir de quanto em quanto tempo a variável DELAY_2 é
decrementada.
Para isto, vamos inserir um outro Breakpoint na linha onde está a instrução
DECFSZ DELAY_2.
Após inserir o Breakpoint, clique no botão “Reset” do simulador e vá
clicando no botão “Step Into” até chegar na instrução 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 variável DELAY_2 é
decrementada a cada 51 milissegundos.
Figura 24

Estamos com um excesso de 125 milissegundos no tempo total.


Se nós diminuirmos o valor de inicialização da variável 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 isto, no
menu “Project” clique em “Build All”.
Retire o Breakpoint da linha onde está a instrução DECFSZ DELAY_2 e
deixe o outro que esta na linha com a instrução BTFSS LED.
Clique no botão “Reset” do simulador e vá clicando em “Step Into” até
chegar na linha com a instrução CLRWDT. Neste momento, vá para a janela “StopWatch” e clique
em “Zero”.
Volte para a janela do programa e clique no botão “Run” do simulador.
Quando o programa parar no Breakpoint, abra a janela “StopWatch”.
Repare que realmente o tempo total caiu para 512 milissegundos.
Figura 25

Ainda temos um excesso de 12 milissegundos.

Vamos experimentar diminuir o valor de inicialização 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 vamos remover o Breakpoint da linha que contem a instrução
DECFSZ DELAY_1 e deixar somente o da instrução BTFSS LED, para podermos medir o tempo
total novamente.
Agora o tempo total é bem próximo de 500 milissegundos:

Figura 26
Vamos experimentar diminuir o valor da variável DELAY_0 para 254.
Agora, o tempo é de praticamente 500 milissegundos.

Figura 27

Ficamos, então com estes valores para as variáveis: DELAY_0 = 254,


DELAY_1 = 49 e DELAY_2 = 10.

Nosso programa está como queríamos e agora é hora de gravá-lo no


microcontrolador.
Você poderá comprar um gravador ou montar o seu próprio gravador.
Há vários modelos à venda e também vários esquemas de gravadores na
Internet para quem quiser montar o seu.
Existem gravadores que são conectados na porta paralela, outros na porta
serial e também os que são conectados na porta USB.
Os melhores são 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).
Figura 28
Para utilizá-lo é necessário o programa IC-prog:
http://www.ic-prog.com/icprog106B.zip
Também é necessário 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, não
posso garantir que o mesmo funcione em versões 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.

Figura 29
Na próxima janela também 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.

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 “Configuração” clique em “Opções”.
Na aba “Diversos”, marque “Activar Driver NT/2000/XP”
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 “Configuração”, clique em “Opções” e na aba “Diversos”, em


“Processo Prioritário”, selecione “Alto” e clique em “OK”.
No menu “Configuração”, 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 “Fusíveis” já


estão configurados, pois, nós 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
confirmação, 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.

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 próxima parte, vamos criar um programa para a mesma finalidade,
porém, utilizando o TIMER 0 para obter o intervalo de 0,5 segundo entre as piscadas do LED.
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 frequência de cerca de 1Hz 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 deste 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 também
alterado, ou seja, podemos escrever o valor que quisermos nele (de 0 a 255).
O Timer 0 pode ser configurado para incrementar o TMR0 a partir do ciclo
de instrução ou a partir do ciclo de um sinal externo aplicado no pino T0CKI (pino 3).
Quando ele é incrementado pelo ciclo de instrução, 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 instrução, pois, desejamos obter um determinado intervalo de tempo, conhecendo o tempo
de duração do ciclo de instrução.
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.
Isto é 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 próximo incremento
fará seu valor voltar a 0 e, então, dizemos que ele “estourou”.
Quando o TMR0 estoura, o bit T0IF do registrador INTCON é setado, ou
seja, o valor deste bit passa a ser igual a 1, sendo que, este bit precisa ser apagado na rotina do
programa, para que se detecte nova mudança de seu estado.
Ao mesmo tempo uma interrupção é provocada, se estiver habilitada.
A vantagem de usar o Timer 0 para obter o tempo que desejamos é que o
programa fica livre para executar outras funções, bastando monitorar o estado do bit T0IF para ver
se o o tempo que desejamos já passou ou então habilitar a interrupção de estouro do Timer 0.
O intervalo de tempo que estamos precisando é de 500 milissegundos.
Para uma frequência do oscilador interno de 4 MHz, o ciclo de instrução é
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 instrução terão 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 instrução, 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 máximo, isto é, para 1:256.
Desta forma, o TMR0 será incrementado a cada 256 ciclos de instrução, 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.
Ou seja, mesmo com o prescaler no máximo, serão necessários mais de 1
estouros do TMR0 para obter o tempo que desejamos e, portanto, teremos que contar estes estouros.
Porém, a divisão de 500 milissegundos por 65,536 milissegundos não
resulta em um número exato.
Temos que, de alguma forma, obter um número exato de estouros que
correspondam ao tempo de 500 milissegundos.
Como vimos, 500 milissegundos correspondem a 500.000 ciclos de
instrução.
Dividindo 500.000 pelos valores de prescaler disponíveis, constatamos que
o maior valor do prescaler que resulta numa divisão 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 instrução, ou seja, a cada 32 microssegundos.
Se após toda vez que o TMR0 estourar, nós o reiniciarmos com o valor de
131 (escrevendo este valor nele), após 125 incrementos (256 – 131) ele irá estourar, ou seja, irá
estourar a cada 32 x 125 microssegundos = 4.000 microssegundos = 4 milissegundos.
Se nós 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
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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 não 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 alterações.
O próximo passo do programa é definirmos as variáveis.
Iremos utilizar apenas uma variável, que será usada para contar os estouros
do TMR0.
Vamos nomeá-la de CONT_EST_TMR0:
;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************
; VARIÁVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

CONT_EST_TMR0 ;USADO PARA CONTAR OS ESTOUROS DO TMR0

ENDC ;FIM DO BLOCO DE MEMORIA

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

O próximo passo do programa é definirmos as contantes.


Iremos utilizar duas constantes, uma no valor de 131 que será usada para
reinicializar o TMR0 e outra no valor de 125 para a variável 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 configuração dos registradores:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************
; VARIÁVEIS

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

;***********************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

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

Como iremos utilizar o Timer 0, precisamos configurar o registrador


OPTION_REG, que está associado a ele.
Este registrador encontra-se no banco 1 de memória.
Conforme consta no datasheet do PIC16F628A, o bit 5 desse registrador, é o
que define se o TMR0 será incrementado pelo ciclo de instrução ou a partir de um sinal externo.
Para que ele seja incrementado pelo ciclo de instrução, 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 deverão ser 1, 0 e 0, respectivamente.
Os demais bits não nos interessam e, portanto, vamos deixá-los com o valor
1, valor com o qual eles são inicializados.
Desta forma, iremos escrever o seguinte número binário no registrador
OPTION_REG: 11010100.
As configurações dos outros registradores são as mesmas.
A seguir, inicializamos a variável e teremos chegado à rotina principal:
;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************
; VARIÁVEIS

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

;***********************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA
;***********************************************************************************************

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDA 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 instrução 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 não houver estourado, o valor deste bit será igual a 0 e a


próxima linha do programa será executada. Portanto, nesta linha escreveremos a instrução 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


instrução GOTO PRINCIPAL será pulada.
Neste caso, a primeira providência que iremos tomar é apagar o valor do bit
TOIF para que na próxima vez que o TMR0 estourar possamos detectar a mudança 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 variável 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 não for igual a 0, a próxima linha será executada e, neste
caso, desviaremos o programa para o começo da rotina principal:

GOTO PRINCIPAL ;NAO

Se o valor da variável houver chegado a 0, iremos reiniciá-la e, neste caso,


terão se passado cerca de 500 milissegundos.
A partir daqui, o resto da rotina é igual ao do programa da parte I deste
tutorial.
O programa, portanto ficou assim:

;***********************************************************************************************
; PROGRAMA: PISCA LED
; VERSÃO 1.0
; DESENVOLVIDO POR: MULDER_FOX
; DATA DE CONCLUSÃO: / /
;***********************************************************************************************

#INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

;***********************************************************************************************
; BITS DE CONFIGURAÇÃO

__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

;**********************************************************************************************
; VARIÁVEIS

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

;***********************************************************************************************
; SAÍDA

#DEFINE LED PORTA,0 ;LED LIGADO EM RA0


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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO


GOTO INICIO ;DESVIA PARA INICIO

;***********************************************************************************************
; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES


RETFIE ;RETORNA

;***********************************************************************************************
; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDA 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 execução 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”, clique em “Add Files to Project...”, localize o arquivo
Pisca LED II.asm, 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 “Buid All”.
Verifique se a montagem foi feita com sucesso, selecionando a janela
“Output” no menu “Window”:

Figura 1

Selecione a janela com o programa Pisca LED II.asm, no menu “Window” e


execute o programa até a linha que contém a instrução CLRWDT, clicando no botão “Step Into” da
barra do simulador.
Insira um Breakpoint na linha que contém a instrução BTFSS LED, dando
um duplo clique nesta 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 botão “Run” do simulador.
O programa irá parar no Breakpoint.
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 instruções 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 simulação e medir o tempo.
Você verá que o tempo agora é de 497 milissegundos:

Figura 4

Como a diferença é menor, ficaremos com este valor.


Este projeto não exige um tempo exato, pois, não trata-se, por exemplo, de
um relógio.
Programas de relógio usam cristais cujo valor da frequência é um múltiplo
de 2 e desta forma, não é preciso reiniciar o Timer, deixando que ele rode de 0 a 255.
Em outra parte deste tutorial voltaremos a falar sobre este assunto.
Grave o programa no microcontrolador e constate o seu funcionamento!
Aqui termina a 2ª parte deste tutorial.
Na próxima parte, vamos continuar com este circuito, mas utilizaremos o
recurso da interrupção provocada pelo estouro do Timer 0.