166
Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 Pisca LED 1 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 um Hz. Vamos utilizar o microcontrolador PIC16F628A, um dos modelos mais usados hoje em dia. Figura 1

Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Embed Size (px)

Citation preview

Page 1: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

1

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 um Hz.

Vamos utilizar o microcontrolador PIC16F628A, um dos modelos mais

usados hoje em dia.

Figura 1

Page 2: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

2

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 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 3 v até 5,5V, sendo que com 3 v, 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

5 v a partir de 9 v.

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

Page 3: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

3

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

Indica o início

Indica uma subrotina

Inicialização das

variáveis

Passou 0,5

segundo? não

sim

Acende LED LED está aceso? Apaga LED

sim não

Page 4: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

4

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:

Page 5: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

5

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

; 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 têm de virem

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:

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

#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 esse comando.

Observe que foi deixado um espaço 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 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 se trata 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

isso sempre que reconhece o termo como uma diretiva. Isso 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 essas 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”. Isso é feito com a diretiva __CONFIG.

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

; BITS DE CONFIGURAÇÃO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF

& _LVP_OFF & _CP_OFF & DATA_CP_OFF

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

Page 6: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

6

São 2 “underlines” antes do CONFIG, seguido de espaço e após as

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,

caso o programa travar.

Vamos habilitar esse recuso escrevendo _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 escrevendo _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 isso, 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 recurso também não 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 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 isso, escrevemos _LVP_OFF.

DATA_CP é um recurso para proteger a memória de dados contra cópia.

Page 7: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

7

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 isso, escrevemos _CP_OFF &

DATA_CP_OFF.

O próximo passo é definir as “labels” para a comutação dos bancos de

memória 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 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 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, 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ão iremos precisar das posições destinadas a Registradores de Uso Geral que lá se

encontram, pois, nos bastarão 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 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.

Page 8: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

8

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 esse motivo, minha forma preferida para defini-las é com o uso da diretiva CBLOCK:

Page 9: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

9

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

; 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).

Esse endereço 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 memória nesse

banco.

Os do endereço 70 até 7F sã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 intercalá-

las 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 utilizamos 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.

Esses valores serão ajustados depois que fizermos a rotina principal do

programa, por isso, os valores que iremos escrever agora serão provisórios.

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

Page 10: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

10

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

INI_DELAY_0, ele irá substituir essa expressão 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

variáveis não estavam satisfatórios, basta alterá-los ali, em vez de modificá-los em todas as linhas

do programa onde forem feitas reinicializações das variáveis.

A propósito, vamos falar de como representar, no 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.

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

; 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 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 são o PORTA e o PORTB.

O próprio 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

Page 11: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

11

Quando um pino estiver configurado como entrada (veremos depois 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 um pino estiver configurado como saída, e quisermos levar o seu nível

para alto, tornamos o valor do seu bit correspondente igual a 1. Para levar o pino para nível baixo,

tornamos o valor do bit correspondente igual a 0, ou seja, controlando o valor do bit controlamos o

nível no pino.

O próximo passo é o vetor de reset.

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

; VETOR DE RESET

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO GOTO INICIO ;DESVIA PARA INICIO

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

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 a ser 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 esse 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 isso. Periféricos são os circuitos presentes no microcontrolador

que fazem funções específicas como contadores, geradores 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, pois, o programa não caberia entre o endereço

0X00 e 0X03 e ele não pode ocupar os endereços a partir do 0X04, pois, ali estará a 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: ;**********************************************************************************************

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES RETFIE ;RETORNA ;***********************************************************************************************

Page 12: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

12

Em outra parte deste tutorial falaremos detalhadamente sobre interrupções.

O próximo passo é configurar os Registradores de Uso Específico.

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

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

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 de 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 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 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

ou no 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).

Page 13: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

13

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 esse número no registrador W.

Fazemos isso com a instrução MOVLW, desta forma: MOVLW B'11111110' Assim, 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 lembra mover. L lembra 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 escrevê-lo 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 ou saída: MOVLW B'11111111' MOVWF TRISB

No 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 de ele 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 isso, para que possamos utilizá-los como pinos

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 desses 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

Page 14: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

14

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

configurar nesse programa.

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

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

; 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 nesses 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 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 próximo 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 variáveis. No próximo programa iremos

utilizar 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 meio 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á!

Page 15: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

15

Primeiramente escrevemos 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á certo preconceito a respeito da instrução GOTO. Algumas pessoas dizem

que se deve evitar usar essa instrução.

O que se deve evitar é usá-la desnecessariamente.

Sempre que for necessário usar essa instrução use-a sem medo. Ela foi feita

para ser usada!

A primeira instrução é DECFSZ DELAY_0,F

Essa 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 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 essas associações entre o nome das instrução e sua

função, irá memorizá-la 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

Page 16: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

16

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 isso 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 terminou.

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

Page 17: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

17

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 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 isso 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 isso 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 isso?

Faremos assim:

Page 18: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

18

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 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 isso chegamos ao final 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, finalizando o programa:

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

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

Page 19: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

19

; 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

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

Page 20: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

20

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

; 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 ver se ele se

comporta como esperamos.

No menu “Project”, clique em “Project Wizard”.

Na janela que se abre clique em “Avançar”:

Page 21: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

21

Figura 5

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

“Avançar”:

Figura 6

Page 22: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

22

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

Page 23: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

23

Figura 9

Em seguida clique em “Avançar”

Figura 10

Page 24: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

24

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

clique em “Add” e em seguida clique em “Avançar”:

Figura 11

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

Figura 12

Page 25: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

25

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

“Absolute”:

Figura 13

A seguir, expanda a janela chamada “Output”:

Page 26: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

26

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á à linha 56 e veja que o registrador em questão é o TRISA, que está no

banco 1. Repare que nós selecionamos esse banco antes e, por isso, 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”.

Page 27: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

27

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

Page 28: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

28

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

Page 29: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

29

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

resetado.

Repare que apareceu uma seta verde do lado esquerdo:

Figura 19

Page 30: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

30

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

Page 31: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

31

Se continuar clicando em “Step Into”, você poderá acompanhar a variável

DELAY_0 sendo decrementada.

Ela irá ser decrementada até chegar ao 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.

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

Page 32: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

32

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 à linha onde está a instrução CLRWDT.

No menu “Debugger”, clique em “StopWatch”.

Eis a janela do “StopWatch”:

Page 33: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

33

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”):

Page 34: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

34

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

Page 35: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

35

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 isso, no

menu “Project” clique em “Build All”.

Retire o Breakpoint da linha onde está a instrução DECFSZ DELAY_2,

dando um duplo clique nessa linha, e deixe o outro que está na linha com a instrução BTFSS LED.

Clique no botão “Reset” do simulador e vá clicando em “Step Into” até

chegar à 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.

Page 36: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

36

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 o tempo total é bem próximo de 500 milissegundos:

Figura 26

Page 37: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

37

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

Page 38: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

38

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.

Page 39: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

39

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.

Page 40: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

40

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”

Page 41: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

41

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

Page 42: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

42

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

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.

Page 43: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 1 – Pisca LED

43

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 meio segundo entre as piscadas do LED.

Page 44: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

44

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

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 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 desse bit passa a ser igual a 1, sendo que ele 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 se 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 tempo que desejamos já passou. Outra opção é habilitar a interrupção de estouro do Timer 0.

O intervalo de tempo que precisamos é de 500 milissegundos.

Para uma frequência do oscilação 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.

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

Page 45: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

45

Ou seja, mesmo com o prescaler no máximo, serão necessários mais de 1

estouros do TMR0 para obtermos o tempo que desejamos e, portanto, teremos que contar esses

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 todas as vezes 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 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

; 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 é a definição das variáveis.

Iremos utilizar apenas uma variável, que será usada para contar os estouros

do TMR0.

Vamos nomeá-la de CONT_EST_TMR0:

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

; VARIÁVEIS

CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

Page 46: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

46

CONT_EST_TMR0 ;USADO PARA CONTAR OS ESTOUROS DO TMR0

ENDC ;FIM DO BLOCO DE MEMORIA

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

O próximo passo é a definição 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 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:

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

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

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

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

Page 47: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

47

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

; 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 desse bit será igual a 0 e a

próxima linha do programa será executada. Portanto, nessa 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.

Nesse caso, a primeira providência que iremos tomar é zerar o 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, nesse caso,

desviaremos o programa para o começo da rotina principal:

GOTO PRINCIPAL ;NAO

Page 48: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

48

Se o valor da variável houver chegado a 0, iremos reiniciá-la e, nesse 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.

Portanto, o programa ficou assim:

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

; PROGRAMA: PISCA LED II

; 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

Page 49: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

49

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

; 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”, 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”:

Page 50: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

50

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 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 botão “Run” do simulador. O

programa irá parar no Breakpoint.

Page 51: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

51

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 esse valor.

Page 52: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 2 – Pisca LED II

52

Este projeto não exige um tempo exato, pois, não se trata, 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 esse 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.

Page 53: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

53

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 mudanças de estado do LED.

A diferença é que iremos habilitar a interrupção do Timer 0 para que não

seja necessário ficar testando o bit T0IF para sabermos quando o registrador TMR0 estourou.

O recurso de interrupção permite que o microcontrolador possa executar

outras tarefas, sendo interrompido quando ocorre o evento esperado, quando então, os

procedimentos relativos a esse evento são tomados.

Quando ocorre uma interrupção, o microcontrolador salva o endereço da

próxima instrução que seria executada e desvia para o endereço 0X04 da memória de programa,

executando a instrução contida nesse endereço.

Quando o microcontrolador encontra uma instrução chamada RETFIE, ele

recupera o endereço da instrução que seria executada antes de ocorrer a interrupção, voltando a

executar o programa do ponto onde havia sido interrompido.

A interrupção de cada periférico do microcontrolador, como o Timer 0, pode

ser habilitada ou desabilitada individualmente através de um bit específico.

Além disso, também existe um bit (PEIE - bit 6 do registrador INTCON),

que permite habilitar e desabilitar as interrupções de todos os periféricos ao mesmo tempo e outro

bit (GIE – bit 7 do mesmo registrador) que permite habilitar e desabilitar todas as interrupções do

microcontrolador ao mesmo tempo. Isso porque, além das interrupções dos periféricos existem as

interrupções por mudança de estado em determinados pinos do PORTB.

Conforme consta no datasheet do PIC16F628A, para habilitar a interrupção

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 periférico, também precisamos setar o bit PEIE (bit 6

do INTCON) para habilitar as interrupções de periféricos.

Finalmente, setamos o bit GIE (bit 7 do INTCON) para habilitar as

interrupções 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 faça as alterações, para não ter de digitar tudo novamente.

O programa é igual ao da Parte 2 até este ponto:

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

; PROGRAMA: PISCA LED III

; VERSÃO 1.0

; DESENVOLVIDO POR: MULDER_FOX

; DATA DE CONCLUSÃO: / /

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

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

Page 54: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

54

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

; 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

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

O próximo passo é a definição das variáveis.

Quando estamos trabalhando com interrupções, a primeira providência que

devemos tomar dentro da rotina de interrupção é salvar os conteúdos 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 não é possível escrevermos diretamente nos

registradores, bem como, copiarmos o valor de um registrador diretamente para outro.

No registrador STATUS, é onde selecionamos o banco de memória de dados

(bits RP0 e RP1) e onde o microcontrolador registra informações sobre o estouro do WDT, entrada

em modo de economia de energia (Sleep), bem como, se operações de soma, subtração, rotação de

bits, etc... resultaram em zero e se houve estouro dos registradores envolvidos.

Nos programas que fizemos até agora, não efetuamos nenhuma leitura do

registrador STATUS, porque foram programas bem simples.

É necessário salvar os conteúdos dos registradores W e STATUS porque eles

são usados durante a rotina de interrupção.

No retorno da interrupção, se estes registradores não estiverem com os

valores que estavam antes, ocorrerá um erro.

Criaremos uma variável chamada W_TEMP para salvarmos o valor do

registrador W e outra chamada STATUS_TEMP para o registrador STATUS.

Esses nome são apenas sugestivos.

A variável CONT_EST_TMR0 terá a mesma função do programa anterior,

ou seja, a de contar os estouros do registrador TMR0.

A partir da definição das variáveis, o programa é igual até a rotina de

interrupção: ;**********************************************************************************************

; VARIÁVEIS

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

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

Page 55: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

55

; 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

Nos programas utilizados nas partes 1 e 2 deste tutorial, havia aqui apenas a

instrução RETFIE, pois não utilizamos o recurso de interrupção, e a instrução RETFIE servia para

se, por acaso, ocorresse uma interrupção inesperada, o programa voltasse ao ponto de onde havia

sido desviado.

Agora iremos habilitar a interrupção de estouro do Timer 0 e, quando ela

ocorrer, o microcontrolador irá executar o código contido a partir daqui.

Primeiramente vamos salvar os valores dos registradores W e STATUS,

copiando-os para as variáveis W_TEMP e STATUS_TEMP.

A Microchip, fabricante do PIC16F628A, recomenda a seguinte sequência

de instruções para salvar os conteúdos 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 através da instrução MOVWF.

A seguir, com a instrução 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 conteúdo do registrador STATUS (que estava no W com os nibbles invertidos) é salvo no

STATUS_TEMP, com a instrução MOVWF.

Uma vez salvos os conteúdos dos registradores W e STATUS, testamos o bit

T0IF do registrador INTCON para confirmarmos se a interrupção foi causada pelo estouro do Timer

0: BTFSS INTCON,T0IF ;TMR0 ESTOUROU?

Se o bit T0IF não estiver setado, significando que a interrupção não foi

causada pelo estouro do Timer 0, a próxima linha do programa será executada, e, nesse caso, temos

de fazer o programa voltar da interrupção.

Page 56: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

56

Para isso usamos a instrução RETFIE, porém, antes, temos de recuperar os

valores dos registradores W e STATUS.

Faremos isso executando as seguintes instruções, 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 INTERRUPÇÃO

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 através da instrução

MOVWF STATUS.

Também é realizado um “swap” no registrador W_TEMP e, como não havia

sido feito antes, faz-se outro em seguida. Ao mesmo tempo, o resultado é salvo no registrador W.

A seguir, vem a instrução RETFIE que faz o microcontrolador retornar da

interrupção.

Lembrando que esse procedimento é recomendado pela Microchip e pode

ser visto no datasheet do PIC16F628A.

Como teremos mais de uma situação em que precisaremos retornar da

interrupção, para evitarmos repetir as instruções acima, deixando nosso código o mais resumido

possível, iremos colocar essas instruções no fim da rotina de interrupção, após a label SAI_INT.

Assim, quando quisermos retornar da interrupção, usaremos a instrução

GOTO SAI_INT: GOTO SAI_INT ;RETORNA DA INTERRUPÇÃO

Se o bit T0IF estiver setado, indicando que a interrupção foi causada pelo

estouro do Timer 0, a linha com a instrução GOTO SAI_INT será pulada, e, nesse caso, na próxima

instrução apagaremos o bit T0IF:

BCF INTCON,T0IF ;SIM

É necessário apagar esse bit, caso contrário, quando o programa retornar da

interrupção, outra será gerada em seguida, já que o bit ainda estará setado.

Continuando com a rotina, vêm agora as instruções que reiniciam o

registrador TMR0: MOVLW INI_TMR0 ;W = INI_TMR0 MOVWF TMR0 ;REINICIA TMR0

A seguir decrementamos a variável 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 variável não houver chegado a zero, a próxima linha do

programa será executada.

Nesse caso, novamente iremos retornar da interrupção e, então, escrevemos

a instrução GOTO SAI_INT:

GOTO SAI_INT ;NAO

Page 57: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

57

Já, se a variável houver chegado a 0, essa linha será pulada e seguem-se as

instruções que reiniciam a variável:

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, após mudá-lo, retornamos da

interrupção:

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 interrupção, onde a variável CONT_EST_TMR0 é

decrementada. Como essa variável é iniciada com o valor 125, quando ela chega a 0, terão se

passado cerca de 500 milissegundos, quando, então, 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 interrupção.

O programa da parte 2 fica testando o bit T0IF para detectar quando ele for

setado. Aqui, não precisamos fazer isto, porque, quando o bit é setado, é gerada uma interrupção.

A cada interrupção, a variável CONT_EST_TMR0 é decrementada. Quando

o seu valor chega a 0, mudamos o estado do LED.

Neste programa tão simples, talvez você não veja muita vantagem nisso,

mas, em programas mais complexos, o recurso da interrupção é muito útil.

Nosso objetivo aqui foi explicar como usar o recurso da interrupção do

microcontrolador.

Com isso concluímos a rotina de interrupção que ficou assim:

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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 INTERRUPÇÃO 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

Page 58: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

58

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 INTERRUPÇÃO

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

O próximo passo é a configuração dos registradores de uso específico.

A diferença aqui em relação ao programa da parte 2, é a configuração do

registrador INTCON.

Conforme já havíamos comentado, temos que “setar” os bits 5 (T0IE), 6

(PEIE) e 7 (GIE) do registrador INTCON e, portanto, escreveremos o valor binário 11100000

neste registrador:

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

; 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 MOVLW B'11100000' MOVWF INTCON ;HABILITA INTERRUPÇÃO DO TIMER 0

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

A seguir vem a inicialização da variável CONT_EST_TRMR0.

Não é necessário inicializar W_TEMP e STATUS_TEMP, pois, não são

variáveis que precisam ter um determinado valor na inicialização.

Finalmente, vem a rotina principal, que consiste apenas na execução da

instrução CLRWDT.

O programa fica executando a instrução CLRWDT até que ocorra uma

interrupção.

O programa completo ficou assim:

Page 59: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

59

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

; PROGRAMA: PISCA LED III

; 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

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

; 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

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

Page 60: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

60

BTFSS INTCON,T0IF ;TMR0 ESTOUROU? GOTO SAI_INT ;NAO, SAIR DA INTERRUPÇÃO 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 INTERRUPÇÃO

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

; 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 MOVLW B'11100000' MOVWF INTCON ;HABILITA INTERRUPÇÃO DO TIMER 0 ;***********************************************************************************************

; INICIALIZACAO DA VARIÁVEL

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

Page 61: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

61

Vamos simular a execução 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 botão “Reset”:

Page 62: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

62

Figura 2

Na mesma barra de ferramentas, vá clicando no botão “Step Into”, e observe

que, na rotina principal, ele fica executando a instrução CLRWDT.

Clique duas vezes na linha da primeira instrução da rotina de interrupção

(MOVWF W_TEMP), para adicionar um “breakpoint”.

Abra a janela do “StopWatch”, no menu “Window”.

Clique em “Zero”.

Clique no botão “Run” da barra de ferramentas do simulador.

Na janela do “Stopwatch” repare que demorou cerca de 4 milissegundos

para que ocorresse uma interrupção.

Vá clicando no botão “Step Into” e observando a execução da rotina de

interrupção, e repare que após a execução da instrução RETFIE ele retorna à rotina principal.

Clique duas vezes na linha com o “breakpoint” para removê-lo e adicione

outro na linha com a instrução BTFSS LED.

Na janela do “Stopwatch”, clique em “Zero”, clique no botão “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.

Page 63: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 3 – Pisca LED III

63

Figura 3

Grave o programa no microcontrolador e teste no circuito para comprovar o

seu funcionamento.

Aqui termina a 3ª parte deste tutorial.

Na próxima parte iremos adicionar um chave do tipo push-button ou seja, do

tipo pulso ao nosso circuito, através da qual iremos ligar e desligar nosso pisca-pisca.

Page 64: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

64

Parte 4

Pisca LED com botão para ligar e desligar

Agora iremos acrescentar ao nosso circuito um botão 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 botão

está pressionado.

Primeiramente devemos decidir em qual pino do PIC16F628A iremos ligar

o botão.

Um botão é 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 botão incluído:

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

que o botão foi ligado entre o pino e o VSS.

Todo pino configurado como entrada tem de estar ou em nível alto ou em

nível baixo, ou seja, ou na tensão de VDD ou na de VSS.

No nosso circuito, quando o botão está solto, o resistor mantém o pino em

nível alto e quando o botão é pressionado o pino vai para nível baixo.

Se não houvéssemos ligado o resistor, quando o botão estivesse solto, o pino

ficaria desconectado, ou seja, “flutuando”, ocasionando um comportamento imprevisível do

microcontrolador quando efetuasse a leitura do estado deste pino.

Page 65: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

65

Poderíamos, também, ter ligado o botão entre o pino e o VDD e o resistor

entre o pino e o VSS, mas geralmente se liga o botão no VSS.

Quando utilizamos uma chave num circuito digital, nos deparamos com um

problema:

Quando a chave é acionada, a condução da corrente elétrica em seus

contatos fica instável 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 botão for pressionado, o LED deverá

alternar entre piscando e apagado.

Mas, com o problema da instabilidade da condução da corrente na chave,

nunca se saberia como o LED ficaria, pois, o microcontrolador poderia detectar dois, três, ou mais

apertos do botão a cada vez que ele fosse pressionado, devido ao problema descrito.

Para resolver esse problema, pode-se utilizar junto ao botão um circuito

conhecido como de “de-bouncing”, baseado em um capacitor.

Mas, quando estamos utilizando um microcontrolador, podemos dispensar o

uso deste circuito, pois é possível 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 botão

pressionado, ele é testado por cerca de mais 50 milissegundos e, se o seu estado permanecer o

mesmo por esse tempo, considera-se que o botão 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 botão.

Se o seu estado voltar para alto antes de ter transcorrido o referido tempo,

iremos começar a testar o botão novamente.

Isso elimina o problema da instabilidade da condução da corrente no

momento em que o botão é pressionado.

Há outro procedimento que deve ser adotado quando se utiliza um botão:

Caso se deseje que a ação seja produzida somente a cada aperto do botão (depois de realizada a

ação, mesmo que o botão seja mantido pressionado nada deverá ocorrer), devemos registrar de

alguma forma que a ação já foi realizada e que se deve aguardar o botão ser solto e pressionado

novamente.

Uma forma de fazer isso, é usar um bit de um registrador de uso geral. Este

bit é setado após a ação referente ao aperto do botão ser realizada e só é apagado quando o botão for

solto. Bits usados para esta finalidade são 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 alteração que faremos é na seção “Variáveis”, onde, iremos

adicionar três: FLAGS, DB_BTA e DB_BTB.

A variável FLAGS conterá os bits de flag.

As variáveis DB_BTA e DB_BTB serão usadas para a contagem do tempo

de de-bouncing do botão:

Page 66: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

66

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

; VARIÁVEIS

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 BOTÃO DB_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO

ENDC ;FIM DO BLOCO DE MEMORIA

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

A seguir, vamos criar as constantes para a inicialização das variáveis

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 simulação, para que tenhamos um

tempo de de-bouncing em torno de 50 milissegundos.

A seguir, depois da seção “Saída”, vamos criar uma seção 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 seção 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 BOTÃO #DEFINE ESTADO_DO_LED FLAGS,1 ;SE = 1 LED PISCANDO

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

A função do flag SOLTAR_BOTAO, já foi explicada. A do flag

ESTADO_DO_LED veremos adiante.

Também faremos alterações na rotina de interrupção, mas somente depois

que tenhamos escrito a rotina principal.

Page 67: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

67

A seguir, na seção “INICIALIZAÇÃO DAS VARIÁVEIS”, vamos incluir as

novas variáveis: ;***********************************************************************************************

; 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 variável FLAGS foi inicializada com a instrução CLRF. Esta instrução faz

todos os bits de um registrador iguais a 0.

Na rotina principal, após a instrução CLRWDT, temos a instrução BTFSS

SOLTAR_BOTAO que testa o estado desse bit de flag.

Se o valor desse bit for 0, significando que não está se aguardando soltar o

botão, a próxima linha será executada e programa será desviado para onde está a label

TESTA_BOTAO, onde será testado o estado do pino onde o botão está ligado (RA1) para ver se

está pressionado.

Porém, se o bit estiver setado, significando que está se aguardando soltar o

botão, devemos verificar se o botão já foi solto. Nesse caso, a próxima linha será pulada e será

executada a instrução BTFSS BOTAO, para testar o RA1.

Se o estado do RA1 for igual a 0, significa que o botão ainda não foi solto e

por isso o programa é desviado para o início 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 botão foi solto e, então,

apagamos o flag SOLTAR_BOTAO.

Após a label TESTA_BOTAO, temos a instrução BTFSC BOTAO, onde

testamos o estado do bit RA1 para verificarmos se o botão está pressionado.

Se ele não estiver pressionado, o estado deste bit será igual a 1, e, portanto, a

próxima linha será executada, desviando o programa para REINC_CONT_DEB, onde as variáveis

DB_BTA e DB_BTB são reinicializadas e depois o programa é desviado para o início da rotina

principal.

Se o botão estiver pressionado (estado do bit RA1 igual a 0), a próxima

linha será pulada e a instrução DECFSZ DB_BTA ,F será executada, começando o de-bouncing.

A instrução DECFSZ DB_BTA,F decrementa a variável e ao mesmo tempo

verifica se o seu valor chegou a 0. Se não chegou, o programa retorna para o início da rotina

PRINCIPAL e, se o botão permanecer pressionado, esta variável será novamente decrementada.

Toda vez que o valor de DB_BTA chega a 0, ela é reinicializada e a variável DB_BTB é

decrementada. Quando o valor de DB_BTB chegar a 0, o de-bouncing terá terminado.

Mas, para que isso ocorra, é necessário que o estado do pino RA1 se

mantenha em nível baixo durante todo esse tempo, que iremos ajustar para cerca de 50

milissegundos, através dos valores de inicialização de DB_BTA e DB_BTB.

Se antes disso o nível de RA1 voltar a 1, o programa será desviado para a

subrotina REINC_CONT_DEB, onde as variáveis DB_BTA e DB_BTB são reinicializadas, para

que se comece uma nova contagem de 50 milissegundos, quando for detectado nível baixo em RA1.

Page 68: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

68

Tendo o de-bouncing terminado com a variável DB_BTB chegando a 0, ela

é reiniciada.

Nesse momento podemos considerar que o botão foi pressionado e devemos

adotar as providências decorrentes disso.

No nosso circuito, queremos que a cada vez que o botão seja pressionado, o

LED mude de estado. Se ele estiver apagado deverá começar 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 próxima instrução é 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.

Após 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 botão 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 BOTÃO ESTÁ SOLTO? GOTO PRINCIPAL ;NAO, DESVIA BCF SOLTAR_BOTAO ;SIM, APAGA FLAG

TESTA_BOTAO

BTFSC BOTAO ;O BOTÃO ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB ;NÃO, 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

Page 69: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

69

MOVWF DB_BTB ;INICIALIZA DB_BTB GOTO PRINCIPAL ;DESVIA

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

END ;FIM DO PROGRAMA

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

Agora vamos fazer as alterações na rotina de interrupção.

É na rotina de interrupção 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 instrução 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 instrução BCF LED e em seguida sairemos da interrupção. Se o valor do bit

ESTADO_DO_LED for igual a 1, significando que o LED deverá piscar, deixaremos que a rotina

de interrupção prossiga:

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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 INTERRUPÇÃO 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

Page 70: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

70

MOVWF STATUS ;RECUPERA STATUS SWAPF W_TEMP,F ;SWAP EM W_TEMP SWAPF W_TEMP,W ;RECUPERA W RETFIE ;RETORNA DA INTERRUPÇÃO

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

Nosso programa está pronto para ser simulado, tendo ficado assim:

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

; PROGRAMA: PISCA LED IV

; 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

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 BOTÃO DB_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO

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

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

; SAÍDA

Page 71: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

71

#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 BOTÃO #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 INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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 INTERRUPÇÃO 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 INTERRUPÇÃO

Page 72: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

72

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

; 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 MOVLW B'11100000' MOVWF INTCON ;HABILITA INTERRUPÇÃO 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 BOTÃO ESTÁ SOLTO? GOTO PRINCIPAL ;NAO, DESVIA BCF SOLTAR_BOTAO ;SIM, APAGA FLAG

TESTA_BOTAO BTFSC BOTAO ;O BOTÃO ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB ;NÃO, 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

Page 73: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

73

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

Page 74: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

74

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 botão

“Add Symbol” e depois clicando nesse botão.

No menu “Debugger”, aponte o mouse para “Stimulus” e clique em “New

Wordbook”.

Na caixa de seleção do campo “Pin/SFR”, selecione RA1:

Page 75: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

75

Figura 2

Na caixa de seleção do campo “Action” ao lado, selecione “Set High”:

Figura 3

Page 76: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

76

Na próxima linha, selecione novamente RA1, porém 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 botão reset da barra de ferramentas do simulador.

Vá clicando no botão “Step Into”, até que o cursor esteja na linha com a

instrução CLRWDT .

Caso apareça esta janela, clique em “SIM”:

Page 77: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

77

Figura 5

No menu “Window”, alterne para a janela do “Stimulus”.

Clique no botão da primeira linha ao lado do RA1:

Figura 6

Clicando nesse botão estará fazendo com que o pino RA1 fique em nível

alto, ou seja, que o seu valor seja igual a 1.

Volte para a janela do programa e clique mais uma vez no botão “Step Into” .

Page 78: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

78

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

Figura 7

No “Stimulus”, clique agora no botão da linha de baixo.

Clique mais uma vez no botão “Step Into” e repare, no “Watch” que o RA1

voltou para 0.

Através desses botões iremos simular que o botão foi pressionado e que foi

solto.

Aproveitando que o RA1 está em nível baixo, simulando que o botão 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 contém

a instrução BTFSS ESTADO_DO LED (rotina principal) para inserir um “Breakpoint”, já que

quando o “de-bouncing” terminar, o programa irá executar essa instrução.

Abra a janela do “Stopwatch”, que deverá estar disponível no menu

“Window” e clique em “Zero”. Se a janela do “Stopwatch” não estiver disponível no menu

“Window”, abra-o através do menu “Debugger”.

Clique no botão “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:

Page 79: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

79

Figura 8

Como queremos um tempo de cerca de 50 milissegundos para o “de-

bouncing”, vamos experimentar diminuir o valor da variável DB_BTB para 20.

Fazemos isso na seção “CONSTANTES” alterando o valor de INI_DB_BTB.

Após alterar, temos de salvar, clicando no menu “File”, em “Save” e montar

novamente o projeto, clicando no menu “Project” em “Build All”.

Após fazer isso, vá clicando no botão “Step Into” até que o cursor chegue à

linha da instrução CLRWDT.

Abra a janela do “Stopwatch” e clique em “Zero”.

Clique no botão “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, não precisa ser de exatos 50 milissegundos.

Vá clicando no botão “Step Into” e acompanhe a execução do programa.

Quando ele retornar para o início da rotina “PRINCIPAL”, terão sido

setados os dois bits de flag: o que indica que se está aguardando soltar o botão e o que indica que o

LED deve piscar. Repare, no “Watch”, que esses dois bits estão setados.

Vá clicando no botão “Step Into” e repare que o programa está aguardando o

botão ser solto.

Vamos simular que o botão foi solto clicando, no “Stimulus”, no botão da

primeira linha, fazendo com que o RA1 vá para nível alto.

Vá clicando em “Step Into” e repare que ele apaga o flag

“SOLTAR_BOTAO”.

Continue clicando no botão “Step Into” e acompanhando a execução do

programa e repare que ele ficará em loop até que o botão seja novamente pressionado.

Como o flag que indica que o botão deve piscar foi setado, vamos ver se o

pino onde o LED está ligado (RA0) está alternando de nível.

Page 80: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

80

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

Figura 9

Arraste a janela do programa para baixo para liberar espaço:

Page 81: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

81

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 botões do “Stimulus”:

Figura 11

Page 82: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 4 – Pisca LED IV

82

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 botão “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 botão foi pressionado.

Ainda com o botão “Run” ativado, no “Stimulus”, clique no botão da

segunda linha para levar o RA1 para nível 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 nível 0, ou seja, o LED está apagado.

No “Stimulus” clique no botão da primeira linha para simular que o botão

foi solto.

Repare que o flag SOLTAR_BOTAO foi apagado.

Simule que o botão foi pressionado novamente através do “Stimulus” e

perceba que o RA0 voltou a alternar de estado.

Uma vez que o programa está se comportando como esperávamos, 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 próxima parte, vamos montar um circuito onde haverá um display de 7

segmentos e dois botões: um incrementará o número exibido no display, enquanto o outro o

decrementará.

Até lá.

Page 83: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

83

Parte 5

Contador Crescente e Decrescente

Desta vez iremos montar o circuito da figura abaixo onde o botão 1 irá

incrementar o número exibido no display, enquanto o botão 2 o decrementará.

Figura 1

Page 84: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

84

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

modelo compatível de dois dígitos, portanto o número exibido estará entre 00 e 99.

Para comandar os 14 segmentos dos dois dígitos do display a partir de

apenas 7 pinos do PIC16F628A, iremos ativar, a cada vez, somente um dos dígitos, através de seu

pino de catodo comum.

Quando o pino RA2 estiver em nível alto, a junção base-emissor do

transistor T1 estará diretamente polarizada, ativando o dígito 1.

Da mesma forma, quando o pino RA3 estiver em nível alto, será o dígito 2

que estará ativo.

Levaremos aos pinos RB0 a RB6 os níveis lógicos adequados para que seja

exibido o número desejado no dígito que estiver ativo no momento.

Desta forma, enquanto um dígito estiver exibindo o seu número, o outro

estará apagado.

Cada dígito estará ativo por cerca de 5 milissegundos, ficando apagado pelos

próximos 5 milissegundos (enquanto o outro estará ativo), voltando após este tempo a estar ativo

por mais 5 milissegundos e assim por diante.

Devido à persistência da visão, os dois dígitos parecerão estar acesos o

tempo todo.

O fluxograma do programa pode ser visto na figura 2, enquanto na figura 3

o da rotina de interrupção.

Page 85: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

85

Figura 2

Page 86: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

86

Figura 3

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

Contador.asm.

A primeira alteração que faremos é na seção “VARIÁVEIS”, onde vamos

excluir a “CONT_EST_TMR0” .

Como teremos dois botões, vamos renomear as variáveis “DB_BTA” e

DB_BTB” para “DB1_BTA” e “DB1_BTB” e criar outras duas: “DB2_BTA” e “DB2_BTB”.

Criaremos uma variável chamada “UNIDADE” para a unidade do número

exibido no display e outra chamada “DEZENA” para a dezena.

Page 87: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

87

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

; VARIÁVEIS

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 BOTÃO 1 DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 1 DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2 DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2

UNIDADE ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY DEZENA ;DEZENA DO NUMERO EXIBIDO NO DISPLAY

ENDC ;FIM DO BLOCO DE MEMORIA

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

Na seção “CONSTANTES”, vamos excluir “INI_CONT_EST_TMR0” e

“INI_TMR0”, renomear as que inicializam as variáveis de “de-bouncing” do botão 1 e criar as que

inicializam as do botão 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 seção “SAÍDAS”, 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 nível alto, o dígito 1 do display

estará ativo e quando RA3 estiver em nível alto, o dígito 2 estará ativo:

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

; SAÍDAS

#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 seção “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

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

Page 88: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

88

Na seção “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 BOTÃO 1 #DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTÃO 2

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

Chegamos à rotina de interrupção.

O Timer 0 será configurado para que gere uma interrupção a cada 5

milissegundos aproximadamente. Isto será feito depois, na seção de configuração dos registradores.

Na rotina de interrupção, iremos:

Verificar qual dígito está ativo e desativá-lo;

Ativar o outro dígito;

Converter o valor numérico 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 INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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 INTERRUPÇÃO BCF INTCON,T0IF ;SIM

A seguir, vamos verificar qual o dígito 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 instrução BTFSS, testamos se o dígito 1 está ativado e, se estiver,

desativamo-lo com a instrução “BCF DIGITO_1” e ativamos o dígito 2 com a instrução

“BSF DIGITO_2”.

Page 89: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

89

Porém se o dígito 1 estiver desativado, significa que o dígito 2 está ativo e,

então, o programa é desviado para a label “DESATIVA_DIGITO_2”, onde o dígito 2 é desativado e

o dígito 1 é ativado.

Repare que antes de ativarmos o dígito, fazemos todos os bits do PORTB =

0 com a instrução CLRF, para que o dígito que será ativado não receba os valores do dígito que

acaba de ser desativado.

Os segmentos do display estão 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 são

ativados com nível alto. Sendo assim, os valores a serem escritos no PORTB para cada algarismo a

ser exibido no display são os constantes na tabela abaixo. O bit 7 do PORTB está desconectado,

portanto, seu valor é indiferente, pelo que lhe atribuímos 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 0110111 1

Tabela 2

As figuras a seguir ilustram os valores da tabela anterior.

Page 90: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

90

01001111

00000110 00111111

01011011

Page 91: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

91

00000111

01101101 01100110

01111101

Page 92: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

92

Após o dígito ser ativado, devemos enviar para o PORTB o valor referente

ao algarismo que deve ser exibido.

O dígito 1 do display exibe a dezena do número e o dígito 2, a unidade.

O algarismo da dezena está gravado na variável “DEZENA”, enquanto que

o da unidade está gravado na variável “UNIDADE”, porém, esses algarismos estão gravados nessas

variáveis no formato binário, conforme a tabela abaixo:

Algarismo Valor binário

0 00000000

1 00000001

2 00000010

3 00000011

4 00000100

5 00000101

6 00000110

7 00000111

8 00001000

9 00001001

Tabela 3

01101111 01111111

Page 93: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

93

Esses valores são 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 binário 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, não podemos simplesmente copiar o valor da variável para o

PORTB.

Existe uma maneira prática de converter o valor binário para o

correspondente a 7 segmentos, que consiste em somar o valor binário ao Contador de Programa (PC

- Program Counter) para provocar um desvio no programa (Computed GOTO) para uma localidade

onde exista uma instrução que faça o programa retornar com o número já convertido no registrador

W.

O Contador de Programa (PC), armazena o endereço da próxima instrução

que será executada.

Quando o microcontrolador é ligado e também depois de um reset, o valor

do PC é igual a 0h (número 0 no formato hexadecimal), o que quer dizer que ele irá executar a

instrução gravada nessa localidade da memória de programa.

A cada instrução que é executada, o PC é incrementado em 1 unidade,

portanto, depois de executar a instrução contida no endereço 0h, ele irá executar a instrução contida

no endereço 1h, depois a do endereço 2h e assim por diante. Isso se as instruções contidas nesses

endereços não provocarem o desvio do programa para outra localidade da memória.

Um exemplo de instrução que provoca o desvio para outra localidade de

memória é a GOTO.

O PC do PIC16F628A é composto de 13 bits, sendo que os 8 bits menos

significativos (do 0 ao 7) compõe 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 através do registrador PCLATH.

Quando uma instrução GOTO é executada, o endereço para onde o

programa deverá ser desviado consta na própria instrução sendo copiado para o PC; portanto, a

próxima instrução que será executada é aquela que consta na instrução GOTO.

Outro tipo de instrução que provoca um desvio no programa é a instrução

CALL.

Page 94: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

94

Quando uma instrução CALL é executada, o valor do PC (endereço da

próxima instrução após CALL) é salvo no “Stack” e em seguida o PC assume o endereço que

consta na instrução CALL (que é para onde o programa deve ser desviado).

Uma vez desviado o programa, assim que uma instrução RETURN ou

RETLW for executada, o endereço que estava salvo no “Stack” é recuperado para o PC e, portanto,

o programa retorna para que seja executada a instrução que estava após a instrução CALL.

A instrução GOTO serve para provocar um desvio no programa quando não

se pretende que ele retorne, enquanto que a instrução CALL desvia o programa para que ele possa

retornar posteriormente.

A instrução RETURN simplesmente provoca o retorno, enquanto a instrução

RETLW faz com que o programa retorne com o valor escrito após a instrução no registrador W. Por

exemplo: RETLW .10: retorna com o valor 10 decimal no registrador W.

O “Stack” tem 8 níveis. Se, por exemplo, uma instrução CALL tiver sido

executada e outra instrução CALL for executada antes de uma instrução RETURN ou RETLW, o

endereço de retorno da primeira instrução passa para o nível 2 do “Stack” enquanto o endereço de

retorno da segunda instrução assume o nível 1.

Quando for executada uma instrução RETURN ou RETLW, o programa

voltará para o endereço constante no nível 1, ou seja, para depois da segunda instrução CALL. Ao

mesmo tempo o endereço de retorno da primeira instrução CALL volta a assumir o nível 1. Quando

for executada outra instrução RETURN ou RETLW o programa voltará para depois da primeira

instrução CALL.

Se nós somarmos um número ao registrador PCL, estaremos alterando o PC

e, portanto, o microcontrolador irá executar a instrução que esteja localizada no endereço que o PC

assumir.

Por exemplo, suponhamos que o valor do PC seja: 0010h. Isto significa que

a próxima instrução a ser executada será a que está localizada neste endereço da memória de

programa.

Nesse número hexadecimal, os dois algarismos menos significativos (10)

são o PCL e os dois mais significativos são o PCH (00).

Se, por exemplo, nós somarmos o número 5h ao PCL, o PC irá assumir o

valor: 0015h e, então, ao invés de ser executada a instrução contida no endereço 0010h será

executada a contida no endereço 0015h.

Para somarmos um número a um registrador qualquer, precisamos,

primeiramente, fazer com que o registrador W assuma o valor desse número, através da instrução

MOVLW. Em seguida, através da instrução ADDWF, somamos o número ao registrador.

No exemplo citado, para somar o número 5 ao registrador PCL, fazemos

assim: MOVLW .5 ;W = 5 ADDWF PCL,F ;PCL = PCL + 5

A instrução ADDWF soma o valor do registrador W ao registrador indicado,

no caso, o PCL. A letra F após a vírgula indica que o resultado da soma será salvo no próprio

registrador PCL.

O PCL é um registrador de 8 bits, e, portanto, o seu valor pode assumir, no

máximo, o valor 255 decimal.

Isto quer dizer que se o seu valor for, por exemplo, igual a 252 e somarmos

a ele o número 5, ele irá assumir o valor 1, pois, terá estourado (252 + 1 = 253 + 1 = 254 + 1 = 255

+ 1 = 0 + 1 = 1).

Page 95: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

95

Esse estouro do PCL provocado quando somamos um número a ele não faz

com que o PCH seja incrementado, como ocorre quando o PC é incrementado pelo ciclo de

instrução.

Desta forma, antes de somarmos um número ao PCL, devemos ter o cuidado

de verificar se isso não irá provocar o estouro do PCL, pois, se provocar, o programa será desviado

para uma localidade que não é 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 não ocorreu

porque o estouro do PCL não provocou o incremento do PCH.

Ou seja, o programa seria desviado para o endereço 0001h quando

queríamos 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, através do registrador PCLATH, fazendo o seu

valor igual ao que deverá assumir o PCH após a soma. No momento da soma ao PCL, o PCH

assumirá o mesmo valor do PCLATH, pois, toda vez que ocorre uma alteração no PCL, o conteúdo

do PCLATH é copiado para o PCH.

Para verificarmos se uma soma ao PCL irá provocar o seu estouro,

verificamos as localidades que assumiram as instruções, depois que o código esteja montado.

Veremos como fazer isso ainda nesta parte do tutorial, quando o programa estiver pronto.

Voltemos ao programa!

Após o dígito 2 ser ativado, o programa é desviado para onde se encontra a

label “COPIAR_UNIDADE”.

Com a instrução MOVF, copiamos o valor da variável “UNIDADE” para o

registrador W:

COPIAR_UNIDADE

MOVF UNIDADE,W ;W = UNIDADE

Em seguida usamos a instrução 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 instrução ADDWF para somar o valor da variável

“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

Page 96: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

96

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

consequentemente o do PC não mudará e, portanto, a próxima instrução que será executada é

RETLW B'00111111'. O programa, então, 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 instrução 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 número 1 e assim por diante.

Após retornar, será executada a instrução que vem depois da instrução

CALL e como já temos o número convertido no registrador W, basta copiá-lo para o PORTB:

MOVWF PORTB ;PORTB RECEBE O VALOR CONVERTIDO

O mesmo procedimento é adotado quando o dígito 1 for ativado, com a

diferença de que é o valor da variável “DEZENA” que é copiado e convertido.

Em seguida, desviamos o programa para a subrotina “SAI_INT” para que

retorne da interrupção.

Concluímos, assim, a rotina de interrupção:

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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

Page 97: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

97

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 INTERRUPÇÃO

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

O próximo passo é configurar os registradores de uso específico.

Devemos configurar o Timer 0 para estourar a cada 5 milissegundos,

aproximadamente.

Como ele será incrementado pelo ciclo de instrução, 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 é próximo o suficiente daquele que precisávamos.

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 também o registrador TRISA para definirmos os pinos

RA0 e RA1 como entrada e os pinos RA2 e RA3 como saída. Os demais pinos do PORTA,

deixaremos como entrada.

Devemos configurar ainda o registrador TRISB para definirmos os pinos

RB0 a RB6 como saída deixando o RB7 como entrada, pois não é usado.

As demais configurações são as mesmas do programa anterior:

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

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDAS 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 INTERRUPÇÃO DO TIMER 0 ;***********************************************************************************************

Page 98: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

98

A seguir, em “INICIALIZAÇÃO DAS VARIÁVEIS”, inicializamos as

variáveis de de-bouncing dos botões com os seus devidos valores e as variáveis “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 “Programação

Estruturada”, onde, na rotina principal, chamamos através da instrução CALL as subrotinas do

programa.

Teremos duas subrotinas que serão as que tratam os dois botões.

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 botão para verificar se ele está solto. Se

estiver, apagamos o flag. Se não estiver solto, retornamos através da instrução RETURN.

Se o flag “SOLTAR_BOTAO_1” não estiver setado, testamos o botão. Se

ele não estiver pressionado, retornamos. Se estiver pressionado, decrementamos a variável

“DB1_BTA” dando início ao de-bouncing e em seguida retornamos.

O retorno depois de decrementar as variáveis do de-bouncing é para que o

programa não 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 BOTÃO 1 ESTÁ SOLTO?

Page 99: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

99

RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1

BTFSC BOTAO_1 ;O BOTÃO 1 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_1 ;NÃO, 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 botão 1:

BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTÃO 1

Como ficou definido, a cada vez que o botão 1 for pressionado o número

exibido no display será incrementado.

O número é composto de dois dígitos: unidade e dezena. Para incrementar

esse número, devemos incrementar a unidade, o que fazemos com a instrução INCF:

INCF UNIDADE,F ;INCREMENTA UNIDADE

Essa instrução 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 próprio 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 não 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 instrução XORWF.

Essa instrução efetua a operação lógica XOR entre o registrador W e outro

registrador. Essa operação é 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 serão iguais a 0 e,

portanto, o valor numérico 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 operação XOR entre eles será igual a 0.

Começamos por fazer o valor do registrador W igual a 10: MOVLW .10 ;W = 10

Em seguida, efetuamos a operação XOR entre o registrador “UNIDADE” e

o W, salvando o resultado no W (para não alterar o valor do “UNIDADE”):

XORWF UNIDADE,W ;W = W XOR UNIDADE

Se o valor da variável “UNIDADE” for igual a 10 (valor do W), o resultado

da operação será igual a 0.

Para sabermos se o resultado da operação foi igual a 0, testamos o bit “Z”

do registrador “STATUS”:

Page 100: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

100

BTFSS STATUS,Z ;UNIDADE = 10?

O bit ”Z” serve para indicar quando o resultado de determinadas operações,

entre elas a XOR, foi igual a 0, sendo que, nesse caso, o valor deste bit será igual a 1, caso contrário

será igual a 0.

Então, se o valor do bit “Z” for igual a 0, significa que o resultado da

operação XOR entre o registrador “UNIDADE” e o registrador W, não foi igual a 0, e portanto, o

valor do registrador “UNIDADE” é diferente de 10. Nesse caso, a próxima linha do programa, onde

está a instrução RETURN, será executada.

RETURN ;NAO, RETORNA

Mas, se o bit “Z” for igual a 1, então, o valor da unidade é igual a 10 e,

então, a linha com a instrução 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, após incrementarmos a

dezena, devemos verificar se o seu valor é igual a 10. Se não for, basta retornar e, se for igual a 10,

devemos zerá-la e depois retornar, pois não 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, concluímos 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 BOTÃO 1 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1

BTFSC BOTAO_1 ;O BOTÃO 1 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_1 ;NÃO, 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 BOTÃO 1

Page 101: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

101

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 botão 1

(porém fazendo referência ao botão 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 BOTÃO 2 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2

BTFSC BOTAO_2 ;O BOTÃO 2 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_2 ;NÃO, 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 BOTÃO 2

O botão 2 a cada vez que for pressionado decrementará o número mostrado

no display.

Devemos, portanto, decrementar a unidade e para isso usaremos a instrução

DECF, que diminui em 1 unidade o valor de um registrador:

DECF UNIDADE,F ;DECREMENTA UNIDADE

Page 102: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

102

Precisamos verificar qual o valor do registrador UNIDADE, após ser

decrementado.

Se o valor do registrador antes de ser decrementado era 0, seu valor após o

decremento será 255, já que se trata de um registrador de 8 bits, cujo valor varia de 0 a 255, porém,

nesse caso, a unidade deverá assumir o valor 9.

O que faremos é verificar se o valor da unidade é igual a 255. Se não 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

Concluímos 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 BOTÃO 2 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2

BTFSC BOTAO_2 ;O BOTÃO 2 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_2 ;NÃO, 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 BOTÃO 2 DECF UNIDADE,F ;DECREMENTA UNIDADE MOVLW .255 ;W = 255 XORWF UNIDADE,W ;W = W XOR UNIDADE BTFSS STATUS,Z ;UNIDADE = 255?

Page 103: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

103

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

; 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

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 BOTÃO 1

DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 1

DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2

DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2

Page 104: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

104

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

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

; SAÍDAS

#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 BOTÃO 1 #DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTÃO 2

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

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO

GOTO INICIO ;DESVIA PARA INICIO

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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

Page 105: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

105

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 INTERRUPÇÃO

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

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDAS 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 INTERRUPÇÃO DO TIMER 0

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

; INICIALIZACAO DAS VARIAVEIS

CLRF FLAGS ;INICIALIZA FLAGS MOVLW INI_DB1_BTA ;W = INI_DB1_BTA MOVWF DB1_BTA ;INICIALIZA DB1_BTA

Page 106: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

106

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 BOTÃO 1 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1

BTFSC BOTAO_1 ;O BOTÃO 1 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_1 ;NÃO, 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 BOTÃO 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

Page 107: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

107

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

TRATA_BOTAO_2

BTFSS SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2? GOTO TESTA_BOTAO_2 ;NAO, DESVIA BTFSS BOTAO_2 ;SIM, O BOTÃO 2 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2

BTFSC BOTAO_2 ;O BOTÃO 2 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_2 ;NÃO, 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 BOTÃO 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 “Avançar”.

Na janela “Step One”, selecione o PIC16F628A e clique em “Avançar”.

Na janela “Step Two”, clique em “Avançar”.

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 “Avançar”.

Page 108: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

108

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

e depois clique em “Avançar”.

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 contrário, confira se o programa está exatamente igual.

Figura 4

Quando falamos sobre a operação de soma ao registrador PCL, dissemos

que após montar o programa, deveríamos verificar se a soma não iria estourar o PCL.

No menu “View”, clique em “Disassembly Listing”.

A primeira coluna corresponde ao endereço, em hexadecimal, que a

instrução ocupará na memória de programa. A segunda coluna corresponde à instrução em

hexadecimal. A terceira coluna é a instrução em Assembly com os nomes dos registradores

substituídos pelos seus endereços na memória de dados.

Page 109: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

109

Figura 5

Repare que a instrução ADD PCL,F está localizada no endereço 01C.

Os dois dígitos menos significativos desse número (1C) correspondem ao

valor do registrador PCL, enquanto que o dígito mais significativo (0) é o valor do registrador PCH.

A última instrução RETLW está localizada no endereço 026.

Repare que não 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 instrução que efetua a soma de um valor ao PCL (no nosso caso, ADD PCL,F) e o valor

do PCH na última instrução da tabela são iguais.

Se houvesse estouro do PCL justamente nesse trecho, a maneira mais fácil

de resolver o problema seria reposicionando a tabela no programa, de forma que ficasse numa

posição onde não 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”:

Page 110: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

110

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). Faça o mesmo

na segunda linha para o RA1.

Na terceira linha, selecione o RA0 e, em “Action”, selecione “Set High”.

Faça o mesmo na quarta linha para o RA1. Na quinta linha, selecione o RA0 e, em “Action”,

selecione “Set Low”. Faça o mesmo na sexta linha para o RA1:

Page 111: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

111

Figura 7

Dessa forma quando clicarmos no botão “Fire” da primeira linha estaremos

simulando que o botão 1 foi pressionado e solto após 100 milissegundos. Clicando no botão “Fire”

da segunda linha, estaremos simulando que o botão 2 foi pressionado e solto após 100

milissegundos.

Definimos o tempo de 100 milissegundos para que o pino se mantenha em

nível baixo, pois esse tempo precisa ser superior ao tempo de de-bouncing que é de cerca de 50

milissegundos.

Os outros botões usaremos quando quisermos que os pinos fiquem fixos nos

níveis 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 botão “Step Into” da barra de ferramentas do simulador até o

cursor chegar à instrução CLRWDT.

Vá para a janela do “Stimulus”, selecionando-a no menu “Windows” e

clique nos botões “Fire” das terceiras e quarta linhas para levar RA0 e RA1 para nível alto,

simulando que os botões estão soltos.

Volte para a janela do programa, clique uma vez no botão “Step Into”.

Vá para a janela do “Watch” e confirme se RA0 e RA1 estão em nível alto:

Page 112: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

112

Figura 8

Volte para a janela do programa e clique novamente no botão “Step Into”.

Repare que o cursor foi para a subrotina “TRATA_BOTAO_1”, pois foi

executada a instrução CALL que chamou essa subrotina.

Continue clicando no botão “Step Into” e acompanhando a simulação do

programa. Repare que, como o botão 1 está solto, ele reinicia as variáveis do de-bouncing e tendo

encontrado uma instrução RETURN, retorna para a rotina principal, na próxima linha após a

instrução CALL.

Em seguida, ele irá executar a instrução que chama a subrotina do botão 2.

Depois de retornar para a rotina principal ele executa a instrução GOTO

PRINCIPAL, e recomeça o ciclo.

Vamos medir os tempos de “de-bouncing”.

Insira um “breakpoint” na linha que contem a instrução BSF

SOLTAR_BOTAO_1, na subrotina do botão 1.

No “Stimulus”, clique no botão “Fire” da quinta linha para fixarmos o nível

do RA0 em 0.

No menu “Debugger”, clique em “Stopwatch”.

Clique no botão “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, não sendo necessário um tempo tão longo.

Nem é necessário medir o tempo de “de-bouncing” do botão 2, pois, será o

mesmo.

Vamos ver se deixamos esse tempo próximo de 50 milissegundos,

diminuindo o valor de inicialização das variáveis DB1_BTB e DB2_BTB para 10 na seção

constantes.

Page 113: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

113

Após 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 botão “Step Into” até chegar à instrução CLRWDT.

Como os bits RA0 e RA1 são inicializados com o valor 0, clique no botão

“Fire” que fixa o valor do RA1 em 1, para simular que o botão 2 está solto.

Como vamos medir o tempo do “de-bouncing” do botão 1, podemos deixar

o valor do RA0 em 0, simulando que ele está pressionado.

No “Stopwatch”, clique em “Zero” e depois clique no botão “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 variáveis 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 botão “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 botão “Run” da barra do simulador.

No “Stimulus”, clique no botão “Fire” da primeira linha para simular que o

botão 1 foi pressionado e em seguida solto.

Page 114: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

114

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

Figura 10

Clique novamente no botão “Fire” da primeira linha e repare que a unidade

foi incrementada novamente, passando para 2.

Continue clicando nesse botão 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 botão “Fire” da segunda linha para simular que o botão 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 botão

“Halt” do simulador.

Vamos conferir a rotina de interrupção.

Insira um breakpoint na linha da primeira instrução da rotina de interrupção

(MOVWF WTEMP).

Clique no botão “Run” da barra do simulador e quando o programa parar no

“breakpoint”, vá para a janela do “Stopwatch” e clique em “Zero”.

Clique no botão “Run” novamente e quando o programa parar outra vez no

“breakpoint”, verifique no “Stopwatch” que o tempo entre uma interrupção e outra foi de 4

milissegundos.

Vá clicando no botão “Step Into” e observando a execução da rotina de

interrupção.

Page 115: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 5 – Contador Crescente e Decrescente

115

Repare que quando é a vez do dígito 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 instrução RETLW referente a este valor.

Quando é a vez do dígito 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

instrução RETLW correspondente.

Depois de executar a instrução 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

número que deve ser exibido no display de 7 segmentos.

Com isso concluímos a simulação do programa e podemos gravá-lo no

microcontrolador e testar o circuito na protoboard:

Figura 11

Aqui termina a 5ª parte deste tutorial. Na próxima parte, vamos utilizar a

memória EEPROM do PIC16F628A para que o valor do contador não seja perdido quando o

circuito é desligado.

Page 116: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

116

Parte 6

Contador Crescente e Decrescente II

O contador da parte anterior não retinha o seu valor quando a alimentação era

desligada, pois ele era salvo apenas na memória de dados, que é uma memória volátil, isto é, cujo

conteúdo só é mantido enquanto há energia elétrica.

Desta vez, vamos utilizar a memória EEPROM do PIC16F628A para manter

salvo o valor do contador mesmo que a alimentação seja desligada.

O PIC16F628A possui 128 localidades de memória EEPROM, cada uma com

8 bits. Essas localidades devem ser lidas ou escritas uma de cada vez, como ocorre na memória de

dados. Segundo informa a Microchip, fabricante desse microcontrolador, cada localidade dessas

suporta ser regravada cerca de um milhão de vezes, não havendo indicação do limite de número de

leituras. Iremos utilizar duas localidades: uma para o valor da unidade e outra para o valor da dezena.

Poderíamos 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 após cerca de um milhão de vezes que os valores fossem salvos. Quando isso

acontecesse, teríamos de trocar o microcontrolador ou reescrever o programa para definir outras duas

localidades. Porém, se todas as vezes que salvarmos aqueles valores, alterarmos as localidades,

estaremos prolongando esse tempo.

As localidades da memória EEPROM do PIC16F628A não são acessadas

diretamente como as da memória de dados. Para ler ou escrever na memória EEPROM, utilizamos

quatro registradores de uso específico:

EEADR: Nesse registrador, devemos escrever o endereço da localidade da

memória 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. É também no EEDATA onde o valor escrito na

localidade da memória EEPROM aparece quando efetuamos uma leitura.

EECON1: É o registrador de controle de leitura e escrita.

EECON2: Esse registrador não existe fisicamente, ou seja, não é uma

localidade da memória. Seu nome é usado para prover uma forma de segurança contra escrita

indesejada, conforme veremos adiante.

O tempo necessário para se efetuar uma gravação na memória EEPROM é

tipicamente de 4 milissegundos. Já, no caso de leitura, ela ocorre em apenas 1 ciclo de instrução.

Para efetuarmos a leitura de uma localidade da memória EEPROM, devemos

adotar os seguintes procedimentos:

Page 117: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

117

1º – Escrever no EEADR o endereço 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 memória EEPROM constará no EEDATA após um

ciclo de instrução, e o bit “RD” será zerado pelo microcontrolador.

Os registradores EEADR, EECON1 e EEDATA estão no banco 1 de memória

e, portanto, devemos selecionar esse banco antes de ler ou escrever nesses registradores.

Para efetuarmos a escrita de uma localidade da memória EEPROM, devemos

adotar os seguintes procedimentos:

1º – Escrever no EEADR o endereço da localidade que queremos escrever;

2º – Escrever no EEDATA, o valor que queremos escrever na localidade da

memória EEPROM;

3º – Setar o bit “WREN” (bit 2 do EECON1);

4º – Zerar o bit “GIE” (bit 7 do INTCON) para desabilitar as interrupções;

5º – Testar se o bit “GIE” foi zerado (recomendação da Microchip) e, se não

houver sido, repetir a instrução para zerá-lo;

6º – Escrever o número 55 (hexadecimal) no registrador EECON2;

7º – Escrever o número 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 interrupções.

As interrupções são desabilitadas para evitar que interfiram durante o

processo de escrita.

Escrever 55h e depois AAh no EECON2 é uma senha para que ocorra a

gravação na EEPROM. Serve para evitar gravações indesejadas.

A gravação demora cerca de 4 milissegundos. Quando ela houver sido

concluída, o microcontrolador irá zerar o bit “WR” e irá setar o bit “EEIF” (bit 7 do registrador PIR1)

gerando uma interrupção, caso esteja habilitada, o que é feito setando o bit EEIE (bit 7 do registrador

PIE1).

Há duas formas de sabermos se a gravação terminou: testando o estado do bit

“WR” ou habilitando a interrupção. Seja qual for a forma escolhida, quando terminar a gravação,

devemos, por precaução, verificar se o valor gravado na localidade da memória EEPROM

corresponde ao que queríamos. Para isso, efetuamos uma leitura daquela localidade e comparamos

com o valor que mandamos gravar. Se a gravação não terminar dentro do tempo esperado, devemos

reiniciar o processo de gravação.

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 alteração que faremos é na seção “VARIÁVEIS”.

Page 118: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

118

Como neste programa iremos acessar com frequência registradores que se

encontram no banco 1 da memória de dados, e para que não precisemos trocar constantemente de

banco, vamos criar as variáveis a partir do endereço 0x70, pois, as variáveis que ocupam esse

endereço até o 0x7F podem ser acessadas a partir de qualquer banco. Repare que são apenas 16

localidades que tem esse atributo.

Iremos adicionar as variáveis ESC_EEPROM_A e ESC_EEPROM_B para a

contagem do tempo de espera pelo fim da escrita na EEPROM e a variável LOCAL_DA_UNIDADE,

que conterá o endereço da localidade da EEPROM onde está salvo o valor da unidade:

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

; VARIÁVEIS

CBLOCK 0X70 ;ENDERECO DA PRIMEIRA VARIÁVEL

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 BOTÃO 1 DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 1 DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2 DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 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 ENDEREÇO DA EEPROM ONDE ESTÁ SALVO O VALOR DA UNIDADE

ENDC ;FIM DO BLOCO DE MEMORIA

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

Na seção “CONSTANTES”, acrescentaremos as de inicialização das variáveis

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 seção “FLAGS”, acrescentaremos os seguintes:

APAGAR_UNIDADE, GRAVAR_UNIDADE, GRAVAR_DEZENA, ESP_FIM_GRV_EEPROM,

CONF_GRV_EEPROM que serão usados na subrotina de gravação da EEPROM.

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

; FLAGS

#DEFINE SOLTAR_BOTAO_1 FLAGS,0 ;SE = 1, AGUARDA SOLTAR O BOTÃO 1

Page 119: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

119

#DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1, AGUARDA SOLTAR O BOTÃO 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 GRAVAÇÃO NA EEPROM #DEFINE CONF_GRV_EEPROM FLAGS,6 ;SE = 1, CONFERE A GRAVAÇÃO NA EEPROM

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

Para verificarmos se a gravação da EEPROM terminou, podemos escolher

entre testar o estado do bit “WR” até que ele seja zerado ou habilitar a interrupção de gravação

completa na EEPROM. Ficaremos com o teste do bit, por ser mais simples e, portanto, não iremos

fazer nenhuma alteração na rotina de interrupção.

A próxima alteração é na seção de Inicialização das Variáveis, onde

incluímos as instruções para a inicialização das variáveis criadas para a contagem do tempo de espera

pelo fim da escrita na EEPROM.

As variáveis UNIDADE e DEZENA não serão inicializadas com o valor 0,

como fizemos na parte anterior deste tutorial, mas, sim, com os valores que houverem sido salvos na

memória EEPROM, pois, queremos que quando o circuito seja ligado, ele mostre o valor que tinha

antes de ser desligado.

Como havíamos comentado, todas as vezes que formos salvar os valores da

unidade e da dezena, iremos alterar as localidades da memória EEPROM, a fim de prolongar sua vida

útil. Assim sendo, quando o programa for iniciado, ele terá de encontrar as localidades onde os

valores estão salvos.

Como o valor da unidade varia entre 0 e 9, apenas os quatro bits menos

significativos (bits 0 a 4) da localidade da memória são necessários para salvá-lo:

Valor em decimal Valor em binário Valor em decimal Valor em binário

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 código que fará com que

o programa identifique a localidade onde está armazenado o valor da unidade.

O código que utilizaremos será este: 0110, ou seja, esses serão os valores dos

bits 5 a 8 da localidade onde o valor da unidade estiver salvo. Esse código será gravado todas as

vezes que salvarmos o valor da unidade, porém, na gravação do programa no microcontrolador,

devemos escrever o código na primeira localidade da memória EEPROM, caso contrário, não haverá

nenhuma localidade com o código para que o programa encontre na primeira vez que o

microcontrolador for ligado. Isso é feito com o uso da diretiva “DE”, desta forma:

Page 120: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

120

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

; INICIALIZAÇÃO DA EEPROM

ORG 2100 ;APONTA PARA O ENDEREÇO 00H DA EEPROM DE B'01100000', .0 ;ESCREVE O NÚMERO BINÁRIO 01100000 NO ENDEREÇO 00H DA EEPROM ;E O NÚMERO DECIMAL 0, NA LOCALIDADE 01H

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

A diretiva “DE” serve para escrevermos nas localidades da memória

EEPROM durante a gravação do programa no microcontrolador. Para o PIC16F628A, devemos nos

referir à primeira localidade da memória EEPROM como 2100. Se quisermos escrever em localidades

sequenciais, basta separar os valores por vírgula. Por exemplo, se escrevêssemos assim:

DE .1, .5, .3 escreveríamos os números decimais 1, 5 e 3, nas três localidades iniciadas pela que foi

apontada na diretiva “ORG”.

No nosso caso, o número binário 01100000 será escrito na localidade 00h e o

número decimal 0 na localidade seguinte, ou seja, a 01h. Assim, na primeira vez que o programa for

executado, ele encontrará o código na primeira localidade da memória EEPROM, iniciando a unidade

com o valor 0. Na localidade seguinte, escrevemos 0 para que a dezena também seja iniciada com o

valor 0.

Insira a seção “INICIALIZAÇÃO DA EEPROM”, entre as seções “BITS DE

CONFIGURAÇÃO” e “PAGINAÇÃO DE MEMÓRIA”.

Voltando à seção “INICIALIZAÇÃO DAS VARIÁVEIS”, o programa irá ler

a primeira localidade da memória EEPROM (00h) em busca do código. Se encontrar, ele saberá que

o valor da unidade está salvo naquela localidade e, portanto, que o valor da dezena está salvo na

próxima (01h). Se não encontrar, ele irá ler a terceira localidade (02h). Se encontrar o código, ele

saberá que o valor da unidade está salvo naquela localidade, e a dezena na próxima (03h) e assim por

diante até encontrar onde estão 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 VARIÁVEL 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

Page 121: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

121

Primeiramente, inicializamos o EEADR com o valor 254.

A seguir, ele é incrementado duas vezes, assumindo o valor 0 (254 + 1 = 255

+ 1 = 0).

Após isso, o bit “RD” é setado, iniciando a leitura da localidade 00h da

memória EEPROM (valor do EEADR).

Em seguida, o conteúdo dessa localidade que estará disponível no EEDATA, é

copiado para o registrador W.

A seguir, com a instrução ANDLW, efetuarmos a operação lógica AND entre

o W e o número binário 11110000, para que os bits 0 a 4 sejam zerados e os bits 5 a 8 permaneçam

com o mesmo valor. O resultado é salvo no próprio W.

A operação AND é efetuada bit a bit entre os bits equivalentes do registrador

W e o número 11110000. O bit do resultado será igual a 1 somente se os dois bits forem iguais a 1.

Nas demais situações, o bit do resultado será 0.

Como no número binário 11110000, os bits 0 a 4 são iguais a zero, os bits 0 a

4 do resultado serão iguais a zero, não importando o valor destes bits no W.

Já os bits 5 a 8 do número binário 11110000 são iguais a 1, e, portanto, os

valores dos bits 5 a 8 do W serão 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, através da instrução XORLW, efetuamos a operação lógica XOR

entre o registrador W e o número binário 01100000, salvando o resultado no W. Repare que os bits 5

a 8 desse número contém o código que indica a localidade de memória EEPROM onde está salvo o

valor da unidade.

A operação lógica XOR também é 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 operação XOR serão iguais a 0, o que significa que o resultado da operação foi igual a 0.

Para saber se o resultado da operação foi igual a 0, testamos o bit Z do

registrador STATUS. Se o resultado houver sido igual a 0, esse bit estará setado, caso contrário, estará

zerado.

A instrução BTFSS STATUS,Z testa o valor do bit Z do registrador STATUS.

Se o seu valor for 0, significa que o resultado da operação XOR não foi igual a 0, ou seja, que o

registrador W é diferente de 01100000, e, então, não é na localidade testada que está salvo o valor da

unidade. Neste caso, a próxima 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 operação XOR entre o registrador W e o número binário 01100000 será igual a 0,

portanto o bit Z do registrador STATUS estará setado. Com isso, a próxima linha depois da instrução

BTFSS STATUS,Z será pulada. Nesse caso, o valor do EEADR é copiado para o W e, em seguida,

deste para a variável LOCAL_DA_UNIDADE, inicializando essa variável.

Page 122: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

122

A seguir, copiamos o valor do EEDATA para o W e, após isso, realizamos a

operação lógica AND entre o W e o número binário 00001111 para zerar os bits 5 a 8, onde está o

código, deixando apenas o valor da unidade nos bits 0 a 4. Então, copiamos o W para o registrador

UNIDADE, inicializando essa variável.

A seguir, o EEADR é incrementado, a fim de apontar para a próxima

localidade da memória EEPROM. Em seguida, o bit “RD” é setado, iniciando a leitura, e, na próxima

instrução, o valor do EEDATA, que agora contém a dezena, é copiado para o W. Depois, copiamos o

valor do W para o registrador DEZENA, inicializando essa variável.

Repare, que antes de acessarmos os registradores EEADR, EECON1 e

EEDATA, selecionamos o banco 1, pois eles estão localizados nesse banco.

Com isso, concluímos a seção de inicialização das variáveis, 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 VARIÁVEL 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

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

Page 123: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

123

Na rotina principal, acrescentaremos uma instrução CALL que chamará a

subrotina de gravação 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 botão 1, após 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, também,

precisamos apagar a localidade anterior da unidade para limpar o código 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 BOTÃO 1 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1

BTFSC BOTAO_1 ;O BOTÃO 1 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_1 ;NÃO, 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 BOTÃO 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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

Page 124: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

124

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 botão 2, também iremos setar esses mesmos flags após 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 BOTÃO 2 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2 BTFSC BOTAO_2 ;O BOTÃO 2 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_2 ;NÃO, 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 BOTÃO 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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 ;**********************************************************************************************

Page 125: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

125

A seguir, vamos escrever a subrotina de gravação 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 memória EEPROM.

Antes de salvá-los, iremos apagar a localidade onde, anteriormente, estava

escrito o valor da unidade, pois, precisamos apagar o código que identificava aquela localidade.

Portanto, são três etapas de escrita na EEPROM:

1) Escrever o número 0 na localidade anterior da unidade;

2) Escrever o valor da unidade com o código na nova localidade;

3) Escrever o valor da dezena na nova localidade.

Nas rotinas dos botões, depois que o valor da unidade é alterado, setamos os

flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA.

Na rotina de gravação da EEPROM, depois de escrevermos o número 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 gravação 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 gravação terminou, testando o bit

“WR”, já que uma gravação demora cerca de 4 milissegundos e só poderemos iniciar outra gravação

depois de que a anterior esteja concluída.

Depois de efetuar as três gravações, 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 instrução testa o flag que informa se o programa está aguardando a

conclusão de uma gravação 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

gravação:

BTFSC CONF_GRV_EEPROM ;NAO, CONFERIR A GRAVAÇÃO?

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:

Page 126: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

126

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, não há

nada para se fazer na subrotina de gravação 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).

Não precisamos apagar a localidade anterior da dezena, pois, ela não contêm o código de localização.

Primeiramente, copiamos o valor da variável LOCAL_DA_UNIDADE para o

EEADR para que este aponte para o endereço onde está gravada a unidade:

APAGA_UNIDADE_ANTERIOR

BANCO_1 ;SELECIONA BANCO 1 DE MEMÓRIA MOVF LOCAL_DA_UNIDADE,W ;W = ENDEREÇO 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

interrupções:

BCF INTCON,GIE ;DESABILITA AS INTERRUPÇÕES

Após isso, testamos esse bit para confirmarmos que ele foi zerado:

BTFSC INTCON,GIE ;BIT GIE ESTÁ ZERADO?

Page 127: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

127

Se ele não houver sido zerado, executamos novamente a instrução BCF

INTCON,GIE, para zerá-lo:

GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA

A instrução GOTO $-2, desvia o programa para 2 linhas acima, onde está a

instrução BCF INTCON,GIE. O número após o cifrão 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

número 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 quiséssemos que o programa fosse desviado para a 16ª linha abaixo, teríamos que

escrever GOTO $+10, pois, 10, no sistema hexadecimal equivale ao número 16 no sistema decimal.

Confirmado que o bit GIE foi zerado, escrevemos o número 55 e depois o

número 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 gravação:

BSF EECON1,WR ;INICIA A GRAVAÇÃO

A seguir, setamos o bit “GIE” para habilitar as interrupções:

BSF INTCON,GIE ;HABILITA INTERRUPÇÕES

Após 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 GRAVAÇÃO BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA RETURN ;RETORNA

Na próxima vez que o programa entrar na subrotina de gravação 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

gravação da EEPROM, que dura cerca de 4 milissegundos.

Para a contagem do tempo de 10 milissegundos, iremos usar as variáveis

ESC_EEPROM_A e ESC_EEPROM_B. A variável ESC_EEPROM_A será decrementada todas as

vezes que o bit “WR” for testado e não estiver zerado. Quando essa variável chegar a 0, ela será

reiniciada e a variável ESC_EEPROM_B será decrementada. Quando essa última chegar a 0, terá

passado cerca de 10 milissegundos.

Page 128: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

128

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

sem que a gravação tenha sido concluída, iremos setar os flags APAGAR_UNIDADE,

GRAVAR_UNIDADE e GRAVAR_DEZENA para reiniciar todo o processo de gravação e

apagaremos os flags “ESP_FIM_GRV_EEPROM” e “CONF_GRV_EEPROM” (este último estará

setado se a demora ocorreu na gravação da dezena).

Raramente isso irá ocorrer, mas temos de contar com essa situação.

Quando o bit “WR” for zerado, apagaremos o flag

“ESP_FIM_GRV_EEPROM”. Em seguida, iremos zerar o bit “WREN” para desabilitar a gravação

da EEPROM. A seguir, reiniciaremos as variáveis de contagem do tempo e retornaremos:

TESTA_FIM_DA_GRAVACAO

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

BTFSC EECON1,WR ;A GRAVAÇÃO 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 MEMÓRIA

RETURN ;RETORNA DEC_CONT_TEMPO_FIM_ESCRITA

BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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 GRAVAÇÃO DA EEPROM BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA RETURN ;RETORNA

Repare que antes de retornar, selecionamos o banco 0, já que havíamos

selecionado o banco 1 anteriormente. Isso porque, quando o programa retornar, ele irá executar a

subrotina do botão 1, onde é testado um bit do PORTA, que se encontra no banco 0. É claro que

poderíamos ter selecionado o banco 0 no começo subrotina do botão.

Concluída a gravação da EEPROM que apagou a localidade anterior da

unidade, na próxima vez que o programa entrar na rotina de gravação 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 memória EEPROM, juntamente com o código para que ela seja encontrada na

inicialização do programa.

Nesse ponto do programa, O EEADR está com o valor do endereço onde

estava gravada anteriormente a unidade, então, devemos incrementar o EEADR duas vezes para que

ele aponte para o endereço da nova localidade onde iremos gravar a unidade:

Page 129: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

129

GRAVA_A_UNIDADE

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

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, porém, no PIC16F628A, existem somente 128 localidades de memória 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 número binário 01100000 para o W e, depois,

efetuamos a operação lógica OR, entre o W e o EEDATA, através da instrução IORWF, salvando o

resultado no EEDATA:

MOVLW B'01100000' ;W = 01100000 IORWF EEDATA,F ;EEDATA = EEDATA OR 01100000

A operação lógica OR é efetuada bit a bit entre o W, cujo valor é igual ao

número binário 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 número binário 01100000 são iguais a 0, o valor dos bits 0 a 4 do EEDATA

serão 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 são iguais a 0, pois o valor da unidade varia

de 0 a 9 (veja a tabela 1), os bits 5 a 8 do número binário 01100000 serão mantidos.

Dessa forma, após a execução da instrução IORWF, nos bits 0 a 4 do

EEDATA estará o valor da unidade e nos bits 5 a 8 estará o código que identifica a localidade da

memória EEPROM onde estará gravada a unidade.

A seguir, escrevemos a sequência de instruções para a gravação da EEPROM:

BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM BCF INTCON,GIE ;DESABILITA AS INTERRUPÇÕES 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 GRAVAÇÃO BSF INTCON,GIE ;HABILITA INTERRUPÇÕES

A seguir, zeramos o flag “GRAVAR_UNIDADE”, setamos o flag

“ESP_FIM_GRV_EEPROM” e retornamos:

Page 130: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

130

BCF GRAVAR_UNIDADE ;APAGA O FLAG BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAÇÃO BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

RETURN ;RETORNA

Na próxima vez que o programa entrar na subrotina de gravação da EEPROM,

ele irá encontrar o flag “ESP_FIM_GRV_EEPROM” setado e então será desviado para onde está a

label “TESTA_FIM_DA_GRAVACAO”.

Depois que o flag “ESP_FIM_GRV_EEPROM” houver sido apagado, na

próxima vez que o programa entrar na subrotina da gravação 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 gravação do valor da dezena na

localidade de memória EEPROM que vem em seguida àquela onde gravamos a unidade.

Portanto, a primeira instrução que escrevemos é a que incrementa o EEADR:

GRAVA_A_DEZENA

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

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 instruções que realizam a gravação na EEPROM:

BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM BCF INTCON,GIE ;DESABILITA AS INTERRUPÇÕES 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 GRAVAÇÃO BSF INTCON,GIE ;HABILITA INTERRUPÇÕES

Após, 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 GRAVAÇÃO BSF CONF_GRV_EEPROM ;SETA O FLAG PARA CONFERIR A GRAVAÇÃO DA EEPROM BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

RETURN ;RETORNA

Na próxima vez que o programa entrar na subrotina de gravação da EEPROM,

ele irá encontrar o flag “ESP_FIM_GRV_EEPROM” setado e então será desviado para onde está a

label “TESTA_FIM_DA_GRAVACAO”.

Depois que o flag “ESP_FIM_GRV_EEPROM” houver sido apagado, na

próxima vez que o programa entrar na subrotina da gravação da EEPROM, ele irá encontrar o flag

“CONF_GRV_EEPROM” setado e então será desviado para onde está a label

“CONFERE_DEZENA”.

Page 131: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

131

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

EEPROM está correto.

Setamos o bit “RD” e após 1 ciclo de instrução teremos, no EEDATA, o valor

da localidade onde foi gravada a dezena.

CONFERE_DEZENA

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

BSF EECON1,RD ;INICIA LEITURA

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

MOVF DEZENA,W ;W = DEZENA

Em seguida efetuamos a operação lógica XOR entre o W e o registrador

EEDATA, para verificarmos se são 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

Porém, se o bit “Z” estiver zerado, significa que o valor gravado não 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

gravação 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA

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 endereço atual a dezena,

pois acabamos de conferi-la, precisamos decrementá-lo três 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), após decrementá-lo três vezes,

ele irá exibir o valor 254 (1 – 1 = 0; 0 – 1 = 255; 255 – 1 = 254), mas, como só existem 128 localidades de memória

EEPROM no PIC16F628A, o valor do EEADR deve variar entre 0 a 127. Qualquer valor além disso é inválido, pois,

corresponde a uma localidade que não existe na EEPROM. Por esse motivo, após decrementarmos três 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 após ser decrementado três vezes partindo do valor 1 (1 – 1 = 0; 0 – 1 = 127; 127 – 1 = 126).

Page 132: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

132

Pode ser que você esteja se perguntando o que ocorreria se o valor do EEADR fosse 0 ou 2.

Isso não é possível, pois, neste ponto do programa, o EEADR aponta para o endereço

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 gravação do programa no microcontrolador, por

meio da diretiva “DE”. A partir daí, ela sempre será gravada duas localidades após a anterior, na subrotina de

gravação da EEPROM.

Por esse motivo, após 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 próximo ciclo de instrução 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 instrução executada pelo microcontrolador resultou em 0, inclusive a

instrução MOVF.

Não são todas as instruções que afetam o bit Z. No datasheet do

microcontrolador, há uma descrição de todas as instruções e quais bits são 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 gravação 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA

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 endereço onde está atualmente gravada a unidade, testando se o seu valor é

igual a 128, como já fizemos quando gravamos a unidade:

Page 133: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

133

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 conferência do

valor da dezena, com a diferença de que após copiarmos a unidade para o W, inserimos o código nos

bits 5 a 8 do W, com a instrução IORWF, antes de comparar com o registrador EEDATA.

Se a gravação 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 variável LOCAL_DA_UNIDADE, atualizando essa variável e retornamos,

finalizando o processo de gravação.

Mas, se o valor da unidade não 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 gravação 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA

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 MEMÓRIA

RETURN ;RETORNA

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

;*********************************************************************************************** ; PROGRAMA: CONTADOR CRESCENTE E DECRESCENTE

; VERSÃO 1.1

; DESENVOLVIDO POR: MULDER_FOX

; DATA DE CONCLUSÃO: / /

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

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

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

Page 134: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

134

; BITS DE CONFIGURAÇÃO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF &

_LVP_OFF & _CP_OFF & DATA_CP_OFF

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

; INICIALIZAÇÃO DA EEPROM

ORG 2100 ;APONTA PARA O ENDEREÇO 00H DA EEPROM DE B'01100000', .0 ;ESCREVE O NÚMERO BINÁRIO 01100000 NO ENDEREÇO 00H DA EEPROM ;E O NÚMERO 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

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

; VARIÁVEIS

CBLOCK 0X70 ;ENDERECO PRIMEIRA VARIÁVEL

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 BOTÃO 1 DB1_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 1 DB2_BTA ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTÃO 2 DB2_BTB ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTÃO 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 ENDEREÇO 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

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

; SAÍDAS

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

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

Page 135: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

135

; 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 BOTÃO 1 #DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1, AGUARDA SOLTAR O BOTÃO 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 GRAVAÇÃO NA EEPROM #DEFINE CONF_GRV_EEPROM FLAGS,6 ;SE = 1, CONFERE A GRAVAÇÃO NA EEPROM ;***********************************************************************************************

; VETOR DE RESET

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO

GOTO INICIO ;DESVIA PARA INICIO

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

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

Page 136: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

136

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 INTERRUPÇÃO ;***********************************************************************************************

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDAS 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 INTERRUPÇÃO 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

Page 137: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

137

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 VARIÁVEL 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 BOTÃO 1 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_1 ;SIM, APAGA FLAG

TESTA_BOTAO_1 BTFSC BOTAO_1 ;O BOTÃO 1 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_1 ;NÃO, 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 BOTÃO 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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

Page 138: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

138

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 BOTÃO 2 ESTÁ SOLTO? RETURN ;NAO, RETORNA BCF SOLTAR_BOTAO_2 ;SIM, APAGA FLAG

TESTA_BOTAO_2

BTFSC BOTAO_2 ;O BOTÃO 2 ESTÁ PRESSIONADO? GOTO REINC_CONT_DEB_2 ;NÃO, 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 BOTÃO 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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

Page 139: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

139

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 GRAVAÇÃO? 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 MEMÓRIA

MOVF LOCAL_DA_UNIDADE,W ;W = ENDEREÇO 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 INTERRUPÇÕES 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 GRAVAÇÃO BSF INTCON,GIE ;HABILITA INTERRUPÇÕES BCF APAGAR_UNIDADE ;APAGA O FLAG BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAÇÃO BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA RETURN ;RETORNA GRAVA_A_UNIDADE

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

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 INTERRUPÇÕES

Page 140: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

140

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 GRAVAÇÃO BSF INTCON,GIE ;HABILITA INTERRUPÇÕES BCF GRAVAR_UNIDADE ;APAGA O FLAG BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAÇÃO BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

RETURN ;RETORNA

GRAVA_A_DEZENA

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

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 INTERRUPÇÕES 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 GRAVAÇÃO BSF INTCON,GIE ;HABILITA INTERRUPÇÕES BCF GRAVAR_DEZENA ;APAGA O FLAG BSF ESP_FIM_GRV_EEPROM ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAÇÃO BSF CONF_GRV_EEPROM ;SETA O FLAG PARA CONFERIR A GRAVAÇÃO DA EEPROM BANCO_0 ;SELECIONA BANCO 0 DE MEMORIA

RETURN ;RETORNA

TESTA_FIM_DA_GRAVACAO

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA

BTFSC EECON1,WR ;A GRAVAÇÃO 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 MEMÓRIA

RETURN ;RETORNA DEC_CONT_TEMPO_FIM_ESCRITA

BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA 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 GRAVAÇÃO DA UNIDADE

Page 141: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

141

BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO 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 GRAVAÇÃO DA EEPROM BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA RETURN ;RETORNA

CONFERE_DEZENA

BANCO_1 ;SELECIONA O BANCO 1 DE MEMÓRIA 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA 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 GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA

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

Page 142: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

142

BSF APAGAR_UNIDADE ;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE BSF GRAVAR_UNIDADE ;SETA O FLAG PARA GRAVAÇÃO DA UNIDADE BSF GRAVAR_DEZENA ;SETA O FLAG PARA GRAVAÇÃO DA DEZENA BANCO_0 ;SELECIONA O BANCO 0 DE MEMÓRIA

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 MEMÓRIA

RETURN ;RETORNA ;*************************************************************************************************

END ;FIM DO PROGRAMA

Vamos simular a execução 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”. Atenção: A opção é “Add Files to Project” e não “Add New File to Project”.

No menu “Project”, clique em “Build All”.

Na janela “Output”, verifique se a mensagem “BUILD SUCCEEDED” foi

exibida. Caso contrário, 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 número binário 01100000, enquanto a localidade 01

está com o número 00. O MPLAB escreveu esses valores ao executar a diretiva “DE” constante no

programa:

Page 143: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

143

Figura 1

No “Watch”, no botão “ADD SFR”, inclua os registradores EECON1,

EEADR, EEDATA e WREG.

Na barra de ferramentas do simulador, clique no botão “Reset”. Em seguida,

vá clicando no botão “Step Into”.

Quando chegar em “Inicialização das Variáveis”, clique nos botões do

“Stimulus” que fixam o RA0 e o RA1 em nível alto (“Set High”) para simular que os botões 1 e 2

estão soltos.

Durante a inicialização das variáveis, acompanhe, no “Watch”, os valores dos

registradores EECON1, EEADR, EEDATA e W, conforme as instruções vão sendo executadas.

Vamos medir o tempo de espera pela conclusão da gravação 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 gravação é iniciada.

Para podermos medir esse tempo, vamos fazer uma alteração 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 não

mudará.

Após essa alteração, monte o projeto novamente, clicando em “Build All”, no

menu “Project”.

Clique no botão “Reset” do simulador e depois vá clicando no botão “Step

Into” até chegar à inicialização das variáveis.

Page 144: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

144

No “Stimulus”, clique nos botões que fixam o RA0 e o RA1 em nível alto

para simular que os botões estão soltos.

Continue clicando em “Step Into” até chegar à subrotina de gravação da

EEPROM.

Em “TESTA_FIM_DA_GRAVACAO”, insira um “breakpoint” na linha que

contém a instrução BCF ESP_FIM_GRV_EEPROM, dando um duplo clique nessa linha.

Quando o programa for executar essa instrução, 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 botão “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

variável “ESC_EEPROM_B” chegasse a 0:

Page 145: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

145

Figura 3

Vamos diminuir esse tempo, alterando o valor de inicialização dessa variável

para 1 na seção “Constantes”, em “INI_ESC_EEPROM_B”.

Após essa alteração, monte o projeto novamente, clicando em “Build All”, no

menu “Project”.

Clique no botão “Reset” do simulador e depois vá clicando no botão “Step

Into” até chegar à inicialização das variáveis.

No “Stimulus”, clique nos botões que fixam o RA0 e o RA1 em nível alto

para simular que os botões estão soltos.

Continue clicando em “Step Into” até chegar à subrotina de gravação 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 botão “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:

Page 146: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

146

Figura 4

Podemos deixar este tempo pois, está bem próximo dos 10 milissegundos que

pretendíamos.

Vamos desfazer a alteração feita em “TESTA_FIM_DA_GRAVACAO”,

voltando a instrução para: BTFSC EECON1,WR.

Após isso, monte o projeto novamente, clicando em “Build All”, no menu

“Project”.

Clique no botão “Reset” do simulador e depois vá clicando no botão “Step

Into” até chegar à inicialização das variáveis.

No “Stimulus”, clique nos botões que fixam o RA0 e o RA1 em nível alto

para simular que os botões estão soltos.

No menu “Debugger”, clique em “Breakpoints”. Na janela que se abre, clique

em “Remove All”.

Posicione as janelas para que possa clicar nos botões do “Stimulus” enquanto

observa os valores dos registradores no “Watch”.

Clique no botão “Run” do simulador.

No “Stimulus”, clique no botão que simula que o botão 1 foi pressionado e

solto (RA0 “Pulse Low”).

No “Watch” repare que o valor da unidade foi incrementado.

Clique no botão “Halt” do simulador.

No menu “Window”, selecione a janela “EEPROM”. Se ela não estiver na

lista, clique em “EEPROM” no menu “View” para exibi-la.

Page 147: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

147

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

corresponde em binário a 01100001, que contém o valor da unidade (1) nos bits 0 a 4 e o código nos

bits 5 a 8. A próxima localidade está com o valor 0 que corresponde ao valor da dezena:

Figura 5

Clique no botão “Run” do simulador e em seguida incremente novamente o

contador, clicando no botão do “Stimulus”.

Clique no botão “Halt” do simulador.

Na janela “EEPROM”, repare que a localidade 04 está com o valor 62

hexadecimal, que corresponde em binário a 01100010, que contém o valor da unidade (2) nos bits 0 a

4 e o código nos bits 5 a 8. A próxima localidade está com o valor 0 da dezena. Repare, também que a

localidade 02 foi zerada. Lembre-se que a localidade anterior da dezena não é apagado, pois não é

necessário:

Page 148: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 6 – Contador II

148

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 são salvos em duas novas

localidades da memória 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 próxima, utilizaremos o PIC16F628A

para gerar um sinal PWM para controlar o brilho de um LED utilizando dois botões. Um dos botões

fará o brilho aumentar até o máximo enquanto o outro o fará diminuir até o LED apagar.

Até lá!

Page 149: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

149

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 botões: 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

Page 150: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

150

Chamaremos o tempo durante o qual a tensão é máxima 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 frequência do sinal. A partir de uma determinada frequência, teremos a impressão de que ele está

permanentemente aceso, devido ao fenômeno da persistência da visão. Se reduzirmos o tempo de

duração do semiciclo ativo, mantendo o do ciclo, conforme figura abaixo, teremos a impressão 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 duração do semiciclo ativo,

mantendo o do ciclo, conforme figura abaixo, teremos a impressão de que o brilho do LED aumentou.

Figura 4

Como você pode observar, o tempo de duração do ciclo do sinal não muda,

portanto a frequência do sinal PWM, que é igual ao inverso do valor do tempo de duração do ciclo,

não muda. O que irá mudar é o tempo de duração do semiciclo ativo, isto é, o tempo em que o sinal

ficará em nível alto.

Page 151: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

151

Para que não se perceba que o LED está piscando, temos de escolher uma

frequência 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 diferença do Timer 1 em relação 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 são o TMR1L e o TMR1H.

Quando o Timer 1 é incrementado, esse incremento ocorre no TMR1L que

pode ir até o valor 255. No próximo 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 instrução 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 frequência de 32.768 KHz, ideal para relógios.

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, é constituído de apenas um registrador de 8

bits, o TMR2 e, portanto, seu valor pode ser incrementado até 255, porém, somente é possível

incrementá-lo a partir do ciclo de instrução, não sendo possível incrementá-lo a partir de um sinal

externo.

O Timer 2 possui algumas características 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 próximo 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 próximo 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 instrução 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 número de vezes que o TMR2 deverá estourar para gerar uma interrupção. Por

exemplo, se ele estiver configurado para 1:1, a cada vez que o TMR2 estourar, o flag TMR2IF será

setado, gerando uma interrupção (desde que ela esteja habilitada). Já, se o Postscaler estiver

configurado, por exemplo, para 1:5, uma interrupção será gerada a cada 5 estouros do TMR2.

As configurações do Prescaler e do Postscaler são feitas no registrador

T2CON, onde também há um bit para ligar e desligar o Timer 2.

É no módulo CCP do PIC16F628A que é gerado o sinal PWM. A

configuração do módulo CCP é feita no registrador CCP1CON. Devemos setar os bits 3 e 2 desse

registrador para habilitar o modo PWM.

Page 152: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

152

O ciclo do sinal PWM reinicia toda vez que o TMR2 estoura. A fórmula para

o cálculo do tempo de duração do ciclo do sinal PWM é esta:

Ciclo = (PR2 + 1) x ciclo de instrução x prescaler do TMR2

É fácil entender essa fórmula, considerando que:

O ciclo termina (e um novo inicia) quando o TMR2 estoura.

O TMR2 estoura no próximo incremento após seu valor se igualar ao PR2

(PR2 +1)

O TMR2 é incrementado pelo ciclo de instrução.

O prescaler define de quantos em quantos ciclos de instrução o TMR2 será

incrementado.

No nosso caso, queremos um sinal PWM com uma frequência 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 instrução tem a duração 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 fórmula com o valor do prescaler em 1:1:

Ciclo = (PR2 + 1) x ciclo de instrução 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 máximo 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 instrução 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, então, aumen-

tar o valor do prescaler para 1:16:

Ciclo = (PR2 + 1) x ciclo de instrução 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

Page 153: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

153

O valor a ser escrito no PR2 continua acima de 255. Isto mostra que não é

possível obter um sinal PWM de 75 Hz se a frequência de oscilação do microcontrolador é de 4 MHz.

Teríamos de diminuir a frequência do oscilador se quiséssemos um sinal PWM de 75 Hz. Poderíamos

fazer isso alterando a frequência do oscilador interno para 48 KHz ou então usando um cristal externo.

Escrevendo no PR2 o seu valor máximo (255) e configurando o prescaler

também para seu valor máximo (16), obtemos a máxima duração do ciclo do sinal PWM para uma

frequência de oscilação de 4 MHz:

Ciclo = (PR2 + 1) x ciclo de instrução 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 duração do ciclo corresponde à frequência de 244 Hz

(1/0,0049096). No nosso circuito, precisamos que o sinal PWM tenha uma frequência maior do que

75 Hz para evitar que se perceba que o LED está piscando. Sendo assim, podemos usar a frequência

de 244 Hz, até mesmo porque o LED pode operar em frequências bem maiores que esta.

Vimos como definir a duração do ciclo do sinal PWM. Vamos ver agora como

se define o tempo de duração do semiciclo ativo. O semiciclo ativo começa junto com o ciclo e ter-

mina quando o sinal vai para nível baixo.

O sinal PWM do PIC16F628A pode ter uma resolução de até 10 bits, depen-

dendo da frequência do próprio sinal e da frequência de oscilação. Uma resolução de 10 bits significa

que podemos definir 1024 (210

) tempos de duração diferentes para o semiciclo ativo.

No nosso caso, o tempo de duração do ciclo é de 4,096 milissegundos. Divi-

dindo este valor por 1024, concluímos que podemos variar o tempo de duração do semiciclo ativo em

passos de 0,004 milissegundo desde o mínimo de 0,004 milissegundo até o máximo de 4,092 milisse-

gundos.

Para definirmos o tempo de duração do semiciclo ativo, escrevemos um valor

entre 0 e 1024 na combinação de 10 bits formada pelo registrador CCPR1L e os bits 5 e 4 do registra-

dor CCP1CON. Nessa combinação, 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

CCPR1L CCP1CON

Bit 5

CCP1CON

Bit 4

Tabela 1

Se escrevermos o valor 0, o sinal ficará o tempo todo em nível baixo. Se es-

crevermos o valor 1024, ele ficará o tempo todo em nível alto. Nesses casos, não teremos um sinal

PWM.

Se escrevermos o valor 1, o semiciclo terá a duração mínima (0,004 milisse-

gundo) e, se escrevermos o valor 1023, a máxima (4,092 milissegundos).

Vamos supor que queiramos que o tempo de duração do semiciclo ativo seja

de 10% do tempo de duração do ciclo. Nesse caso, temos de escrever o valor 102,4 (10% de 1024)

nos 10 bits da referida combinação.

Como o número a ser escrito tem de ser inteiro, arredondamos para 102, que,

em binário, é igual a 1100110. Portanto:

Page 154: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

154

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

CCPR1L CCP1CON

Bit 5

CCP1CON

Bit 4

Tabela 2

Ou seja, temos de escrever o número binário 00011001 no registrador

CCPR1L, setar o bit 5 e zerar o bit 4 do registrador CCP1CON.

Uma outra combinação de 10 bits formada pelo registrador TMR2 e dois bits

do oscilador interno do microcontrolador é incrementada a cada ciclo do oscilador. Quando as duas

combinações se igualam o semiciclo ativo termina, isto é, o sinal PWM vai para nível baixo.

Se você preferir, pode usar a seguinte fórmula para o cálculo do tempo de du-

ração do semiciclo ativo:

Semiciclo ativo = (CCPR1L:CCP1CON<5:4>) x ciclo de oscilação x prescaler do TMR2

Nessa fórmula, (CCPR1L:CCP1CON<5:4>) é o valor de 0 a 1024 a ser es-

crito na combinação de 10 bits formada pelo registrador CCPR1L e os bits 5 e 4 do CCP1CON; ciclo

de oscilação é o tempo de duração de um ciclo do oscilador do microcontrolador, que, no nosso caso

é igual a 0,00000025 segundo (1/4000000).

Vamos aplicar a fórmula para o exemplo dos 10% que demos acima, onde a

duração do semiciclo ativo é de 10% do ciclo, ou seja, 0,0004096 segundo:

Semiciclo ativo = (CCPR1L:CCP1CON<5:4>) x ciclo de oscilação 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 havíamos encontrado quando dividimos o nú-

mero 1024 por 10.

A figura abaixo mostra os eventos que provocam o reinício do ciclo e o fim

do semiciclo ativo do sinal PWM.

Page 155: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

155

Figura 5

No nosso circuito, quando o botão 1 for pressionado, o brilho do LED irá au-

mentar até o máximo e, quando o botão 2 for pressionado, o brilho irá diminuir até o LED apagar.

Com o LED apagado, o botão 1 deverá ficar pressionado por cerca de 5 se-

gundos para que o brilho atinja o máximo. Esse também será o tempo que o botão 2 deverá ser man-

tido pressionado para que o LED apague, partindo do brilho máximo.

Como vimos, é possível definir 1024 valores diferentes para o tempo de dura-

ção do semiciclo ativo do sinal PWM, escrevendo na combinação de 10 bits, um valor entre 0 e 1024.

Não precisamos de uma resolução tão alta. Se modificarmos apenas o valor do

registrador CCPR1L, já teremos 256 valores diferentes, o que é mais do que suficiente para uma vari-

ação 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 interrupção a cada

cerca de 19 milissegundos. Na rotina da interrupção, iremos verificar qual botão está pressionado. Se

for o botão 1, iremos incrementar o registrador CCPR1L. Se for o botão 2 decrementaremos o

CCPR1L. Se nenhum botão estiver pressionado, manteremos o valor do CCPR1L.

Para configurarmos o Timer 0 a fim de que ele provoque uma interrupção a

cada 19 milissegundos, primeiramente dividimos 19 milissegundos pelo tempo de duração de um

ciclo de instrução, que é de 1 microssegundo: 0,019 / 0,000001 = 19.000.

Isto significa que 19 milissegundos equivalem a 19.000 ciclos de instrução, ou

seja, o registrador TMR0 deverá estourar a cada 19.000 ciclos de instrução. Como o registrador

TMR0 estoura a cada 256 incrementos, se fizéssemos o valor do prescaler igual a 1:1, onde, o TMR0

é incrementado a cada ciclo de instrução, ele iria estoura a cada 256 ciclos de instrução apenas. Então,

precisamos aumentar o valor do prescaler para que ele estoure a cada 19.000 ciclos de instrução.

Page 156: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

156

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, não há como definir ele para 1:74. Nesse caso, vamos adotar o valor maior

mais próximo, que é 1:128.

Se o valor do prescaler é de 1:128, o TMR0 será incrementado a cada 128 ci-

clos de instrução, estourando a cada: 256 x 128 = 32.768 ciclos de instrução, porém queremos que ele

estoure a cada 19.000 ciclos de instrução.

Para resolver isso, a cada vez que o TMR0 estourar (seu valor passar de 255

para 0, gerando uma interrupção), 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, subtraímos esse número 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 começa 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 instrução. Esse valor é o mais próximo 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 alteração é na seção “VARIÁVEIS”. Exclua essa seção. Isso mes-

mo, não precisaremos de nenhuma variável neste programa!

Exclua também a seção “CONSTANTES”.

Renomeie a seção “SAÍDA” 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 interrupção, a primeira instrução será BTFSS INTCON,T0IF

portanto, exclua as anteriores a ela. Essa instrução testa se a interrupção foi a do Timer 0. Caso não

tenha sido, a instrução da próxima linha será executada, onde saímos da interrupção. Se a interrupção

foi do Timer 0, apagamos o flag na linha seguinte:

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

BTFSS INTCON,T0IF ;TMR0 ESTOUROU?

RETFIE ;NAO, SAI DA INTERRUPÇÃO

BCF INTCON,T0IF ;SIM, APAGA O FLAG

A seguir, escrevemos o número 108 no registrador TMR0:

MOVLW .108 ;W = 108

MOVWF TMR0 ;REINICIA TMR0

Page 157: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

157

Agora, testamos se o botão 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 contrário, testamos se o botão 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 botão 2 não estiver pressionado, saímos da interrupção:

RETFIE ;NAO, SAI DA INTERRUPÇÃO

Em “INCREMENTA_CCPR1L”, primeiramente testamos se o valor do

CCPR1L é igual a 255, pois, se for, iremos sair da interrupção sem incrementá-lo, caso contrário seu

valor passaria para 0, apagando o LED e queremos que quando o brilho do LED chegar ao máximo,

fique no máximo:

INCREMENTA_CCPR1L

MOVLW .255 ;W = 255

XORWF CCPR1L,W ;W = W XOR CCPRR1L

BTFSC STATUS,Z ;CCPR1L = 255?

RETFIE ;SIM, SAI DA INTERRUPÇÃO

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

saímos da interrupção:

INCF CCPR1L,F ;NAO, INCREMENTA CCPR1L

RETFIE ;SAI DA INTERRUPÇÃO

Em “DECREMENTA_CCPR1L”, primeiramente testamos se o valor do

CCPR1L é igual a 0, pois, se for, iremos sair da interrupção sem decrementá-lo, caso contrário seu

valor passaria para 255, acendendo o LED no máximo 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 INTERRUPÇÃO DECF CCPR1L,F ;NAO, DECREMENTA CCPR1L

RETFIE ;SAI DA INTERRUPÇÃO

Com isso concluímos a rotina de interrupção.

Na seção “CONFIGURACAO DOS REGISTRADORES DE USO

ESPECÍFICO”, vamos configurar o registrador OPTION_REG, para que o Timer 0 seja

incrementado pelo ciclo de instrução (bit 5 = 0), com prescaler de 1:128 (bits 3:0 = 0110):

Page 158: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

158

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

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 também 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 saída, pois é a

saída do sinal PWM, e os demais como entradas: MOVLW B'11110111' ;W = B'11110111'

MOVWF TRISB ;CONFIGURA BR3/CCP1 COMO SAÍDA E DEMAIS COMO ENTRADA

A seguir, escrevemos o número 255 no registrador PR2:

MOVLW .255 ;W = 255

MOVWF PR2 ;PR2 = 255

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

configurações do CMCON para que os pinos RA0 e RA1 possam ser usados como pinos de entrada, e

do INTCON para que a interrupção 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 INTERRUPÇÃO 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:

Page 159: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

159

MOVLW B'00001100' ;W = B'00001100'

MOVWF CCP1CON ;HABILITA MODO PWM DO MODULO CCP

Com isso, concluímos a configuração dos registradores de uso específico.

Em seguida, exclua a seção “INICIALIZAÇÃO DAS VARIÁVEIS”.

A seguir vem a rotina principal. Vamos chamar esta parte do programa de

“ROTINA PARA AGUARDAR A INTERRUPÇÃO”, afinal, não tem sentido chamá-la de principal,

já que a rotina mais importante deste programa é a de interrupção.

Aqui o programa ficará executando a instrução CLRWDT até que ocorra a

interrupção:

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

;ROTINA PARA AGUARDAR A INTERRUPÇÃO

CLRWDT ;LIMPA O WDT GOTO $-1 ;RETORNA UMA LINHA

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

O programa está pronto, tendo ficado assm:

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

; PROGRAMA: DIMMER PARA 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

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

; ENTRADAS

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

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

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

Page 160: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

160

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

; VETOR DE RESET

ORG 0X00 ;ENDERECO INICIAL DE PROCESSAMENTO

GOTO INICIO ;DESVIA PARA INICIO

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

; ROTINA DE INTERRUPÇÃO

ORG 0X04 ;VETOR DAS INTERRUPÇÕES

BTFSS INTCON,T0IF ;TMR0 ESTOUROU?

RETFIE ;NAO, SAI DA INTERRUPÇÃO

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 INTERRUPÇÃO

INCREMENTA_CCPR1L

MOVLW .255 ;W = 255

XORWF CCPR1L,W ;W = W XOR CCPRR1L

BTFSC STATUS,Z ;CCPR1L = 255?

RETFIE ;SIM, SAI DA INTERRUPÇÃO INCF CCPR1L,F ;NAO, INCREMENTA CCPR1L

RETFIE ;SAI DA INTERRUPÇÃO

DECREMENTA_CCPR1L MOVLW .0 ;W = 0

XORWF CCPR1L,W ;W = W XOR CCPRR1L

BTFSC STATUS,Z ;CCPR1L = 0?

RETFIE ;SIM, SAI DA INTERRUPÇÃO DECF CCPR1L,F ;NAO, DECREMENTA CCPR1L

RETFIE ;SAI DA INTERRUPÇÃO

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

; CONFIGURACAO DOS REGISTRADORES DE USO ESPECÍFICO

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 SAÍDA 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 INTERRUPÇÃO DO TIMER 0

MOVLW B'00000110'

Page 161: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

161

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 INTERRUPÇÃO

CLRWDT ;LIMPA O WDT

GOTO $-1 ;RETORNA UMA LINHA

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

END ;FIM DO PROGRAMA

Vamos simular a execução do programa.

No MPLAB, no menu “Project”, clique em “Project Wizard...”.

Na janela “Welcome”, clique em “Avançar”.

Na janela “Step One”, selecione o PIC16F628A e clique em “Avançar”.

Na janela “Step Two”, clique em “Avançar”.

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 “Avançar”.

Na janela “Step Four”, selecione o arquivo Dimmer para LED.asm, clique em

“Add” e depois clique em “Avançar”.

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 não, 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 botão “Add SFR” e depois clicando nesse botão.

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 operação 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 próxima página.

Clique em “Save”. Escreva o nome Dimmer para LED e clique em “Salvar”.

Page 162: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

162

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 botão “Reset”.

Vá clicando no botão “Step Into” até chegar na instrução CLRWDT.

Selecione a janela do “Stimulus” no menu “Window”. Na coluna “Fire”,

clique nos botões da primeira e terceira linhas para levar os pinos RA0 e RA1 para nível alto,

simulando que os botões estão soltos.

Vamos medir o tempo entre uma interrupção e outra.

Volte para a janela do programa.

Insira um “breakpoint” na primeira instrução da rotina de interrupção, dando

um duplo clique na sua linha.

Clique no botão “Run” do simulador. O programa irá parar no “breakpoint”.

No menu “Debugger”, clique em “StopWatch”. Clique em “Zero”.

Clique novamente no botão “Run”. Quando o programa parar no “breakpoint”

novamente, volte para a janela do “Stopwatch” e repare que o tempo entre uma interrupção e outra é

de cerca de 19 milissegundos, conforme queríamos:

Page 163: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

163

Figura 7

Agora vamos ver se o CCPR1L está sendo incrementado e decrementado

pelos botões.

Remova o “breakpoint”, dando outro duplo clique na linha da primeira

instrução da interrupção.

Posicione as janelas de forma a poder visualizar a janela “Watch” enquanto

clica nos botões do “Stimulus”:

Page 164: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

164

Figura 8

Clique no botão “Run” do simulador.

No “Stimulus”, clique no botão da coluna “Fire” que leva o pino RA0 para

nível baixo (Set Low) para simular que o botão 1 foi pressionado.

Observe que o CCPR1L foi incrementado até o valor 255.

Agora, clique no botão que leva o pino RA0 para o nível alto, para simular

que o botão 1 foi solto.

Em seguida, clique no botão que leva o pino RA1 para nível 0, simulando que

o botão 2 foi pressionado.

Observe que o CCPR1L foi decrementado até o valor 0 e lá ficou.

Volte o pino RA1 para nível alto, clicando no botão da terceira linha do

Stimulus.

Vamos medir o tempo que o botão 1 deve ficar pressionado para o CCPR1L ir

de 0 até 255.

Clique no botão “Halt” do simulador.

Insira um “breakpoint” na linha que contem a instrução RETFIE, que é

executada quando o valor do CCPR1L for igual a 255:

Page 165: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

165

Figura 9

Na janela do “Stopwatch”, clique em “Zero”.

Clique no botão que leva o pino RA0 para nível baixo simulando que o botão

1 foi pressionado.

Clique no botão “Run” do simulador.

Quando o programa parar no “breakpoint”, veja, no “Stopwatch” que

transcorreu 4,84 segundos, conforme havíamos projetado:

Page 166: Tutorial de Programação Assembly para Microcontroladores PIC - Partes 1 a 7

Tutorial de Programação Assembly para Microcontroladores PIC - Parte 7 – Dimmer para LED

166

Figura 10

Remova o “breakpoint”.

Clique no botão “Run” do simulador.

No “Stimulus”, volte o pino RA0 para nível alto.

Repare que, quando o valor do CCPR1L é igual a 255, o pino RB3 fica fixo

em nível alto. Por outro lado, quando o valor do CCPR1L é igual a 0, ele fica fixo em nível baixo.

Com o valor do CCPR1L num ponto intermediário, 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 sólido, ligado no pino RB3 podemos controlar

equipamentos de maior potência, como por exemplo, lâmpadas incandescentes, aquecedores, motores

elétricos, etc.

Aqui termina esta parte do tutorial. Espero que tenha sido útil para você. Na

próxima parte iremos desenvolver um frequencímetro. Até lá!