You are on page 1of 204

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

Figura 1

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 2

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Configurao dos registradores

Inicializao das variveis

Passou 0,5 segundo?

no

sim

Acende LED no

LED est aceso? sim

Apaga LED

Indica o incio

Indica uma subrotina

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Indica uma deciso

Indica acesso a um dispositivo de I/O

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

Figura 3

Primeiramente vamos criar um cabealho onde ir constar o nome do programa, sua verso, o nome do autor e a data de concluso, ficando assim:

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

DATA_CP um recurso para proteger a memria de dados contra cpia. CP um recurso para proteger a memria de programa contra cpias. Estes recursos interessam a quem fabrica aparelhos eletrnicos e quer evitar engenharia reversa. Estes recursos no nos interessam, e, por isso, escrevemos _CP_OFF & DATA_CP_OFF. O prximo passo definir as labels para a comutao dos bancos de memria de dados. Fazemos isto utilizando a diretiva #DEFINE desta forma:
;********************************************************************************************** ; PAGINACAO DE MEMORIA #DEFINE BANCO_0 #DEFINE BANCO_1 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 4 O prximo passo definir as variveis que iremos utilizar em nosso programa. Uma varivel um Registrador de Uso Geral, ou seja, uma das posies da memria de dados que podemos usar para armazenar os valores dos dados que vamos manipular no nosso programa. medida que vamos escrevendo o programa, vamos precisando criar 8

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

variveis. Por esse motivo, minha forma preferida para defini-las com o uso da diretiva CBLOCK:
;********************************************************************************************** ; VARIAVEIS CBLOCK 0X20 DELAY_0 DELAY_1 DELAY_2 ENDC ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;FIM DO BLOCO DE MEMORIA

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

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

10

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

INICIO

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

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

11

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Em outra parte deste tutorial falaremos detalhadamente sobre interrupes. O prximo passo configurar os Registradores de Uso Especfico.
;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF B'00000111' CMCON B'11111110' TRISA B'11111111' TRISB ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11111110' ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS ;TODOS OS PINOS DO PORTB COMO ENTRADAS ;SELECIONA BANCO 0 DE MEMORIA

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

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

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

13

Tutorial de Programao Assembly para Microcontroladores PIC MOVWF CMCON

Parte 1 Pisca LED

So apenas esses os Registradores de Uso Especfico que precisamos configurar nesse programa. O prximo passo inicializar as variveis.
;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF INI_DELAY_0 DELAY_0 INI_DELAY_1 DELAY_1 INI_DELAY_2 DELAY_2 ;W = INI_DELAY_0 ;INICIALIZA DELAY_0 ;W = INI_DELAY_1 ;INICIALIZA DELAY_1 ;W = INI_DELAY_2 ;INICIALIZA DELAY_2

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Aps reinicializar DELAY_0, vamos decrementar DELAY_1 e testar se seu valor chegou a 0:
DECFSZ DELAY_1,F

Se o seu valor no for igual a 0, o programa dever voltar para decrementar DELAY_0 e por isto, usamos a mesma instruo de antes:
GOTO PRINCIPAL

15

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Porm, se o valor de DELAY_1 chegou a 0, reiniciaremos DELAY_1 e iremos decrementar DELAY_2 e testar se o seu valor chegou a 0:
MOVLW MOVWF DECFSZ INI_DELAY_1 DELAY_1 DELAY_2,F

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


GOTO PRINCIPAL

Mas, se DELAY_2 chegou a 0, iremos reinici-la e ter terminado a contagem do tempo:


MOVLW MOVWF INI_DELAY_2 DELAY_2

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

16

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

Com isso acendemos o LED. Ento, este trecho do nosso programa ficou assim:
BTFSS BSF BCF LED LED LED ;testa o valor do bit 0 do PORTA ;valor = 0, acende o LED ;valor = 1, apaga o LED

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

17

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Faremos assim:
BTFSS GOTO BCF GOTO LED ACENDE_LED LED PRINCIPAL ;testa o valor do bit 0 do PORTA ;valor = 0, desvia ;valor = 1, apaga o LED ;desvia

ACENDE_LED BSF LED GOTO PRINCIPAL END

;ACENDE O LED ;desvia ;Fim do programa

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

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

18

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

;
CBLOCK 0X20 DELAY_0 DELAY_1 DELAY_2 ENDC

VARIAVEIS ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;USADO PARA GERAR O TEMPO DE 0,5 SEGUNDO ;FIM DO BLOCO DE MEMORIA

;********************************************************************************************** ; CONSTANTES INI_DELAY_0 INI_DELAY_1 INI_DELAY_2 EQU .255 EQU .50 EQU .13 ;VALOR QUE DELAY_0 INICIA ;VALOR QUE DELAY_1 INICIA ;VALOR QUE DELAY_2 INICIA

;*********************************************************************************************** ; SADA #DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG 0X04 RETFIE ;VETOR DAS INTERRUPES ;RETORNA

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11111110' ;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS ;TODOS OS PINOS DO PORTB COMO ENTRADAS ;SELECIONA BANCO 0 DE MEMORIA ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

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

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

19

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

;********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF INI_DELAY_0 DELAY_0 INI_DELAY_1 DELAY_1 INI_DELAY_2 DELAY_2 ;W = INI_DELAY_0 ;INICIALIZA DELAY_0 ;W = INI_DELAY_1 ;INICIALIZA DELAY_1 ;W = INI_DELAY_2 ;INICIALIZA DELAY_2

;*********************************************************************************************** PRINCIPAL CLRWDT DECFSZ GOTO MOVLW MOVWF DECFSZ GOTO MOVLW MOVWF DECFSZ GOTO MOVLW MOVWF BTFSS GOTO BCF GOTO ACENDE_LED BSF GOTO ;ROTINA PRINCIPAL DO PROGRAMA ;LIMPA O WDT ;DECREMENTA DELAY_0. DELAY_0 = 0? ;NO ;SIM, W = INI_DELAY_0 ;REINICIALIZA DELAY_0 ;DECREMENTA DELAY_1. DELAY_1 = 0? ;NO ;SIM, W = INI_DELAY_1 ;REINICIALIZA DELAY_1 ;DECREMENTA DELAY_2. DELAY_2 = 0? ;NO ;SIM, W = INI_DELAY_2 ;REINICIALIZA DELAY_2 ;TESTA O VALOR DO BIT 0 DO PORTA ;VALOR = 0, DESVIA ;VALOR = 1, APAGA O LED ;DESVIA ;ACENDE O LED ;DESVIA

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

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

Nosso prximo passo simular a execuo do programa para ver se ele se comporta como esperamos. No menu Project, clique em Project Wizard. Na janela que se abre clique em Avanar:

20

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 6

21

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

Figura 8

Na janela que se abre, escolha um local e d um nome para o projeto, por exemplo Pisca LED e clique em Salvar:

22

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 9

Em seguida clique em Avanar

Figura 10

23

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na janela seguinte (Step Four), selecione o arquivo Pisca LED.asm, clique em Add e em seguida clique em Avanar:

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

Figura 12

24

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 13 A seguir, expanda a janela chamada Output:

25

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

26

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Na janela Watch, clique onde est indicado na figura abaixo, selecione o PORTA e clique em Add SFR:

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

Figura 16

27

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Em Add SFR adicionamos os Registradores de Uso Especfico que queremos visualizar, enquanto em Add Symbol adicionamos as variveis por ns criadas que queremos visualizar. No menu Window, clique em Pisca LED.asm:

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

28

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 19

29

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

30

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

31

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 21

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

32

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

33

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 23

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

34

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 24

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

35

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 26 36

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Vamos experimentar diminuir o valor da varivel DELAY_0 para 254. Agora, o tempo de praticamente 500 milissegundos.

Figura 27

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

37

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

38

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

Figura 29

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

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

39

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

Figura 35

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

42

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 1 Pisca LED

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

43

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

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

44

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

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

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

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

Para no ter de escrever tudo de novo, no MPLAB, abra o arquivo Pisca LED.asm e, no menu File, clique em Save As... e mude o nome do arquivo para Pisca LED II.asm e v fazendo as alteraes. O prximo passo do programa a definio das variveis. Iremos utilizar apenas uma varivel, que ser usada para contar os estouros do TMR0. Vamos nome-la de CONT_EST_TMR0:
;********************************************************************************************** ; VARIVEIS CBLOCK 0X20 ;ENDERECO INICIAL DA MEMORIA DO USUARIO

45

Tutorial de Programao Assembly para Microcontroladores PIC CONT_EST_TMR0 ENDC

Parte 2 Pisca LED II

;USADO PARA CONTAR OS ESTOUROS DO TMR0 ;FIM DO BLOCO DE MEMORIA

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

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

;*********************************************************************************************** ; SADA #DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG 0X04 RETFIE ;VETOR DAS INTERRUPES ;RETORNA

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

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

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

46

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

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

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

;TODOS OS PINOS DO PORTB COMO ENTRADAS ;SELECIONA BANCO 0 DE MEMORIA ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;*********************************************************************************************** ; INICIALIZACAO DA VARIAVEL MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0

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

A primeira instruo da rotina principal CLRWDT para limpar o WDT. A seguir, iremos testar o bit T0IF do registrador INTCON para verificarmos se o TMR0 estourou:
BTFSS INTCON,TOIF ;TMR0 ESTOUROU?

Se o TMR0 no houver estourado, o valor desse bit ser igual a 0 e a prxima linha do programa ser executada. Portanto, nessa linha escreveremos a instruo GOTO PRINCIPAL, para que o bit seja testado novamente.
GOTO PRINCIPAL ;NAO

Se o TMR0 houver estourado, o valor do bit ser igual a 1 e a linha com a instruo GOTO PRINCIPAL ser pulada. Nesse caso, a primeira providncia que iremos tomar zerar o bit TOIF para que na prxima vez que o TMR0 estourar possamos detectar a mudana do seu valor para 1:
BCF INTCON,T0IF ;SIM

A seguir, iremos reiniciar o TMR0 com o valor 131, usando a constante que criamos:
MOVLW MOVWF INI_TMR0 TMR0 ;W = INI_TMR0 ;REINICIA TMR0

Em seguida, decrementamos o valor da varivel e ao mesmo tempo verificamos se o seu valor chegou a 0:
DECFSZ CONT_EST_TMR0,F
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

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

47

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

Se o valor da varivel houver chegado a 0, iremos reinici-la e, nesse caso, tero se passado cerca de 500 milissegundos. A partir daqui, o resto da rotina igual ao do programa da parte I deste tutorial. Portanto, o programa ficou assim:
;*********************************************************************************************** ; PROGRAMA: PISCA LED II ; VERSO 1.0 ; DESENVOLVIDO POR: MULDER_FOX ; DATA DE CONCLUSO: / / ;*********************************************************************************************** #INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

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

;********************************************************************************************** ; VARIVEIS CBLOCK 0X20 CONT_EST_TMR0 ENDC ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADO PARA CONTAR OS ESTOUROS DO TMR0 ;FIM DO BLOCO DE MEMORIA

;********************************************************************************************** ; CONSTANTES INI_TMR0 INI_CONT_EST_TMR0 EQU .131 EQU .125 ;VALOR QUE TMR0 INICIA ;VALOR QUE CONT_EST_TMR0 INICIA

;*********************************************************************************************** ; SADA #DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG 0X04 RETFIE ;VETOR DAS INTERRUPES ;RETORNA

48

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32

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

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

;TODOS OS PINOS DO PORTB COMO ENTRADAS ;SELECIONA BANCO 0 DE MEMORIA ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

;*********************************************************************************************** ; INICIALIZACAO DA VARIAVEL MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0

;*********************************************************************************************** PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA CLRWDT BTFSS GOTO BCF MOVLW MOVWF DECFSZ GOTO MOVLW MOVWF BTFSS GOTO BCF GOTO ACENDE_LED BSF GOTO ;LIMPA O WDT ;TMR0 ESTOUROU? ;NAO ;SIM ;W = INI_TMR0 ;REINICIA TMR0 ;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0? ;NAO ;SIM, W = INI_CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0 ;TESTA O VALOR DO BIT 0 DO PORTA ;VALOR = 0, DESVIA ;VALOR = 1, APAGA O LED ;DESVIA ;ACENDE O LED ;DESVIA

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

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

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

49

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

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

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

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

V para a janela do Stop Watch e veja que demorou 505 milissegundos para o programa chegar neste ponto, ou seja, a cada 505 milissegundos o LED ser testado e mudar de estado.

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

Figura 4

Como a diferena menor, ficaremos com esse valor. 51

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 2 Pisca LED II

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

52

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

;*********************************************************************************************** ; PROGRAMA: PISCA LED III ; VERSO 1.0 ; DESENVOLVIDO POR: MULDER_FOX ; DATA DE CONCLUSO: / / ;*********************************************************************************************** #INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

53

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

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

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

;USADA PARA CONTAR OS ESTOUROS DO TMR0 ;FIM DO BLOCO DE MEMORIA

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

54

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

; INI_TMR0 INI_CONT_EST_TMR0 EQU .131 EQU .125

CONSTANTES ;VALOR QUE TMR0 INICIA ;VALOR QUE CONT_EST_TMR0 INICIA

;*********************************************************************************************** ; SADA #DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG 0X04 ;VETOR DAS INTERRUPES

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

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

Se o bit T0IF no estiver setado, significando que a interrupo no foi causada pelo estouro do Timer 0, a prxima linha do programa ser executada, e, nesse caso, temos de fazer o programa voltar da interrupo.

55

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

Para isso usamos a instruo RETFIE, porm, antes, temos de recuperar os valores dos registradores W e STATUS. Faremos isso executando as seguintes instrues, recomendadas pela Microchip:
SWAPF MOVWF SWAPF SWAPF RETFIE STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W ;W = SWAP EM STATUS_TEMP ;RECUPERA STATUS ;SWAP EM W_TEMP ;RECUPERA W ;RETORNA DA INTERRUPO

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

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

necessrio apagar esse bit, caso contrrio, quando o programa retornar da interrupo, outra ser gerada em seguida, j que o bit ainda estar setado. Continuando com a rotina, vm agora as instrues que reiniciam o registrador TMR0:
MOVLW MOVWF INI_TMR0 TMR0 ;W = INI_TMR0 ;REINICIA TMR0

A seguir decrementamos a varivel que conta os estouros do Timer 0 e ao mesmo tempo verificamos se ela chegou a 0:
DECFSZ CONT_EST_TMR0,F
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

Se o valor dessa varivel no houver chegado a zero, a prxima linha do programa ser executada. Nesse caso, novamente iremos retornar da interrupo e, ento, escrevemos a instruo GOTO SAI_INT:
GOTO SAI_INT ;NAO

56

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

J, se a varivel houver chegado a 0, essa linha ser pulada e seguem-se as instrues que reiniciam a varivel:
MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 ;SIM, W = INI_CONT_EST_TMR0 ;REINICIALIZA CONT_EST_TMR0

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


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

ACENDE_LED BSF LED

;ACENDE O LED

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

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

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

57

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

GOTO BCF GOTO ACENDE_LED BSF SAI_INT SWAPF MOVWF SWAPF SWAPF RETFIE

ACENDE_LED LED SAI_INT LED

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

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

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

O prximo passo a configurao dos registradores de uso especfico. A diferena aqui em relao ao programa da parte 2, a configurao do registrador INTCON. Conforme j havamos comentado, temos que setar os bits 5 (T0IE), 6 (PEIE) e 7 (GIE) do registrador INTCON e, portanto, escreveremos o valor binrio 11100000 neste registrador:

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

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

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

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

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

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

58

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

;*********************************************************************************************** ; PROGRAMA: PISCA LED III ; VERSO 1.0 ; DESENVOLVIDO POR: MULDER_FOX ; DATA DE CONCLUSO: / / ;*********************************************************************************************** #INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

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

;********************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP CONT_EST_TMR0 ENDC ;ENDERECO INICIAL DA MEMORIA DO USUARIO
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;USADA PARA CONTAR OS ESTOUROS DO TMR0 ;FIM DO BLOCO DE MEMORIA

;*********************************************************************************************** ; CONSTANTES INI_TMR0 INI_CONT_EST_TMR0 EQU .131 EQU .125 ;VALOR QUE TMR0 INICIA ;VALOR QUE CONT_EST_TMR0 INICIA

;*********************************************************************************************** ; SADA #DEFINE LED PORTA,0 ;LED LIGADO EM RA0

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG 0X04 W_TEMP STATUS,W STATUS_TEMP ;VETOR DAS INTERRUPES ;SALVA W ;W = SWAP EM STATUS ;CHAVEIA PARA BANCO 0 DE MEMORIA ;SALVA STATUS

MOVWF SWAPF BANCO_0 MOVWF

59

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

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

;TMR0 ESTOUROU? ;NAO, SAIR DA INTERRUPO ;SIM ;W = INI_TMR0 ;REINICIA TMR0


;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

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

ACENDE_LED BSF LED SAI_INT SWAPF MOVWF SWAPF SWAPF RETFIE

;ACENDE O LED

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO , COM PRESCALER DE 1:32

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

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

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

;*********************************************************************************************** ; INICIALIZACAO DA VARIVEL MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 ;W = INI_CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0

;*********************************************************************************************** PRINCIPAL CLRWDT GOTO ;ROTINA PRINCIPAL DO PROGRAMA ;LIMPA O WDT PRINCIPAL

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

60

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

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

61

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

62

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 3 Pisca LED III

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

63

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

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

64

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

65

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

;******************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP CONT_EST_TMR0 FLAGS DB_BTA DB_BTB ENDC
;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS ;USADA PARA CONTAR OS ESTOUROS DO TMR0 ;REGISTRADOR DE FLAGS ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO ;FIM DO BLOCO DE MEMORIA

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

A seguir, vamos criar as constantes para a inicializao das variveis DB_BTA e DB_BTB:
;********************************************************************************************** ; CONSTANTES INI_TMR0 INI_CONT_EST_TMR0 INI_DB_BTA INI_DB_BTB EQU EQU EQU EQU .131 .125 .255 .50 ;VALOR QUE TMR0 INICIA ;VALOR QUE CONT_EST_TMR0 INICIA ;VALOR QUE DB_BTA INICIA ;VALOR QUE DB_BTB INICIA

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

Iremos ajustar esses valores durante a simulao, para que tenhamos um tempo de de-bouncing em torno de 50 milissegundos. A seguir, depois da seo Sada, vamos criar uma seo chamada Entrada, para definirmos a label BOTAO como sendo o bit 1 do PORTA:
;*********************************************************************************************** ; ENTRADA #DEFINE BOTAO PORTA,1 ;BOTAO LIGADO EM RA1

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

A seguir, iremos acrescentar uma seo chamada FLAGS onde iremos atribuir um nome aos bits que iremos utilizar como flags:
;*********************************************************************************************** ; FLAGS #DEFINE #DEFINE SOLTAR_BOTAO FLAGS,0 ESTADO_DO_LED FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTO ;SE = 1 LED PISCANDO

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

A funo do flag SOLTAR_BOTAO, j foi explicada. A do flag ESTADO_DO_LED veremos adiante. Tambm faremos alteraes na rotina de interrupo, mas somente depois que tenhamos escrito a rotina principal.

66

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

A seguir, na seo INICIALIZAO DAS VARIVEIS, vamos incluir as novas variveis:


;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS MOVLW MOVWF CLRF MOVLW MOVWF MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 FLAGS INI_DB_BTA DB_BTA INI_DB_BTB DB_BTB ;W = INI_CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0 ;INICIALIZA FLAGS ;W = INI_DB_BTA ;INICIALIZA DB_BTA ;W = INI_DB_BTB ;INICIALIZA DB_BTB

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

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

67

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

SOLTAR_BOTAO TESTA_BOTAO BOTAO PRINCIPAL SOLTAR_BOTAO

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

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

;DESVIA

;FAZ O LED PISCAR


;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

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

68

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

MOVWF GOTO

DB_BTB PRINCIPAL

;INICIALIZA DB_BTB ;DESVIA

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

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

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

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

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

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

;ACENDE O LED

STATUS_TEMP,W

;SWAP EM STATUS_TEMP

69

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

MOVWF SWAPF SWAPF RETFIE

STATUS W_TEMP,F W_TEMP,W

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

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

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

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

;********************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP CONT_EST_TMR0 FLAGS DB_BTA DB_BTB ENDC ;ENDERECO INICIAL DA MEMORIA DO USUARIO
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS ;USADA PARA CONTAR OS ESTOUROS DO TMR0 ;REGISTRADOR DE FLAGS ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO

;FIM DO BLOCO DE MEMORIA

;********************************************************************************************** ; CONSTANTES INI_TMR0 INI_CONT_EST_TMR0 INI_DB_BTA INI_DB_BTB EQU EQU EQU EQU .131 .125 .255 .50 ;VALOR QUE TMR0 INICIA ;VALOR QUE CONT_EST_TMR0 INICIA ;VALOR QUE DB_BTA INICIA ;VALOR QUE DB_BTB INICIA

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

70

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

#DEFINE

LED

PORTA,0

;LED LIGADO EM RA0

;*********************************************************************************************** ; ENTRADA #DEFINE BOTAO PORTA,1 ;BOTAO LIGADO EM RA1

;*********************************************************************************************** ; FLAGS #DEFINE #DEFINE SOLTAR_BOTAO ESTADO_DO_LED FLAGS,0 FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTO ;SE = 1 LED PISCANDO

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

INICIO

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

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

;W = INI_TMR0 ;REINICIA TMR0


;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?

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

;ACENDE O LED

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

71

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010100'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, COM PRESCALER DE 1:32

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

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

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

;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS MOVLW MOVWF CLRF MOVLW MOVWF MOVLW MOVWF INI_CONT_EST_TMR0 CONT_EST_TMR0 FLAGS INI_DB_BTA DB_BTA INI_DB_BTB DB_BTB ;W = INI_CONT_EST_TMR0 ;INICIALIZA CONT_EST_TMR0 ;INICIALIZA FLAGS ;W = INI_DB_BTA ;INICIALIZA DB_BTA ;W = INI_DB_BTB ;INICIALIZA DB_BTB

;*********************************************************************************************** PRINCIPAL CLRWDT BTFSS GOTO BTFSS GOTO BCF ;ROTINA PRINCIPAL DO PROGRAMA ;LIMPA O WDT ;AGUARDA SOLTAR O BOTAO? ;NAO, DESVIA ;SIM, O BOTO EST SOLTO? ;NAO, DESVIA ;SIM, APAGA FLAG

SOLTAR_BOTAO TESTA_BOTAO BOTAO PRINCIPAL SOLTAR_BOTAO

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

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

;DESVIA

72

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

;FAZ O LED PISCAR


;SETA O FLAG PARA AGUARDAR SOLTAR O BOTAO

;DESVIA

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

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

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

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

73

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

74

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

Figura 3

75

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

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

76

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

Figura 6

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

77

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

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

78

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

79

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

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

80

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

Figura 11

81

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 4 Pisca LED IV

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

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

82

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Parte 5
Contador Crescente e Decrescente

Desta vez iremos montar o circuito da figura abaixo onde o boto 1 ir incrementar o nmero exibido no display, enquanto o boto 2 o decrementar.

Figura 1

83

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

84

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 2

85

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Figura 3

No MPLAB, abra o arquivo Pisca LED IV.asm e salve-o com o nome de Contador.asm. A primeira alterao que faremos na seo VARIVEIS, onde vamos excluir a CONT_EST_TMR0 . Como teremos dois botes, vamos renomear as variveis DB_BTA e DB_BTB para DB1_BTA e DB1_BTB e criar outras duas: DB2_BTA e DB2_BTB. Criaremos uma varivel chamada UNIDADE para a unidade do nmero exibido no display e outra chamada DEZENA para a dezena.

86

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

;*********************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP FLAGS DB1_BTA DB1_BTB DB2_BTA DB2_BTB UNIDADE DEZENA ENDC ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

;REGISTRADOR DE FLAGS ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1 ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1 ;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2 ;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2 ;UNIDADE DO NUMERO EXIBIDO NO DISPLAY ;DEZENA DO NUMERO EXIBIDO NO DISPLAY ;FIM DO BLOCO DE MEMORIA

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

Na seo CONSTANTES, vamos excluir INI_CONT_EST_TMR0 e INI_TMR0, renomear as que inicializam as variveis de de -bouncing do boto 1 e criar as que inicializam as do boto 2:
;********************************************************************************************** ; CONSTANTES INI_DB1_BTA INI_DB1_BTB INI_DB2_BTA INI_DB2_BTB EQU EQU EQU EQU .255 .20 .255 .20 ;VALOR QUE DB1_BTA INICIA ;VALOR QUE DB1_BTB INICIA ;VALOR QUE DB2_BTA INICIA ;VALOR QUE DB2_BTB INICIA

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

Na seo SADAS, vamos definir a label DIGITO_1 para o pino RA2 e a label DIGITO_2 para o pino RA3. Relembrando que quando RA2 estiver em nvel alto, o dgito 1 do display estar ativo e quando RA3 estiver em nvel alto, o dgito 2 estar ativo:
;*********************************************************************************************** ; SADAS #DEFINE #DEFINE DIGITO_1 DIGITO_2 PORTA,2 PORTA,3 ;SE = 1, DIGITO 1 DO DISPLAY ATIVADO ;SE = 1, DIGITO 2 DO DISPLAY ATIVADO

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

Na seo ENTRADAS, vamos definir a label BOTAO_1 para o pino RA0 e a label BOTAO_2 para o pino RA1, conforme o esquema do circuito:
;*********************************************************************************************** ; ENTRADAS #DEFINE #DEFINE BOTAO_1 BOTAO_2 PORTA,0 PORTA,1 ;BOTAO 1 LIGADO EM RA0 ;BOTAO 2 LIGADO EM RA1

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

87

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Na seo FLAGS, vamos excluir o flag ESTADO_DO_LED, renomear o flag SOLTAR_BOTAO para SOLTAR_BOTAO_1 e criar o flag SOLTAR_BOTAO_2:
;*********************************************************************************************** ; FLAGS #DEFINE #DEFINE SOLTAR_BOTAO_1 SOLTAR_BOTAO_2 FLAGS,0 FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTO 1 ;SE = 1 AGUARDA SOLTAR O BOTO 2

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

Chegamos rotina de interrupo. O Timer 0 ser configurado para que gere uma interrupo a cada 5 milissegundos aproximadamente. Isto ser feito depois, na seo de configurao dos registradores. Na rotina de interrupo, iremos: Verificar qual dgito est ativo e desativ-lo; Ativar o outro dgito; Converter o valor numrico a ser exibido no display para o formato de 7 segmentos; Enviar este valor convertido para o PORTB, onde est ligado o display. A rotina igual at este ponto:
;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG MOVWF SWAPF BANCO_0 MOVWF BTFSS GOTO BCF 0X04 W_TEMP STATUS,W STATUS_TEMP INTCON,T0IF SAI_INT INTCON,T0IF ;VETOR DAS INTERRUPES ;SALVA W ;W = SWAP EM STATUS ;CHAVEIA PARA BANCO 0 DE MEMORIA ;SALVA STATUS ;TMR0 ESTOUROU? ;NAO, SAIR DA INTERRUPO ;SIM

A seguir, vamos verificar qual o dgito que est ativo, desativ-lo, e ativar o outro:
BTFSS GOTO BCF CLRF BSF GOTO DIGITO_1 DESATIVA_DIGITO_2 DIGITO_1 PORTB DIGITO_2 COPIAR_UNIDADE ;DIGITO 1 ESTA ATIVADO? ;NAO, DESVIA ;SIM, DESATIVA DIGITO 1 ;TODOS OS BITS DO PORT B = 0 ;ATIVA DIGITO 2 ;DESVIA

DESATIVA_DIGITO_2 BCF DIGITO_2 CLRF PORTB BSF DIGITO_1

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

Com a instruo BTFSS, testamos se o dgito 1 est ativado e, se estiver, desativamo-lo com a instruo BCF DIGITO_1 e ativamos o dgito 2 com a instruo BSF DIGITO_2.

88

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Porm se o dgito 1 estiver desativado, significa que o dgito 2 est ativo e, ento, o programa desviado para a label DESATIVA_DIGITO_2, onde o dgito 2 desativado e o dgito 1 ativado. Repare que antes de ativarmos o dgito, fazemos todos os bits do PORTB = 0 com a instruo CLRF, para que o dgito que ser ativado no receba os valores do dgito que acaba de ser desativado. Os segmentos do display esto conectados no PORTB, da seguinte forma: Segmento Bit a b c d e f g RB0 RB1 RB2 RB3 RB4 RB5 RB6

Tabela 1 O display utilizado do tipo catodo comum, portanto os segmentos so ativados com nvel alto. Sendo assim, os valores a serem escritos no PORTB para cada algarismo a ser exibido no display so os constantes na tabela abaixo. O bit 7 do PORTB est desconectado, portanto, seu valor indiferente, pelo que lhe atribumos o valor 0 para todos os algarismos. Algarismo 0 1 2 3 4 5 6 7 8 9 PORTB 00111111 00000110 01011011 01001111 01100110 01101101 01111101 00000111 01111111 01101111 Tabela 2 As figuras a seguir ilustram os valores da tabela anterior.

89

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

00111111

00000110

01011011

01001111

90

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

01100110

01101101

01111101

00000111

91

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

01111111

01101111

Aps o dgito ser ativado, devemos enviar para o PORTB o valor referente ao algarismo que deve ser exibido. O dgito 1 do display exibe a dezena do nmero e o dgito 2, a unidade. O algarismo da dezena est gravado na varivel DEZENA, enquanto que o da unidade est gravado na varivel UNIDADE, porm, esses algarismos esto gravados nessas variveis no formato binrio, conforme a tabela abaixo: Algarismo Valor binrio 0 1 2 3 4 5 6 7 8 9 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 Tabela 3

92

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Esses valores so diferentes dos que deve assumir o PORTB para que os algarismos sejam exibidos no display de 7 segmentos, conforme a tabela comparativa abaixo: Algarismo Valor binrio 0 1 2 3 4 5 6 7 8 9 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 Tabela 4 Por isso, no podemos simplesmente copiar o valor da varivel para o PORTB. Existe uma maneira prtica de converter o valor binrio para o correspondente a 7 segmentos, que consiste em somar o valor binrio ao Contador de Programa (PC - Program Counter) para provocar um desvio no programa (Computed GOTO) para uma localidade onde exista uma instruo que faa o programa retornar com o nmero j convertido no registrador W. O Contador de Programa (PC), armazena o endereo da prxima instruo que ser executada. Quando o microcontrolador ligado e tambm depois de um reset, o valor do PC igual a 0h (nmero 0 no formato hexadecimal), o que quer dizer que ele ir executar a instruo gravada nessa localidade da memria de programa. A cada instruo que executada, o PC incrementado em 1 unidade, portanto, depois de executar a instruo contida no endereo 0h, ele ir executar a instruo contida no endereo 1h, depois a do endereo 2h e assim por diante. Isso se as instrues contidas nesses endereos no provocarem o desvio do programa para outra localidade da memria. Um exemplo de instruo que provoca o desvio para outra localidade de memria a GOTO. O PC do PIC16F628A composto de 13 bits, sendo que os 8 bits menos significativos (do 0 ao 7) compe o registrador PCL. Este registrador pode ser acessado diretamente para ser alterado. Os 5 bits mais significativos do PC (do 8 ao 12), chamados de PCH s podem ser alterados indiretamente atravs do registrador PCLATH. Quando uma instruo GOTO executada, o endereo para onde o programa dever ser desviado consta na prpria instruo sendo copiado para o PC; portanto, a prxima instruo que ser executada aquela que consta na instruo GOTO. Outro tipo de instruo que provoca um desvio no programa a instruo CALL. PORTB 00111111 00000110 01011011 01001111 01100110 01101101 01111101 00000111 01111111 01101111

93

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

94

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

Em seguida usamos a instruo CALL para desviar o programa para onde est a label CONVERTE_BINARIO_7_SEGMENTOS:
CALL CONVERTE_BINARIO_7_SEGMENTOS ;CHAMA SUBROTINA

Nesta subrotina, usamos a instruo ADDWF para somar o valor da varivel UNIDADE, que est copiada no registrador W, ao PCL:
CONVERTE_BINARIO_7_SEGMENTOS ADDWF PCL,F ;PCL = PCL + W RETLW B'00111111' ;W = 0 RETLW B'00000110' ;W = 1 RETLW B'01011011' ;W = 2 RETLW B'01001111' ;W = 3 RETLW B'01100110' ;W = 4 RETLW B'01101101' ;W = 5 RETLW B'01111101' ;W = 6 RETLW B'00000111' ;W = 7 RETLW B'01111111' ;W = 8 RETLW B'01101111' ;W = 9

95

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

O mesmo procedimento adotado quando o dgito 1 for ativado, com a diferena de que o valor da varivel DEZENA que copiado e convertido. Em seguida, desviamos o programa para a subrotina SAI_INT para que retorne da interrupo. Conclumos, assim, a rotina de interrupo:
;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG MOVWF SWAPF BANCO_0 MOVWF BTFSS GOTO BCF BTFSS GOTO BCF CLRF BSF GOTO 0X04 W_TEMP STATUS,W STATUS_TEMP INTCON,T0IF SAI_INT INTCON,T0IF DIGITO_1 DESATIVA_DIGITO_2 DIGITO_1 PORTB DIGITO_2 COPIAR_UNIDADE ;VETOR DAS INTERRUPES ;SALVA W ;W = SWAP EM STATUS ;CHAVEIA PARA BANCO 0 DE MEMORIA ;SALVA STATUS ;TMR0 ESTOUROU? ;NAO, DESVIA ;SIM, APAGA FLAG ;DIGITO 1 ESTA ATIVADO? ;NAO, DESVIA ;SIM, DESATIVA DIGITO 1 ;TODOS OS BITS DO PORT B = 0 ;ATIVA DIGITO 2 ;DESVIA

DESATIVA_DIGITO_2 BCF DIGITO_2 CLRF PORTB BSF DIGITO_1 MOVF DEZENA,W CALL CONVERTE_BINARIO_7_SEGMENTOS MOVWF PORTB GOTO SAI_INT COPIAR_UNIDADE MOVF UNIDADE,W CALL CONVERTE_BINARIO_7_SEGMENTOS MOVWF PORTB GOTO SAI_INT CONVERTE_BINARIO_7_SEGMENTOS ADDWF PCL,F RETLW B'00111111'

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

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

;PCL = PCL + W ;W = 0

96

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

RETLW RETLW RETLW RETLW RETLW RETLW RETLW RETLW RETLW SAI_INT SWAPF MOVWF SWAPF SWAPF RETFIE

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

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

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

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

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

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

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

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

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

97

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

A seguir, em INICIALIZAO DAS VARIVEIS, inicializamos as variveis de de-bouncing dos botes com os seus devidos valores e as variveis FLAGS, UNIDADE e DEZENA com o valor 0 (CLRF):
;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS CLRF MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF CLRF CLRF FLAGS INI_DB1_BTA DB1_BTA INI_DB1_BTB DB1_BTB INI_DB2_BTA DB2_BTA INI_DB2_BTB DB2_BTB UNIDADE DEZENA ;INICIALIZA FLAGS ;W = INI_DB1_BTA ;INICIALIZA DB1_BTA ;W = INI_DB1_BTB ;INICIALIZA DB1_BTB ;W = INI_DB2_BTA ;INICIALIZA DB2_BTA ;W = INI_DB2_BTB ;INICIALIZA DB2_BTB ;INICIALIZA UNIDADE ;INICIALIZA DEZENA

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

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

TRATA_BOTAO_1 TRATA_BOTAO_2 PRINCIPAL

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

Na subrotina TRATA_BOTAO_1, primeiramente testamos se o flag SOLTAR_BOTAO_1 est setado. Se estiver, testamos o boto para verificar se ele est solto. Se estiver, apagamos o flag. Se no estiver solto, retornamos atravs da instruo RETURN. Se o flag SOLTAR_BOTAO_1 no estiver setado, testamos o boto. Se ele no estiver pressionado, retornamos. Se estiver pressionado, decrementamos a varivel DB1_BTA dando incio ao de-bouncing e em seguida retornamos. O retorno depois de decrementar as variveis do de-bouncing para que o programa no fique preso dentro da rotina de de-bouncing. Quando terminar o de-bouncing, teremos chegado a este ponto:
;*********************************************************************************************** TRATA_BOTAO_1 BTFSS GOTO BTFSS SOLTAR_BOTAO_1 TESTA_BOTAO_1 BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1? ;NAO, DESVIA ;SIM, O BOTO 1 EST SOLTO?

98

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

RETURN BCF

SOLTAR_BOTAO_1

;NAO, RETORNA ;SIM, APAGA FLAG

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

;O BOTO 1 EST PRESSIONADO? ;NO, DESVIA ;SIM, DECREMENTA DB1_BTA. DB1_BTA = 0? ;NAO,RETORNA ;SIM, W = INI_DB1_BTA ;INICIALIZA DB1_BTA ;DECREMENTA DB1_BTB. DB1_BTB = 0? ;NAO, RETORNA ;SIM, W = INI_DB1_BTB ;INICIALIZA DB1_BTB

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


BSF SOLTAR_BOTAO_1 ;SETA FLAG PARA AGUARDAR SOLTAR O BOTO 1

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

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

Em seguida, efetuamos a operao XOR entre o registrador UNIDADE e o W, salvando o resultado no W (para no alterar o valor do UNIDADE):
XORWF UNIDADE,W ;W = W XOR UNIDADE

Se o valor da varivel UNIDADE for igual a 1 0 (valor do W), o resultado da operao ser igual a 0. Para sabermos se o resultado da operao foi igual a 0, testamos o bit Z do registrador STATUS:

99

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

BTFSS

STATUS,Z

;UNIDADE = 10?

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

Mas, se o bit Z for igual a 1, ento, o valor da unidade igual a 10 e, ento, a linha com a instruo RETURN pulada. Como o valor da unidade chegou a 10, devemos zer-la e incrementar o valor da dezena:
CLRF INCF UNIDADE DEZENA,F ;SIM, UNIDADE = 0 ;INCREMENTA DEZENA

Da mesma forma que fizemos com a unidade, aps incrementarmos a dezena, devemos verificar se o seu valor igual a 10. Se no for, basta retornar e, se for igual a 10, devemos zer-la e depois retornar, pois no temos a centena para incrementar:
MOVLW XORWF BTFSS RETURN CLRF RETURN .10 DEZENA,W STATUS,Z DEZENA ;W = 10 ;W = W XOR DEZENA ;DEZENA = 10? ;NAO, RETORNA ;SIM, DEZENA = 0 ;RETORNA

Com isso, conclumos a subrotina TRATA_BOTAO_1 que ficou assim:


;*********************************************************************************************** TRATA_BOTAO_1 BTFSS GOTO BTFSS RETURN BCF TESTA_BOTAO_1 BTFSC GOTO DECFSZ RETURN MOVLW MOVWF DECFSZ RETURN MOVLW MOVWF BSF SOLTAR_BOTAO_1 TESTA_BOTAO_1 BOTAO_1 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1? ;NAO, DESVIA ;SIM, O BOTO 1 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

100

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

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

REINC_CONT_DEB_1 MOVLW INI_DB1_BTA MOVWF DB1_BTA MOVLW INI_DB1_BTB MOVWF DB1_BTB RETURN

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

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

A seguir, vem a subrotina TRATA_BOTAO_2 que igual do boto 1 (porm fazendo referncia ao boto 2) at este ponto:
;*********************************************************************************************** TRATA_BOTAO_2 BTFSS GOTO BTFSS RETURN BCF TESTA_BOTAO_2 BTFSC GOTO DECFSZ RETURN MOVLW MOVWF DECFSZ RETURN MOVLW MOVWF BSF SOLTAR_BOTAO_2 TESTA_BOTAO_2 BOTAO_2 SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2? ;NAO, DESVIA ;SIM, O BOTO 2 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

O boto 2 a cada vez que for pressionado decrementar o nmero mostrado no display. Devemos, portanto, decrementar a unidade e para isso usaremos a instruo DECF, que diminui em 1 unidade o valor de um registrador:
DECF UNIDADE,F ;DECREMENTA UNIDADE

101

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

Precisamos verificar qual o valor do registrador UNIDADE, aps ser decrementado. Se o valor do registrador antes de ser decrementado era 0, seu valor aps o decremento ser 255, j que se trata de um registrador de 8 bits, cujo valor varia de 0 a 255, porm, nesse caso, a unidade dever assumir o valor 9. O que faremos verificar se o valor da unidade igual a 255. Se no for, retornamos e, se for 255, tornamos o valor da unidade igual a 9:
MOVLW XORWF BTFSS RETURN MOVLW MOVWF .255 UNIDADE,W STATUS,Z .9 UNIDADE ;W = 255 ;W = W XOR UNIDADE ;UNIDADE = 255? ;NAO, RETORNA ;SIM, W = 9 ;UNIDADE = 9

Em seguida decrementamos a dezena, e adotamos o mesmo procedimento se o seu valor for igual a 255:
DECF MOVLW XORWF BTFSS RETURN MOVLW MOVWF RETURN DEZENA,F .255 DEZENA,W STATUS,Z .9 DEZENA ;DECREMENTA DEZENA ;W = 255 ;W = W XOR DEZENA ;DEZENA = 255? ;NAO, RETORNA ;SIM, W = 9 ;DEZENA = 9 ;RETORNA

Conclumos assim a subrotina TRATA_BOTAO_2:


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

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

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

102

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

RETURN MOVLW MOVWF DECF MOVLW XORWF BTFSS RETURN MOVLW MOVWF RETURN

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

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

REINC_CONT_DEB_2 MOVLW INI_DB2_BTA MOVWF DB2_BTA MOVLW INI_DB2_BTB MOVWF DB2_BTB RETURN

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

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

O nosso programa est pronto, tendo ficado assim:


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

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

;*********************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP FLAGS DB1_BTA DB1_BTB DB2_BTA DB2_BTB ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

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

103

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

UNIDADE DEZENA ENDC

;UNIDADE DO NUMERO EXIBIDO NO DISPLAY ;DEZENA DO NUMERO EXIBIDO NO DISPLAY ;FIM DO BLOCO DE MEMORIA

;*********************************************************************************************** ; CONSTANTES INI_DB1_BTA INI_DB1_BTB INI_DB2_BTA INI_DB2_BTB EQU EQU EQU EQU .255 .20 .255 .20 ;VALOR QUE DB1_BTA INICIA ;VALOR QUE DB1_BTB INICIA ;VALOR QUE DB2_BTA INICIA ;VALOR QUE DB2_BTB INICIA

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

;*********************************************************************************************** ; ENTRADAS #DEFINE #DEFINE BOTAO_1 BOTAO_2 PORTA,0 PORTA,1 ;BOTAO 1 LIGADO EM RA0 ;BOTAO 2 LIGADO EM RA1

;*********************************************************************************************** ; FLAGS #DEFINE SOLTAR_BOTAO_1 FLAGS,0 ;SE = 1 AGUARDA SOLTAR O BOTO 1 #DEFINE SOLTAR_BOTAO_2 FLAGS,1 ;SE = 1 AGUARDA SOLTAR O BOTO 2 ;*********************************************************************************************** ; VETOR DE RESET ORG GOTO 0X00 INICIO ;ENDERECO INICIAL DE PROCESSAMENTO ;DESVIA PARA INICIO

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

DESATIVA_DIGITO_2 BCF DIGITO_2

;DESATIVA DIGITO 2

104

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

CLRF BSF MOVF CALL MOVWF GOTO

PORTB DIGITO_1 DEZENA,W CONVERTE_BINARIO_7_SEGMENTOS PORTB SAI_INT

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

COPIAR_UNIDADE MOVF UNIDADE,W CALL CONVERTE_BINARIO_7_SEGMENTOS MOVWF PORTB GOTO SAI_INT CONVERTE_BINARIO_7_SEGMENTOS ADDWF PCL,F RETLW B'00111111' RETLW B'00000110' RETLW B'01011011' RETLW B'01001111' RETLW B'01100110' RETLW B'01101101' RETLW B'01111101' RETLW B'00000111' RETLW B'01111111' RETLW B'01101111' SAI_INT SWAPF MOVWF SWAPF SWAPF RETFIE

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

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

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010011'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16

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

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

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

;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS CLRF MOVLW MOVWF FLAGS INI_DB1_BTA DB1_BTA ;INICIALIZA FLAGS ;W = INI_DB1_BTA ;INICIALIZA DB1_BTA

105

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF CLRF CLRF

INI_DB1_BTB DB1_BTB INI_DB2_BTA DB2_BTA INI_DB2_BTB DB2_BTB UNIDADE DEZENA

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

;*********************************************************************************************** PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA CLRWDT CALL CALL GOTO ;LIMPA O WDT ;CHAMA SUBROTINA ;CHAMA SUBROTINA ;DESVIA

TRATA_BOTAO_1 TRATA_BOTAO_2 PRINCIPAL

;*********************************************************************************************** TRATA_BOTAO_1 BTFSS GOTO BTFSS RETURN BCF TESTA_BOTAO_1 BTFSC GOTO DECFSZ RETURN MOVLW MOVWF DECFSZ RETURN MOVLW MOVWF BSF INCF MOVLW XORWF BTFSS RETURN CLRF INCF MOVLW XORWF BTFSS RETURN CLRF RETURN SOLTAR_BOTAO_1 TESTA_BOTAO_1 BOTAO_1 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1? ;NAO, DESVIA ;SIM, O BOTO 1 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

REINC_CONT_DEB_1 MOVLW INI_DB1_BTA MOVWF DB1_BTA MOVLW INI_DB1_BTB MOVWF DB1_BTB RETURN

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

106

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

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

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

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

107

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

108

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

109

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

110

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

111

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

112

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

113

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

114

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 5 Contador Crescente e Decrescente

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

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

115

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Parte 6
Contador Crescente e Decrescente II

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

116

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

117

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Como neste programa iremos acessar com frequncia registradores que se encontram no banco 1 da memria de dados, e para que no precisemos trocar constantemente de banco, vamos criar as variveis a partir do endereo 0x70, pois, as variveis que ocupam esse endereo at o 0x7F podem ser acessadas a partir de qualquer banco. Repare que so apenas 16 localidades que tem esse atributo. Iremos adicionar as variveis ESC_EEPROM_A e ESC_EEPROM_B para a contagem do tempo de espera pelo fim da escrita na EEPROM e a varivel LOCAL_DA_UNIDADE, que conter o endereo da localidade da EEPROM onde est salvo o valor da unidade:
;*********************************************************************************************** ; VARIVEIS CBLOCK 0X70 W_TEMP STATUS_TEMP FLAGS DB1_BTA DB1_BTB DB2_BTA DB2_BTB UNIDADE DEZENA ESC_EEPROM_A ESC_EEPROM_B
LOCAL_DA_UNIDADE

;ENDERECO DA PRIMEIRA VARIVEL ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W


;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

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

ENDC

;FIM DO BLOCO DE MEMORIA

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

Na seo CONSTANTES, acrescentaremos as de inicializao das variveis ESC_EEPROM_A e ESC_EEPROM_B:


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

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

A seguir, na seo FLAGS, acrescentaremos os seguintes: APAGAR_UNIDADE, GRAVAR_UNIDADE, GRAVAR_DEZENA, ESP_FIM_GRV_EEPROM, CONF_GRV_EEPROM que sero usados na subrotina de gravao da EEPROM.
;*********************************************************************************************** ; FLAGS #DEFINE SOLTAR_BOTAO_1 FLAGS,0 ;SE = 1, AGUARDA SOLTAR O BOTO 1

118

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

;SE = 1, AGUARDA SOLTAR O BOTO 2


;SE = 1, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE

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

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

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

Valor em decimal Valor em binrio Valor em decimal Valor em binrio 0 1 2 3 4 0000 0000 0000 0001 0000 0010 0000 0011 0000 0100 Tabela 1 Sendo assim, usaremos os bits 5 a 8 para gravar um cdigo que far com que o programa identifique a localidade onde est armazenado o valor da unidade. O cdigo que utilizaremos ser este: 0110, ou seja, esses sero os valores dos bits 5 a 8 da localidade onde o valor da unidade estiver salvo. Esse cdigo ser gravado todas as vezes que salvarmos o valor da unidade, porm, na gravao do programa no microcontrolador, devemos escrever o cdigo na primeira localidade da memria EEPROM, caso contrrio, no haver nenhuma localidade com o cdigo para que o programa encontre na primeira vez que o microcontrolador for ligado. Isso feito com o uso da diretiva DE, desta forma: 5 6 7 8 9 0000 0101 0000 0110 0000 0111 0000 1000 0000 1001

119

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

;********************************************************************************************** ; ORG DE 2100 B'01100000', .0 INICIALIZAO DA EEPROM ;APONTA PARA O ENDEREO 00H DA EEPROM
;ESCREVE O NMERO BINRIO 01100000 NO ENDEREO 00H DA EEPROM

;E O NMERO DECIMAL 0, NA LOCALIDADE 01H ;**********************************************************************************************

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

120

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

121

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

122

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Na rotina principal, acrescentaremos uma instruo CALL que chamar a subrotina de gravao da EEPROM, ficando assim:
;*********************************************************************************************** PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA CLRWDT CALL CALL CALL GOTO ;LIMPA O WDT ;CHAMA SUBROTINA ;CHAMA SUBROTINA ;CHAMA SUBROTINA ;DESVIA

TRATA_BOTAO_1 TRATA_BOTAO_2 GRAVA_EEPROM PRINCIPAL

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

Na subrotina do boto 1, aps a unidade ser incrementada, iremos setar os flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA, pois todas as vezes que o valor da unidade for alterado, iremos salvar os valores da unidade e da dezena, sendo que, tambm, precisamos apagar a localidade anterior da unidade para limpar o cdigo que a identificava.
;*********************************************************************************************** TRATA_BOTAO_1 BTFSS GOTO BTFSS RETURN BCF TESTA_BOTAO_1 BTFSC GOTO DECFSZ RETURN MOVLW MOVWF DECFSZ RETURN MOVLW MOVWF BSF INCF BSF BSF BSF MOVLW XORWF BTFSS RETURN CLRF INCF MOVLW XORWF BTFSS RETURN CLRF RETURN SOLTAR_BOTAO_1 TESTA_BOTAO_1 BOTAO_1 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1? ;NAO, DESVIA ;SIM, O BOTO 1 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

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

123

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

REINC_CONT_DEB_1 MOVLW INI_DB1_BTA MOVWF DB1_BTA MOVLW INI_DB1_BTB MOVWF DB1_BTB RETURN

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

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

Na subrotina do boto 2, tambm iremos setar esses mesmos flags aps a unidade ser decrementada:
;******************************************************************************************** TRATA_BOTAO_2 BTFSS GOTO BTFSS RETURN BCF SOLTAR_BOTAO_2 TESTA_BOTAO_2 BOTAO_2 SOLTAR_BOTAO_2 ;AGUARDA SOLTAR O BOTAO 2? ;NAO, DESVIA ;SIM, O BOTO 2 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

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

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

124

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

Se o flag estiver zerado, testamos o flag que informa se j podemos conferir a gravao:
BTFSC CONF_GRV_EEPROM ;NAO, CONFERIR A GRAVAO?

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

Se o flag estiver zerado, testamos o flag que informa se a vez de apagar a localidade anterior da unidade:

125

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BTFSC

APAGAR_UNIDADE

;NAO, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE?

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

Se o flag estiver zerado, testamos o flag que informa se a vez de gravar a unidade na nova localidade:
BTFSC GRAVAR_UNIDADE ;NAO, GRAVAR UNIDADE?

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

Se o flag estiver zerado, testamos o flag que informa se a vez de gravar a dezena na nova localidade:
BTFSC GRAVAR_DEZENA ;NAO, GRAVAR DEZENA?

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

Se o flag estiver zerado, retornamos:


RETURN ;NAO

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

;EEADR RECEBE ENDERECO

A seguir, zeramos o EEDATA:


CLRF EEDATA ;EEDATA = 0

Em seguida, setamos o bit WREN (bit 2 do EECON1) para habilitar a escrita na EEPROM:
BSF EECON1,WREN ;HABILITA ESCRITA NA EEPROM

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


BCF INTCON,GIE ;DESABILITA AS INTERRUPES

Aps isso, testamos esse bit para confirmarmos que ele foi zerado:
BTFSC INTCON,GIE ;BIT GIE EST ZERADO?

126

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Se ele no houver sido zerado, executamos novamente a instruo BCF INTCON,GIE, para zer-lo:
GOTO $-2 ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA

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

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


BSF EECON1,WR ;INICIA A GRAVAO

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


BSF INTCON,GIE ;HABILITA INTERRUPES

Aps isso, zeramos o flag APAGAR_UNIDADE:


BCF APAGAR_UNIDADE ;APAGA O FLAG

Por fim, setamos o flag ESP_FIM_GRV_EEPROM, selecionamos o banco 0 e retornamos:


BSF BANCO_0 RETURN ESP_FIM_GRV_EEPROM
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO

;SELECIONA O BANCO 0 DE MEMRIA ;RETORNA

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

127

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

128

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

GRAVA_A_UNIDADE BANCO_1 INCF EEADR,F INCF EEADR,F

;SELECIONA O BANCO 1 DE MEMRIA ;INCREMENTA EEADR ;INCREMENTA EEADR

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

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


CONT_GRV_UNIDADE MOVF UNIDADE,W MOVWF EEDATA ;W = UNIDADE ;EEDATA = UNIDADE

Em seguida, copiamos o nmero binrio 01100000 para o W e, depois, efetuamos a operao lgica OR, entre o W e o EEDATA, atravs da instruo IORWF, salvando o resultado no EEDATA:
MOVLW IORWF B'01100000' EEDATA,F ;W = 01100000 ;EEDATA = EEDATA OR 01100000

A operao lgica OR efetuada bit a bit entre o W, cujo valor igual ao nmero binrio 01100000, e o EEDATA. Quando pelo menos um dos bits for igual a 1, o bit do resultado ser igual a 1. Se os dois bits forem iguais a 0, o bit do resultado ser igual a 0. Nos bits 0 a 4 do EEDATA, est o valor da unidade, que copiamos antes. Como os bits 0 a 4 do nmero binrio 01100000 so iguais a 0, o valor dos bits 0 a 4 do EEDATA sero mantidos, pois, se o bit do EEDATA igual a 0, o bit do resultado ser igual a 0 e se o bit do EEDATA for igual a 1, o do resultado ser igual a 1. Como os bits 5 a 8 do EEDATA so iguais a 0, pois o valor da unidade varia de 0 a 9 (veja a tabela 1), os bits 5 a 8 do nmero binrio 01100000 sero mantidos. Dessa forma, aps a execuo da instruo IORWF, nos bits 0 a 4 do EEDATA estar o valor da unidade e nos bits 5 a 8 estar o cdigo que identifica a localidade da memria EEPROM onde estar gravada a unidade. A seguir, escrevemos a sequncia de instrues para a gravao da EEPROM:
BSF BCF BTFSC GOTO MOVLW MOVWF MOVLW MOVWF BSF BSF EECON1,WREN INTCON,GIE INTCON,GIE $-2 0x55 EECON2 0xAA EECON2 EECON1,WR INTCON,GIE ;HABILITA ESCRITA NA EEPROM ;DESABILITA AS INTERRUPES ;BIT GIE EST ZERADO? ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA ;W = NUMERO 55 HEXADECIMAL ;EECON2 = 55 HEXADECIMAL ;W = NUMERO AA HEXADECIMAL ;EECON2 = AA HEXADECIMAL ;INICIA A GRAVAO ;HABILITA INTERRUPES

A seguir, zeramos o flag ESP_FIM_GRV_EEPROM e retornamos:

GRAVAR_UNIDADE, setamos o flag

129

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BCF BSF BANCO_0 RETURN

GRAVAR_UNIDADE ESP_FIM_GRV_EEPROM

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

;SELECIONA BANCO 0 DE MEMORIA ;RETORNA

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

;SELECIONA O BANCO 1 DE MEMRIA ;INCREMENTA EEADR

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


MOVF MOVWF DEZENA,W EEDATA ;W = DEZENA ;EEDATA = DEZENA

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


BSF BCF BTFSC GOTO MOVLW MOVWF MOVLW MOVWF BSF BSF EECON1,WREN INTCON,GIE INTCON,GIE $-2 0x55 EECON2 0xAA EECON2 EECON1,WR INTCON,GIE ;HABILITA ESCRITA NA EEPROM ;DESABILITA AS INTERRUPES ;BIT GIE EST ZERADO? ;DESVIA O PROGRAMA PARA 2 LINHAS ACIMA ;W = NUMERO 55 HEXADECIMAL ;EECON2 = 55 HEXADECIMAL ;W = NUMERO AA HEXADECIMAL ;EECON2 = AA HEXADECIMAL ;INICIA A GRAVAO ;HABILITA INTERRUPES

Aps, zeramos o flag GRAVAR_DEZENA e setamos os flags ESP_FIM_GRV_EEPROM e CONF_GRV_EEPROM, retornando em seguida:
BCF BSF BSF BANCO_0 RETURN GRAVAR_DEZENA ESP_FIM_GRV_EEPROM CONF_GRV_EEPROM ;APAGA O FLAG ;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO ;SETA O FLAG PARA CONFERIR A GRAVAO DA EEPROM ;SELECIONA BANCO 0 DE MEMORIA ;RETORNA

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

130

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Neste trecho do programa, vamos conferir se o valor da dezena gravado na EEPROM est correto. Setamos o bit RD e aps 1 ciclo de instruo teremos, no EEDATA, o valor da localidade onde foi gravada a dezena.
CONFERE_DEZENA BANCO_1 BSF EECON1,RD ;SELECIONA O BANCO 1 DE MEMRIA ;INICIA LEITURA

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


MOVF DEZENA,W ;W = DEZENA

Em seguida efetuamos a operao lgica XOR entre o W e o registrador EEDATA, para verificarmos se so iguais:
XORWF EEDATA,W ;W = W XOR EEDATA

Testamos o bit Z do registrador STATUS, o qual estar setado se eles forem iguais:
BTFSC STATUS,Z ;VALOR DA DEZENA FOI GRAVADO CORRETAMENTE?

Estando setado, CONFERE_APAGAMENTO:


GOTO CONFERE_APAGAMENTO

desviamos
;SIM

programa

para

onde

est

label

Porm, se o bit Z estiver zerado, significa que o valor gravado no est igual ao da dezena, portanto apagamos o flag CONF_GRV_EEPROM, setamos os flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA para que o processo de gravao seja repetido.
BCF BSF BSF BSF BANCO_0 RETURN CONF_GRV_EEPROM APAGAR_UNIDADE GRAVAR_UNIDADE GRAVAR_DEZENA ;APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

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

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

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

131

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

A seguir, setamos o bit RD e no prximo ciclo de instruo teremos o valor dessa localidade no EEDATA, o qual copiamos para o W:
CONT_CONFERENCIA BSF EECON1,RD MOVF EEDATA,W ;INICIA LEITURA ;W = VALOR DA LOCALIDADE DA EEPROM

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

;SIM ;NAO, APAGA FLAG


;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

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

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

132

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

Em seguida, procedemos da mesma forma que foi feito na conferncia do valor da dezena, com a diferena de que aps copiarmos a unidade para o W, inserimos o cdigo nos bits 5 a 8 do W, com a instruo IORWF, antes de comparar com o registrador EEDATA. Se a gravao estiver correta, o programa desviado para onde est a label GRAVACAO_CORRETA, onde apagamos o flag CONF_GRV_EEPROM, copiamos o valor do EEADR para a varivel LOCAL_DA_UNIDADE, atualizando essa varivel e retornamos, finalizando o processo de gravao. Mas, se o valor da unidade no houver sido gravado corretamente, apagamos o flag CONF_GRV_EEPROM, setamos os flags APAGAR_UNIDADE, GRAVAR_UNIDADE e GRAVAR_DEZENA para que o processo de gravao seja repetido:
CONT_CONF_UNIDADE BSF EECON1,RD MOVF UNIDADE,W IORLW B'01100000' XORWF EEDATA,W BTFSC STATUS,Z GOTO GRAVACAO_CORRETA BCF CONF_GRV_EEPROM BSF APAGAR_UNIDADE BSF GRAVAR_UNIDADE BSF GRAVAR_DEZENA BANCO_0 RETURN GRAVACAO_CORRETA BCF CONF_GRV_EEPROM MOVF EEADR,W MOVWF LOCAL_DA_UNIDADE BANCO_0 RETURN ;INICIA LEITURA ;W = UNIDADE ;W = W OR B'01100000' ;W = W XOR EEDATA ;VALOR DA UNIDADE FOI GRAVADO CORRETAMENTE? ;SIM ;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

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

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


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

133

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BITS DE CONFIGURAO

__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _CP_OFF & DATA_CP_OFF ;********************************************************************************************** ; ORG DE 2100 B'01100000', .0 INICIALIZAO DA EEPROM ;APONTA PARA O ENDEREO 00H DA EEPROM
;ESCREVE O NMERO BINRIO 01100000 NO ENDEREO 00H DA EEPROM

;E O NMERO DECIMAL 0 NA LOCALIDADE 01h ;********************************************************************************************** ; PAGINACAO DE MEMORIA #DEFINE BANCO_0 #DEFINE BANCO_1 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

;*********************************************************************************************** ; CBLOCK 0X70 W_TEMP STATUS_TEMP FLAGS DB1_BTA DB1_BTB DB2_BTA DB2_BTB UNIDADE DEZENA ESC_EEPROM_A ESC_EEPROM_B LOCAL_DA_UNIDADE ENDC VARIVEIS ;ENDERECO PRIMEIRA VARIVEL ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W
;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS

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

;FIM DO BLOCO DE MEMORIA

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

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

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

134

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

; #DEFINE #DEFINE BOTAO_1 BOTAO_2 PORTA,0 PORTA,1

ENTRADAS ;BOTAO 1 LIGADO EM RA0 ;BOTAO 2 LIGADO EM RA1

;*********************************************************************************************** ; FLAGS #DEFINE SOLTAR_BOTAO_1 #DEFINE SOLTAR_BOTAO_2 #DEFINE APAGAR_UNIDADE FLAGS,0 FLAGS,1 FLAGS,2 ;SE = 1, AGUARDA SOLTAR O BOTO 1 ;SE = 1, AGUARDA SOLTAR O BOTO 2
;SE = 1, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE

#DEFINE GRAVAR_UNIDADE FLAGS,3 ;SE = 1, GRAVAR UNIDADE NA EEPROM #DEFINE GRAVAR_DEZENA FLAGS,4 ;SE = 1, GRAVAR DEZENA NA EEPROM #DEFINE ESP_FIM_GRV_EEPROM FLAGS,5 ;SE = 1, ESPERA O FIM DA GRAVAO NA EEPROM #DEFINE CONF_GRV_EEPROM FLAGS,6 ;SE = 1, CONFERE A GRAVAO NA EEPROM ;*********************************************************************************************** ; VETOR DE RESET ORG GOTO 0X00 INICIO ;ENDERECO INICIAL DE PROCESSAMENTO ;DESVIA PARA INICIO

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

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

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

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

135

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010011'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:16

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

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

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

;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS CLRF FLAGS MOVLW INI_DB1_BTA MOVWF DB1_BTA MOVLW INI_DB1_BTB MOVWF DB1_BTB MOVLW INI_DB2_BTA MOVWF DB2_BTA MOVLW INI_DB2_BTB MOVWF DB2_BTB MOVLW INI_ESC_EEPROM_A MOVWF ESC_EEPROM_A MOVLW INI_ESC_EEPROM_B MOVWF ESC_EEPROM_B BANCO_1 MOVLW .254 MOVWF EEADR INICIALIZA_UNIDADE_E_DEZENA INCF EEADR,F ;INICIALIZA FLAGS ;W = INI_DB1_BTA ;INICIALIZA DB1_BTA ;W = INI_DB1_BTB ;INICIALIZA DB1_BTB ;W = INI_DB2_BTA ;INICIALIZA DB2_BTA ;W = INI_DB2_BTB ;INICIALIZA DB2_BTB ;W = INI_ESC_EEPROM_A ;INICIALIZA ESC_EEPROM_A ;W = INI_ESC_EEPROM_B ;INICIALIZA ESC_EEPROM_B ;SELECIONA BANCO 1 DE MEMORIA ;W = 254 ;INICIALIZA EEADR ;INCREMENTA EEADR

136

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

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

;*********************************************************************************************** PRINCIPAL CLRWDT CALL CALL CALL GOTO ;ROTINA PRINCIPAL DO PROGRAMA ;LIMPA O WDT ;CHAMA SUBROTINA ;CHAMA SUBROTINA ;CHAMA SUBROTINA ;DESVIA

TRATA_BOTAO_1 TRATA_BOTAO_2 GRAVA_EEPROM PRINCIPAL

;*********************************************************************************************** TRATA_BOTAO_1 BTFSS GOTO BTFSS RETURN BCF TESTA_BOTAO_1 BTFSC GOTO DECFSZ RETURN MOVLW MOVWF DECFSZ RETURN MOVLW MOVWF BSF INCF BSF BSF BSF MOVLW XORWF BTFSS RETURN CLRF SOLTAR_BOTAO_1 TESTA_BOTAO_1 BOTAO_1 SOLTAR_BOTAO_1 ;AGUARDA SOLTAR O BOTAO 1? ;NAO, DESVIA ;SIM, O BOTO 1 EST SOLTO? ;NAO, RETORNA ;SIM, APAGA FLAG

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

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

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

137

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

INCF MOVLW XORWF BTFSS RETURN CLRF RETURN

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

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

REINC_CONT_DEB_1 MOVLW INI_DB1_BTA MOVWF DB1_BTA MOVLW INI_DB1_BTB MOVWF DB1_BTB RETURN

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

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

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

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

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

138

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

EINC_CONT_DEB_2 MOVLW INI_DB2_BTA MOVWF DB2_BTA MOVLW INI_DB2_BTB MOVWF DB2_BTB RETURN

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

;********************************************************************************************** GRAVA_EEPROM BTFSC GOTO BTFSC GOTO BTFSC GOTO BTFSC GOTO BTFSC GOTO RETURN ESP_FIM_GRV_EEPROM TESTA_FIM_DA_GRAVACAO CONF_GRV_EEPROM CONFERE_DEZENA APAGAR_UNIDADE APAGA_UNIDADE_ANTERIOR GRAVAR_UNIDADE GRAVA_A_UNIDADE GRAVAR_DEZENA GRAVA_A_DEZENA ;AGUARDA O FIM DA GRAVACAO NA EEPROM? ;SIM ;NAO, CONFERIR A GRAVAO? ;SIM
;NAO, APAGAR A LOCALIDADE ANTERIOR DA UNIDADE?

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

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

;SELECIONA BANCO 1 DE MEMRIA


;W = ENDEREO DA EEPROM ONDE EST GRAVADA A UNIDADE

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

;SELECIONA O BANCO 0 DE MEMRIA ;RETORNA

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

139

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

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

;SELECIONA BANCO 0 DE MEMORIA ;RETORNA

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

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

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

140

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

BSF BCF BCF BANCO_0 RETURN

GRAVAR_DEZENA ESP_FIM_GRV_EEPROM CONF_GRV_EEPROM

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

;SELECIONA O BANCO 0 DE MEMRIA ;RETORNA

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

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

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

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

;SIM ;NAO, APAGA FLAG


;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE

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

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

141

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

142

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

143

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

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

144

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

145

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

146

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

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

Figura 5

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

147

Tutorial de Programao Assembly para Microcontroladores PIC -

Parte 6 Contador II

Figura 6

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

148

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

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

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

Figura 2

149

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

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

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

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

150

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

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

151

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

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

152

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

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

CCPR1L Tabela 1

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

153

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

0
Bit 9

0
Bit 8

0
Bit 7

1
Bit 6

1
Bit 5

0
Bit 4

0
Bit 3

1
Bit 2

1
Bit 1 CCP1CON Bit 5

0
Bit 0 CCP1CON Bit 4

CCPR1L Tabela 2

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

154

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

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

155

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

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

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

Na rotina de interrupo, a primeira instruo ser BTFSS INTCON,T0IF portanto, exclua as anteriores a ela. Essa instruo testa se a interrupo foi a do Timer 0. Caso no tenha sido, a instruo da prxima linha ser executada, onde samos da interrupo. Se a interrupo foi do Timer 0, apagamos o flag na linha seguinte:
;************************************************************************************************ ; ROTINA DE INTERRUPO ORG BTFSS RETFIE BCF 0X04 INTCON,T0IF INTCON,T0IF ;VETOR DAS INTERRUPES ;TMR0 ESTOUROU? ;NAO, SAI DA INTERRUPO ;SIM, APAGA O FLAG

A seguir, escrevemos o nmero 108 no registrador TMR0:


MOVLW MOVWF .108 TMR0 ;W = 108 ;REINICIA TMR0

156

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

Agora, testamos se o boto 1 est pressionado. Se estiver, desviamos o programa para onde esta a label INCREMENTA_CCPR1L:
BTFSS GOTO BOTAO_1 INCREMENTA_CCPR1L ;BOTAO 1 EST PRESSIONADO? ;SIM

Caso contrrio, testamos se o boto 2 est pressionado. Se estiver, desviamos o programa para onde est a label DECREMENTA_CCPR1L:
BTFSS GOTO BOTAO_2 DECREMENTA_CCPR1L ;NAO, BOTAO 2 EST PRESSIONADO? ;SIM

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


RETFIE ;NAO, SAI DA INTERRUPO

Em INCREMENTA_CCPR1L, primeiramente testamos se o valor do CCPR1L igual a 255, pois, se for, iremos sair da interrupo sem increment-lo, caso contrrio seu valor passaria para 0, apagando o LED e queremos que quando o brilho do LED chegar ao mximo, fique no mximo:
INCREMENTA_CCPR1L MOVLW .255 XORWF CCPR1L,W BTFSC STATUS,Z RETFIE ;W = 255 ;W = W XOR CCPRR1L ;CCPR1L = 255? ;SIM, SAI DA INTERRUPO

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


INCF RETFIE CCPR1L,F ;NAO, INCREMENTA CCPR1L ;SAI DA INTERRUPO

Em DECREMENTA_CCPR1L, primeiramente testamos se o valor do CCPR1L igual a 0, pois, se for, iremos sair da interrupo sem decrement-lo, caso contrrio seu valor passaria para 255, acendendo o LED no mximo brilho e queremos que quando o LED apagar, fique apagado:
DECREMENTA_CCPR1L MOVLW .0 XORWF CCPR1L,W BTFSC STATUS,Z RETFIE DECF CCPR1L,F RETFIE ;W = 0 ;W = W XOR CCPRR1L ;CCPR1L = 0? ;SIM, SAI DA INTERRUPO ;NAO, DECREMENTA CCPR1L ;SAI DA INTERRUPO

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

157

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

;*********************************************************************************************** ; INICIO BANCO_1 MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010110'


;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO COM PRESCALER DE 1:128

CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO

B'11010110' OPTION_REG

Vamos tambm configurar todos os pinos do PORTA como entradas:


MOVLW MOVWF B'11111111' TRISA ;W = B'11111111' ;CONFIGURA PORTA COMO ENTRADA

Quanto ao PORTB, vamos configurar o pino RB3/CCP1 como sada, pois a sada do sinal PWM, e os demais como entradas:
MOVLW MOVWF B'11110111' TRISB ;W = B'11110111' ;CONFIGURA BR3/CCP1 COMO SADA E DEMAIS COMO ENTRADA

A seguir, escrevemos o nmero 255 no registrador PR2:


MOVLW MOVWF .255 PR2 ;W = 255 ;PR2 = 255

Passamos agora para os registradores do banco 0, onde mantemos as configuraes do CMCON para que os pinos RA0 e RA1 possam ser usados como pinos de entrada, e do INTCON para que a interrupo do Timer 0 esteja habilitada:
BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 0 DE MEMORIA B'00000111' CMCON B'11100000' INTCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O ;HABILITA INTERRUPO DO TIMER 0

A seguir, configuramos o registrador T2CON para ativar o Timer 2 (bit2 = 1), com prescaler de 1:16 (bit 1 = 1):
MOVLW MOVWF B'00000110' T2CON ;ATIVA O TIMER 2, COM PRESCALER DE 1:16

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

Por fim, configuramos o registrador CCP1CON para habilitar o modo PWM, setando os bits 3 e 2 desse registrador:

158

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

MOVLW MOVWF

B'00001100' CCP1CON

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

Com isso, conclumos a configurao dos registradores de uso especfico. Em seguida, exclua a seo INICIALIZAO DAS VARIVEIS. A seguir vem a rotina principal. Vamos chamar esta parte do programa de ROTINA PARA AGUARDAR A INTERRUPO, afinal, no tem sentido cham-la de principal, j que a rotina mais importante deste programa a de interrupo. Aqui o programa ficar executando a instruo CLRWDT at que ocorra a interrupo:
;********************************************************************************************** ;ROTINA PARA AGUARDAR A INTERRUPO CLRWDT GOTO ;LIMPA O WDT ;RETORNA UMA LINHA

$-1

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

O programa est pronto, tendo ficado assm:


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

;*********************************************************************************************** ; BITS DE CONFIGURAO

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

;*********************************************************************************************** ; ENTRADAS #DEFINE #DEFINE BOTAO_1 BOTAO_2 PORTA,0 PORTA,1 ;BOTAO 1 LIGADO EM RA0 ;BOTAO 2 LIGADO EM RA1

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

159

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

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

INICIO

;*********************************************************************************************** ; ROTINA DE INTERRUPO ORG BTFSS RETFIE BCF MOVLW MOVWF BTFSS GOTO BTFSS GOTO RETFIE 0X04 INTCON,T0IF INTCON,T0IF .108 TMR0 BOTAO_1 INCREMENTA_CCPR1L BOTAO_2 DECREMENTA_CCPR1L ;VETOR DAS INTERRUPES ;TMR0 ESTOUROU? ;NAO, SAI DA INTERRUPO ;SIM, APAGA O FLAG ;W = 108 ;REINICIA TMR0 ;BOTAO 1 EST PRESSIONADO? ;SIM ;NAO, BOTAO 2 EST PRESSIONADO? ;SIM ;NAO, SAI DA INTERRUPO

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

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

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

;************************************************************************************************ ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW MOVWF MOVLW ;SELECIONA BANCO 1 DE MEMORIA ;W = B'11010110'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO COM PRESCALER DE 1:128

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

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

160

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

MOVWF CLRF MOVLW MOVWF

T2CON CCPR1L B'00001100' CCP1CON

;ATIVA O TIMER 2, COM PRESCALER DE 1:16 ;ZERA CCPR1L ;W = B'00001100' ;HABILITA MODO PWM DO MODULO CCP

;********************************************************************************************** ; ROTINA PARA AGUARDAR A INTERRUPO CLRWDT GOTO ;LIMPA O WDT ;RETORNA UMA LINHA

$-1

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

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

161

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

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

162

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

Figura 7

Agora vamos ver se o CCPR1L est sendo incrementado e decrementado pelos botes. Remova o breakpoint, dando outro duplo clique na linha da primeira instruo da interrupo. Posicione as janelas de forma a poder visualizar a janela Watch enquanto clica nos botes do Stimulus:

163

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

Figura 8 Clique no boto Run do simulador. No Stimulus, clique no boto da coluna Fire que leva o pino RA0 para nvel baixo (Set Low) para simular que o boto 1 foi pressionado. Observe que o CCPR1L foi incrementado at o valor 255. Agora, clique no boto que leva o pino RA0 para o nvel alto, para simular que o boto 1 foi solto. Em seguida, clique no boto que leva o pino RA1 para nvel 0, simulando que o boto 2 foi pressionado. Observe que o CCPR1L foi decrementado at o valor 0 e l ficou. Volte o pino RA1 para nvel alto, clicando no boto da terceira linha do Stimulus. Vamos medir o tempo que o boto 1 deve ficar pressionado para o CCPR1L ir de 0 at 255. Clique no boto Halt do simulador. Insira um breakpoint na linha que contem a instruo RETFIE, que executada quando o valor do CCPR1L for igual a 255:

164

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

Figura 9 Na janela do Stopwatch, clique em Zero. Clique no boto que leva o pino RA0 para nvel baixo simulando que o boto 1 foi pressionado. Clique no boto Run do simulador. Quando o programa parar no breakpoint, veja, no Stopwatch que transcorreu 4,84 segundos, conforme havamos projetado:

165

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

Figura 10 Remova o breakpoint. Clique no boto Run do simulador. No Stimulus, volte o pino RA0 para nvel alto. Repare que, quando o valor do CCPR1L igual a 255, o pino RB3 fica fixo em nvel alto. Por outro lado, quando o valor do CCPR1L igual a 0, ele fica fixo em nvel baixo. Com o valor do CCPR1L num ponto intermedirio, o estado do RB3 varia entre 0 e 1, indicando que temos o sinal PWM nesse pino. Grave o programa no microcontrolador, monte o circuito na protoboard e comprove o seu funcionamento. muito interessante. Se usarmos um rel de estado slido, ligado no pino RB3 podemos controlar equipamentos de maior potncia, como por exemplo, lmpadas incandescentes, aquecedores, motores eltricos, etc. Aqui termina esta parte do tutorial. Espero que tenha sido til para voc. Na prxima parte iremos desenvolver um frequencmetro. At l!

166

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Figura 1 POT1 um potencimetro linear de 100 k, onde podemos variar a frequncia do sinal. Trocando o capacitor C2, mudamos a escala da frequncia. Valores obtidos nos testes: 10 F 1 Hz a 40 Hz 1 F 16 Hz a 460 Hz 100 nF 150 Hz a 4.100 Hz 10 nF 1.400 Hz a 9.999 Hz

167

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Frequncia do sinal =

1 nmero de incrementos x 0,000001

168

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Simplificando essa frmula obtemos:

1 Frequncia do sinal =

1 x nmero de incrementos

1 0,000001

Frequncia do sinal =

1 nmero de incrementos

1.000.000

Frequncia do sinal =

1.000.000 nmero de incrementos

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

169

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Frequncia do sinal =

100.000.000 nmero de incrementos

Pois, o nmero de incrementos referente a 100 ciclos do sinal. No nosso programa teremos trs rotinas de interrupo: a do Timer 0, a do Timer 1 e a do mdulo CCP. Na rotina de interrupo do Timer 0, iremos controlar os dgitos do display. Na do Timer 1, iremos contar o nmero de estouros desse timer que ocorreram entre as cpias dos registradores, necessrio para o clculo do nmero de incrementos. Na interrupo do mdulo CCP, iremos calcular o nmero de incrementos. A frequncia do sinal ser calculada na rotina principal do programa. No MPLAB, abra o arquivo Contador.asm da parte 5 deste tutorial e salve-o com o nome Frequencimetro.asm. Na seo VARIAVEIS, exclua DB1_BTA, DB1_BTB, DB2_BTA e DB2_BTB e crie as seguintes variveis: CENTENA, MILHAR, REG1A, REG2A, REG1B, REG2B, REG3B, REG1C, REG2C, REG3C, DISP_DELAY, CAPTURA, MILHAO_1, MILHAO_2, MILHAO_3, MILHAO_4, UNI_TEMP, DEZ_TEMP, CEN_TEMP, MIL_TEMP:
;*********************************************************************************************** ; VARIVEIS CBLOCK 0X20 W_TEMP STATUS_TEMP FLAGS UNIDADE ;ENDERECO INICIAL DA MEMORIA DO USUARIO ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR W ;USADA PARA SALVAR O CONTEUDO DO REGISTRADOR STATUS ;REGISTRADOR DE FLAGS ;UNIDADE DA FREQUNCIA

170

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

DEZENA CENTENA MILHAR REG1A REG2A REG1B REG2B REG3B REG1C REG2C REG3C DISP_DELAY CAPTURA MILHAO_1 MILHAO_2 MILHAO_3 MILHAO_4 UNI_TEMP DEZ_TEMP CEN_TEMP MIL_TEMP ENDC

;DEZENA DA FREQUNCIA ;CENTENA DA FREQUNCIA ;MILHAR DA FREQUNCIA ;REGISTRADOR MENOS SIGNIFICATIVO DA 1 CAPTURA ;REGISTRADOR MAIS SIGNIFICATIVO DA 1 CAPTURA ;REGISTRADOR MENOS SIGNIFICATIVO DA 2 CAPTURA ;REGISTRADOR MAIS SIGNIFICATIVO DA 2 CAPTURA ;REGISTRADOR QUE CONTA OS ESTOUROS DO TIMER 1 ;REGISTRADOR MENOS SIGNIFICATIVO DO N DE INCREMENTOS ;REGISTRADOR INTERMEDIRIO DO N DE INCREMENTOS ;REGISTRADOR MAIS SIGNIFICATIVO DO N DE INCREMENTOS ;CONTA 250 MS ENTRE EXIBIES DA FREQUNCIA ;CONTA AS CAPTURAS DO MDULO CCP ;PRIMEIRO REGISTRADOR DO NMERO 1.000.000 ;SEGUNDO REGISTRADOR DO NMERO 1.000.000 ;TERCEIRO REGISTRADOR DO NMERO 1.000.000 ;QUARTO REGISTRADOR DO NMERO 100.000.000 ;REGISTRADOR TEMPORRIO DA UNIDADE ;REGISTRADOR TEMPORRIO DA DEZENA ;REGISTRADOR TEMPORRIO DA CENTENA ;REGISTRADOR TEMPORRIO DO MLHAR ;FIM DO BLOCO DE MEMORIA

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

Exclua a seo CONSTANTES. Na seo SAIDAS, defina a label DIG_UNI para o RA0, que ser o dgito da unidade, DIG_DEZ para o RA1, que ser o dgito da dezena, DIG_CEN para o RA2, que ser o dgito da centena e DIG_MIL para o RA3, que ser o dgito do milhar, SEG_A para o RB0, SEG_B para o RB1, SEG_C para o RB2, SEG_D para o RB4, SEG_E para o RB5, SEG_F para o RB6 e SEG_G para o RB7 (teremos de controlar individualmente os segmentos do display, j que o pino RB3 a entrada do sinal:
;*********************************************************************************************** ; SADAS #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE #DEFINE DIG_UNI DIG_DEZ DIG_CEN DIG_MIL SEG_A SEG_B SEG_C SEG_D SEG_E SEG_F SEG_G PORTA,0 PORTA,1 PORTA,2 PORTA,3 PORTB,0 PORTB,1 PORTB,2 PORTB,4 PORTB,5 PORTB,6 PORTB,7 ;SE = 1, DIGITO DA UNIDADE ATIVADO ;SE = 1, DIGITO DA DEZENA ATIVADO ;SE = 1, DIGITO DA CENTENA ATIVADO ;SE = 1, DIGITO DO MILHAR ATIVADO ;SEGMENTO A DO DISPLAY ;SEGMENTO B DO DISPLAY ;SEGMENTO C DO DISPLAY ;SEGMENTO D DO DISPLAY ;SEGMENTO E DO DISPLAY ;SEGMENTO F DO DISPLAY ;SEGMENTO G DO DISPLAY

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

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

171

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;*********************************************************************************************** ; FLAGS #DEFINE #DEFINE #DEFINE CALCULAR_FREQ CEM_MILHOES ATUALIZA_DISP FLAGS,0 FLAGS,1 FLAGS,2 ;SE = 1 A FREQUENCIA PODE SER CALCULADA ;SE = 100.000.000/N. DE INCREMENTOS ;SE = 1, ATUALIZAR VALOR DO DISPLAY

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

Na rotina de interrupo, primeiramente temos de testar qual das trs interrupes ocorreu. Para verificar se a interrupo foi a do Timer 0, devemos testar o bit T0IF do registrador INTCON. Para a do Timer 1, o bit TMR1IF do registrador PIR1. Para a do mdulo CCP, o bit CCP1IF tambm do registrador PIR1. Portanto, a rotina de interrupo comea assim:
;************************************************************************************************* ; ROTINA DE INTERRUPO ORG MOVWF SWAPF BANCO_0 MOVWF BTFSC GOTO BTFSC GOTO BTFSC GOTO GOTO 0X04 W_TEMP STATUS,W STATUS_TEMP INTCON,T0IF INT_TIMER_0 PIR1,TMR1IF INT_TIMER_1 PIR1,CCP1IF INT_CCP SAI_INT ;VETOR DAS INTERRUPES ;SALVA W ;W = SWAP EM STATUS ;CHAVEIA PARA BANCO 0 DE MEMORIA ;SALVA STATUS ;INTERRUPO DO TIMER 0? ;SIM ;NO, INTERRUPO DO TIMER 1? ;SIM ;NO, INTERRUPO DO MDULO CCP? ;SIM ;NO, SAI DA INTERRUPO

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

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

172

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

DECFSZ GOTO BSF

DISP_DELAY,F TESTA_DIG_ATIVO ATUALIZA_DISP

;DECREMENTA DISP_DELAY. DISP_DELAY = 0? ;NO ;SIM, SETA FLAG

A seguir, testamos qual dgito est ativado:


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

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

Repare que estamos controlando cada segmento do display individualmente, diferentemente do que fizemos nos programas das parte 5 e 6 deste tutorial, pois, o PORTB no exclusivo dos displays (RB3 a entrada do sinal). Procedimento semelhante feito para os outros dgitos:
CONT_DIG_DEZ BCF DIG_CEN BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_DEZ MOVF DEZENA,W GOTO CONV_BIN_7_SEG CONT_DIG_UNI BCF DIG_DEZ BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D ;DESATIVA DGITO DA CENTENA ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA DEZENA ;COPIA DEZENA PARA O W ;CHAMA SUBROTINA

;DESATIVA DGITO DA DEZENA ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO

173

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_UNI MOVF UNIDADE,W GOTO CONV_BIN_7_SEG CONT_DIG_MIL BCF DIG_UNI BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_MIL MOVF MILHAR,W GOTO CONV_BIN_7_SEG

;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA UNIDADE ;COPIA UNIDADE PARA O W ;CHAMA SUBROTINA ;DESATIVA DGITO DA UNIDADE ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA MILHAR ;COPIA MILHAR PARA O W ;CHAMA SUBROTINA

Na subrotina de converso de binrio para 7 segmentos, primeiramente somamos ao registrador PCL o valor que est no registrador W. Em seguida, o programa ir pular um nmero de linhas igual ao valor do W, caindo numa instruo GOTO que o direcionar para uma sequncia de instrues que ativam os segmentos que formam o nmero a ser mostrado, saindo da interrupo ao final:
CONV_BIN_7_SEG ADDWF PCL,F GOTO NUM_ZERO GOTO NUM_UM GOTO NUM_DOIS GOTO NUM_TRES GOTO NUM_QUATRO GOTO NUM_CINCO GOTO NUM_SEIS GOTO NUM_SETE GOTO NUM_OITO GOTO NUM_NOVE NUM_ZERO BSF SEG_A BSF SEG_B BSF SEG_C BSF SEG_D BSF SEG_E BSF SEG_F GOTO SAI_INT NUM_UM BSF SEG_B BSF SEG_C GOTO SAI_INT NUM_DOIS BSF SEG_A BSF SEG_B BSF SEG_D BSF SEG_E BSF SEG_G GOTO SAI_INT ;PCL = PCL + W ;W = 0 ;W = 1 ;W = 2 ;W = 3 ;W = 4 ;W = 5 ;W = 6 ;W = 7 ;W = 8 ;W = 9 ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

174

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

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

175

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

176

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Em seguida, precisamos saber se a interrupo referente 1 captura. Incrementamos a varivel CAPTURA e testamos se o seu valor igual a 1. Se for, tratar-se- da 1 captura:
INCF MOVLW XORWF BTFSC GOTO CAPTURA,F .1 CAPTURA,W STATUS,Z PRIMEIRA_CAPTURA ;INCREMENTA CAPTURA ;W = 1 ;W = CAPTURA XOR 1 ;CAPTURA = 1? ;SIM

Na subrotina PRIMEIRA_CAPTURA, copiamos o valor do registrador CCPR1L para o REG1A e o do CCPR1H para o REG2A, zeramos o REG3B e samos da interrupo:
PRIMEIRA_CAPTURA MOVF CCPR1L,W MOVWF REG1A MOVF CCPR1H,W MOVWF REG2A CLRF REG3B GOTO SAI_INT

;W = CCPR1L ;REG1A = CCPR1L ;W = CCPR1H ;REG2A = CCPR1H ;REG3B = 0 ;SAI DA INTERRUPO

177

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Na prxima interrupo do mdulo CCP, a varivel CAPTURA ser incrementada novamente e seu valor ser igual a 2, o que significar que a 2 captura, ento desviamos para a subrotina CALC_INC:
MOVLW XORWF BTFSC GOTO .2 CAPTURA,W STATUS,Z CALC_INC ;NO, W = 2 ;W = CAPTURA XOR 2 ;CAPTURA = 2? ;SIM

Na subrotina CALC_INC, copiamos o valor do registrador CCPR1L para a varivel REG1B e o do CCPR1H para a varivel REG2B:
CALC_INC MOVF MOVWF MOVF MOVWF CCPR1L,W REG1B CCPR1H,W REG2B ;W = CCPR1L ;REG1B = CCPR1L ;W = CCPR1H ;REG2B = CCPR1H

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

REG3B =

REG2B REG2A

REG1B REG1A

Os passos para efetuar essa operao so semelhantes aos realizados numa operao de subtrao no sistema decimal. Por exemplo, para subtrair o nmero 32 do nmero 164, primeiramente subtramos os algarismos menos significativos, ou seja, as unidades: 1 0 6 3 4 2 2 =

A seguir, subtramos os prximos algarismos em ordem de significncia, as dezenas: 1 0 6 3 3 4 2 2 =

Por fim, subtramos as centenas:

1 0 1

6 3 3

4 2 2

178

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Com registradores, fazemos a mesma coisa; subtramos os registradores menos significativos (REG1B REG1A), depois os prximos (REG2B REG2A) e assim por diante. Mas, a coisa complica um pouco quando o algarismo a ser subtrado menor, como, por exemplo, na operao 192 65: 1 0 9 6 2 5 =

Nesse caso, para subtrair a unidade, temos de decrementar a dezena e somar 10 unidade: 1 1 0 9 8 6 2 12 5 7 -

Depois, subtramos a dezena:

1 1 0

9 8 6 2

2 12 5 7

E, finalmente a centena:

1 1 0 1

9 8 6 2

2 12 5 7

Se, ao precisar decrementar a dezena, o seu valor for igual a 0, teremos de decrementar a centena, somar 10 dezena, decrement-la, e somar 10 unidade, como por exemplo, na operao 102 34: 1 0 0 3 2 4 =

179

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

1 0 0

0 10 3

2 2 4

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

1 0 0 0

0 2 10 2 9 12 3 4 6 8

1 0 0 0 0

0 2 10 2 9 12 3 4 6 8

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

180

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

REG1B REG1A

RESULTADO POSITIVO

RESULTADO NEGATIVO

REG2B REG2A

DECREMENTA REG2B

RESULTADO POSITIVO

RESULTADO NEGATIVO

REG2B 255

REG2B = 255

OPERAO CONCLUDA

DECREMENTA REG3B

REG2B REG2A

DECREMENTA REG3B

OPERAO CONCLUDA

RESULTADO POSITIVO

RESULTADO NEGATIVO

REG2B REG2A

OPERAO CONCLUDA

DECREMENTA REG3B

RESULTADO POSITIVO

RESULTADO NEGATIVO

OPERAO CONCLUDA

OPERAO CONCLUDA

DECREMENTA REG3B

OPERAO CONCLUDA

Figura 2

181

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Comeamos subtraindo os registradores menos significativos, ou seja, fazemos REG1B REG1A:


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

A instruo SUBWF REG1B,F subtrai o valor de W, que igual a REG1A, do valor de REG1B e salva o resultado no prprio REG1B. O resultado poder ser positivo, se REG1B > REG1A ou negativo, se REG1B < REG1A. Para sabermos se o resultado foi positivo ou negativo, testamos o bit C do registrador STATUS, que ser igual a 0 se o resultado for negativo. Se o resultado for positivo, desviamos para a subrotina SEG_SUB, onde iremos fazer REG2B REG2A. Se o resultado for negativo, decrementamos o REG2B e, em seguida, testamos se o seu valor igual a 255:
BTFSC GOTO DECF MOVLW XORWF BTFSS STATUS,C SEG_SUB REG2B,F .255 REG2B,W STATUS,Z ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA REG2B ;W = 255 ;W = REG2B XOR 255 ;REG2B = 255?

Se o valor de REG2B for diferente de 255, desviamos para a subrotina SEG_SUB, caso contrrio, decrementamos REG3B e, a seguir, entramos na subrotina SEG_SUB, onde fazemos REG2B REG2A e testamos se o resultado negativo:
GOTO DECF SEG_SUB MOVF SUBWF BTFSC SEG_SUB REG3B,F REG2A,W REG2B,F STATUS,C ;NO ;SIM, DECREMENTA REG3B ;W = REG2A ;REG2B = REG2B - REG2A ;RESULTADO NEGATIVO?

Se o resultado for positivo, o processo de subtrao terminou, caso contrrio, decrementamos o registrador REG3B e estar concluda a subtrao:
BTFSC GOTO DECF STATUS,C TST_NR_INC REG3B,F ;RESULTADO NEGATIVO? ;NO, OPERAO CONCLUDA ;SIM, DECREMENTA REG3B

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

182

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Primeiramente, verificamos se REG2B maior do que 3, copiando seu valor para W e executando a instruo SUBLW .3 Essa instruo efetua a operao 3 W e salva o resultado no W.:
TST_NR_INC MOVF SUBLW REG2B,W .3 ;W = REG2B ;W = 3 REG2B

A seguir, verificamos qual foi o resultado. Se REG2B for igual ou menor do que 3, o resultado ser positivo. Nesse caso, desviamos para a subrotina TST_MENOR_3:
BTFSC GOTO STATUS,C TST_MENOR_3 ;REG2B MAIOR DO QUE 3? ;NAO

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

O clculo da frequncia, que feito na rotina principal, demora um certo tempo. Por isso, a seguir, testamos se o flag CALCULAR_FREQ est setado, pois, se estiver, o clculo iniciado com os valores da captura anterior ainda no foi concludo. Nesse caso, samos da interrupo, ou seja, os valores dessa captura sero desprezados:
BTFSC GOTO CALCULAR_FREQ SAI_INT ;FREQUNCIA SENDO CALCULADA? ;SIM, SAI DA INTERRUPO

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


GOTO COPIA_NR_INC ;NAO, DESVIA

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

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

183

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

TST_MENOR_3 MOVF REG2B,W SUBLW .2 BTFSC STATUS,C GOTO SAI_INT

;W = REG2B ;W = 2 REG2B ;REG2B MENOR DO QUE 3? ;SIM

Se o resultado da operao anterior foi negativo, significa que REG2B igual 3. Nesse caso, testamos o valor do REG1B para ver se maior do que 232:

MOVF SUBLW BTFSC

REG1B,W .232 STATUS,C

;NO, W = REG1B ;W = 232 REG1B ;REG1B MAIOR DO QUE 232?

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

Se REG1B for maior do que 232, o resultado ser negativo, o que significa que o nmero de incrementos maior do que 1.000, ento, zeramos a varivel CAPTURA, e testamos se o flag CALCULAR_FREQ est setado:
CLRF BTFSC CAPTURA CALCULAR_FREQ ;SIM, CAPTURA = 0 ;FREQUNCIA SENDO CALCULADA?

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


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

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

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

184

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Na subrotina SAI_INT, recuperamos os registradores W e STATUS:


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

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

185

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

CALCULAR_FREQ PRINCIPAL

Se ele estiver setado, testamos o flag CEM_MILHOES, para verificar se iremos dividir 1.000.000 ou 100.000.000 pelo nmero de incrementos, e, conforme o caso, iniciamos os registradores com os valores devidos. No caso de 100.000.000, apagamos o flag CEM_MILHOES:
BTFSC CEM_MILHOES GOTO DIV_CEM_MILHOES MOVLW .64 MOVWF MILHAO_1 MOVLW .66 MOVWF MILHAO_2 MOVLW .15 MOVWF MILHAO_3 CLRF MILHAO_4 GOTO INICIA_DIVISAO DIV_CEM_MILHOES BCF CEM_MILHOES CLRF MILHAO_1 MOVLW .225 MOVWF MILHAO_2 MOVLW .245 MOVWF MILHAO_3 MOVLW .5 MOVWF MILHAO_4 ;SIM, DIVIDIR 1.000.000 OU 100.000.000? ;100.000.000 ;1.000.000. W = 64 ;MILHAO_1 = 64 ;W = 66 ;MILHAO_2 = 66 ;W = 15 ;MILHAO_3 = 15 ;MILHAO_4 = 0

;APAGA FLAG ;MILHAO_1 = 0 ;W = 225 ;MILHAO_2 = 225 ;W = 245 ;MILHAO_3 = 245 ;W = 5 ;MILHAO_3 = 4

Vamos comear a diviso, lembrando que o nmero de incrementos o valor formado pelos registradores REG3C, REG2C e REG1C. Primeiramente zeramos as variveis temporrias:

186

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

INICIA_DIVISAO CLRF UNI_TEMP CLRF DEZ_TEMP CLRF CEN_TEMP CLRF MIL_TEMP

;UNI_TEMP = 0 ;DEZ_TEMP = 0 ;CEN_TEMP = 0 ;MIL_TEMP = 0

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

Em seguida, subtramos os registradores menos significativos, ou seja, fazemos MILHAO_1 REG1C:


MOVF SUBWF REG1C,W MILHAO_1,F ;W = REG1C ;MILHAO_1 = MILHAO_1 - REG1C

A seguir verificamos qual foi o resultado. Se foi positivo, desviamos o programa para onde est a label SEG_DIV_1, onde iremos subtrair os prximos registradores, ou seja, MILHAO_2 REG2C. Se o resultado foi negativo, decrementamos MILHAO_2, e, a seguir, testamos se o seu valor igual a 255:
BTFSC GOTO DECF MOVLW XORWF BTFSS STATUS,C SEG_DIV_1 MILHAO_2,F .255 MILHAO_2,W STATUS,Z ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA MILHAO_2 ;W = 255 ;W = MILHAO_2 XOR 255 ;MILHAO_2 = 255?

Se o valor de MILHAO_2 for diferente de 255, desviamos para SEG_DIV_1, caso contrrio, decrementamos MILHAO_3 e verificamos se o seu valor igual a 255:
GOTO DECF MOVLW XORWF BTFSS SEG_DIV_1 MILHAO_3,F .255 MILHAO_3,W STATUS,Z ;NAO ;SIM, DECREMENTA MILHAO_3 ;W = 255 ;W = MILHAO_3 XOR 255 ;MILHAO_3 = 255?

Se o valor de MILHAO_3 for diferente de 255, desviamos para SEG_DIV_1, caso contrrio, decrementamos MILHAO_4 e verificamos se o seu valor igual a 255:
GOTO DECF MOVLW XORWF BTFSC SEG_DIV_1 MILHAO_4,F .255 MILHAO_4,W STATUS,Z ;NAO ;SIM, DECREMENTA MILHAO_4 ;W = 255 ;W = MILHAO_4 XOR 255 ;MILHAO_4 = 255?

Se o valor de MILHAO_4 for igual a 255, a diviso terminou. Caso contrrio, entramos na subrotina SEG_DIV_1, onde fazemos MILHAO_2 REG2C:

187

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

GOTO SEG_DIV_1 MOVF SUBWF

DIVISAO_TERMINOU REG2C,W MILHAO_2,F

;SIM ;W = REG2C ;MILHAO_2 = MILHAO_2 - REG2C

A seguir, verificamos qual foi o resultado. Se foi positivo, desviamos para SEG_DIV_2, onde iremos subtrair os prximos registradores, ou seja, faremos MILHAO_3 REG3C. Se o resultado foi negativo, decrementamos MILHAO_3 e, em seguida, verificamos se o seu valor igual a 255:
BTFSC GOTO DECF MOVLW XORWF BTFSS STATUS,C SEG_DIV_2 MILHAO_3,F .255 MILHAO_3,W STATUS,Z ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA MILHAO_3 ;W = 255 ;W = MILHAO_3 XOR 255 ;MILHAO_3 = 255?

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

Se o valor de MILHAO_4 for igual a 255, a diviso terminou. Caso contrrio, entramos na subrotina SEG_DIV_2, onde fazemos MILHAO_3 REG3C:
GOTO SEG_DIV_2 MOVF SUBWF DIVISAO_TERMINOU REG3C,W MILHAO_3,F ;SIM ;NAO, W = REG3C ;MILHAO_3 = MILHAO_3 - REG3C

A seguir, verificamos se o resultado foi negativo. Se foi positivo, a subtrao foi possvel e, ento, desviamos para INC_UNI_TEMP, onde iremos incrementar a varivel UNI_TEMP. Se o resultado foi negativo, decrementamos MILHAO_4 e verificamos se o seu valor igual a 255:
BTFSC GOTO DECF MOVLW XORWF BTFSC STATUS,C INC_UNI_TEMP MILHAO_4,F .255 MILHAO_4,W STATUS,Z ;RESULTADO NEGATIVO? ;NAO ;SIM, DECREMENTA MILHAO_4 ;W = 255 ;W = MILHAO_4 XOR 255 ;MILHAO_4 = 255?

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

188

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Nesta subrotina, incrementamos UNI_TEMP e verificamos se o seu valor igual a 10. Se for diferente de 10, desviamos para CICLO_DE_SUBTRACAO para efetuarmos outra subtrao:
INCF MOVLW XORWF BTFSS GOTO UNI_TEMP,F .10 UNI_TEMP,W STATUS,Z CICLO_DE_SUBTRACAO ;INCREMENTA UNI_TEMP ;W = 10 ;W = UNI_TEMP XOR 10 ;UNI_TEMP = 10? ;NO

Se o valor de UNI_TEMP for igual a 10, zeramos essa varivel e incrementamos a varivel DEZ_TEMP. Aps increment-la, testamos se o seu valor igual a 10. Se no for, desviamos para CICLO_DE_SUBTRACAO. Se for, zeramo-la e assim por diante at a varivel MIL_TEMP:
CLRF INCF MOVLW XORWF BTFSS GOTO CLRF INCF MOVLW XORWF BTFSS GOTO CLRF INCF UNI_TEMP DEZ_TEMP,F .10 DEZ_TEMP,W STATUS,Z CICLO_DE_SUBTRACAO DEZ_TEMP CEN_TEMP,F .10 CEN_TEMP,W STATUS,Z CICLO_DE_SUBTRACAO CEN_TEMP MIL_TEMP,F ;SIM, UNI_TEMP = 0 ;INCREMENTA DEZ_TEMP ;W = 10 ;W = DEZ_TEMP XOR 10 ;DEZ_TEMP = 10? ;NO ;SIM, DEZ_TEMP = 0 ;INCREMENTA CEN_TEMP ;W = 10 ;W = CEN_TEMP XOR 10 ;CEN_TEMP = 10? ;NO ;SIM, CEN_TEMP = 0 ;INCREMENTA MIL_TEMP

Depois de incrementar a varivel MIL_TEMP, testamos se o seu valor igual a 10. Se o valor de MIL_TEMP for diferente de 10, desviamos para CICLO_DE_SUBTRACAO. Se for igual a 10, zeramo-la, e, em seguida, desviamos para DIVISAO_TERMINOU:
MOVLW XORWF BTFSS GOTO CLRF GOTO .10 MIL_TEMP,W STATUS,Z CICLO_DE_SUBTRACAO MIL_TEMP DIVISAO_TERMINOU ;W = 10 ;W = MIL_TEMP XOR 10 ;MIL_TEMP = 10? ;NO ;SIM, MIL_TEMP = 0

Na subrotina DIVISAO_TERMINOU, primeiramente zeramos o flag CALCULAR_FREQ:


DIVISAO_TERMINOU BCF CALCULAR_FREQ ;APAGA FLAG

A seguir, testamos o flag ATUALIZA_DISP. Se esse flag estiver apagado, significa que no hora de atualizar o display e, portanto, voltamos para o incio da rotina PRINCIPAL:

189

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BTFSS GOTO

ATUALIZA_DISP PRINCIPAL

;ATUALIZAR O DISPLAY? ;NO

Se ele estiver setado, zeramo-lo, copiamos os valores das variveis intermedirias e voltamos para o incio da rotina PRINCIPAL:
BCF MOVF MOVWF MOVF MOVWF MOVF MOVWF MOVF MOVWF GOTO ATUALIZA_DISP UNI_TEMP,W UNIDADE DEZ_TEMP,W DEZENA CEN_TEMP,W CENTENA MIL_TEMP,W MILHAR PRINCIPAL ;SIM, APAGA FLAG ;W = UNI_TEMP ;UNIDADE = UNI_TEMP ;W = DEZ_TEMP ;DEZENA = DEZ_TEMP ;W = CEN_TEMP ;CENTENA = CEN_TEMP ;W = MIL_TEMP ;MILHAR = MIL_TEMP

Por fim, encerramos o programa:


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

Na seo CONFIGURAO DOS REGISTRADORES DE USO ESPECFICO, vamos configurar o registrador OPTION_REG para que o prescaler do Timer 0 seja de 8:1:
;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF ;SELECIONA BANCO 1 DE MEMORIA B'10000010' ;W = B'10000010' OPTION_REG ;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:8

Configuramos o registrador TRISA para que os pinos RA0, RA1, RA2 e RA3 sejam sadas e os demais entradas e o TRISB para que o pino RB3 seja entrada e os demais sadas:
MOVLW MOVWF MOVLW MOVWF B'11110000' TRISA B'00001000' TRISB ;W = B'11110000'
;CONFIGURA RA0, RA1, RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS ;CONFIGURA O PINO RB3 COMO ENTRADA E DEMAIS COMO SAIDAS

Configuramos o registrador PIE1 para habilitamos as interrupes do Timer 1 e do mdulo CCP:


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

190

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

Em seguida, liberamos os pinos RA0 a RA3 do mdulo comparador, configurando o registrador CMCON e habilitamos a interrupo do Timer 0, no registrador INTCON:
BANCO_0 MOVLW MOVWF MOVLW MOVWF ;SELECIONA BANCO 0 DE MEMORIA B'00000111' CMCON B'11100000' INTCON ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O ;HABILITA INTERRUPO DO TIMER 0

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


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

Finalmente, configuramos o registrador CCP1CON para habilitar o modo capture do mdulo CCP para que efetue uma captura a cada mudana de nvel baixo para alto no pino RB3:
MOVLW MOVWF B'00000101' CCP1CON ;HABILITA MODO CAPTURE A CADA MUDANA DE BAIXO PARA ALTO

Essas configuraes constam no datasheet do PIC16F628A, nas sees que tratam do Timer 0, Mdulo Comparador, PORTA, PORTB, Timer 1 e Mdulo CCP. Na seo INICIALIZAO DA VARIVEIS, inicializamos as variveis FLAGS, UNIDADE, DEZENA, CENTENA e MILHAR, REG3B com o valor 0.
;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS CLRF CLRF CLRF CLRF CLRF CLRF CLRF FLAGS UNIDADE DEZENA CENTENA MILHAR REG3B CAPTURA ;INICIALIZA FLAGS ;INICIALIZA UNIDADE ;INICIALIZA DEZENA ;INICIALIZA CENTENA ;INICIALIZA MILHAR ;INICIALIZA REG3B ;INICIALIZA CAPTURA

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


;*********************************************************************************************** ; PROGRAMA: FREQUENCIMETRO ; VERSO 1.0 ; DESENVOLVIDO POR: MULDER_FOX ; DATA DE CONCLUSO: / / ;*********************************************************************************************** #INCLUDE <P16F628A.INC> ;ARQUIVO PADRAO MICROCHIP PARA O PIC16F628A

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

191

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;********************************************************************************************** ; PAGINACAO DE MEMORIA #DEFINE BANCO_0 #DEFINE BANCO_1 BCF STATUS,RP0 ;SETA BANCO 0 DE MEMORIA BSF STATUS,RP0 ;SETA BANCO 1 DE MEMORIA

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

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

192

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

;*********************************************************************************************** ; FLAGS #DEFINE #DEFINE #DEFINE CALCULAR_FREQ CEM_MILHOES ATUALIZA_DISP FLAGS,0 FLAGS,1 FLAGS,2 ;SE = 1 A FREQUENCIA PODE SER CALCULADA ;SE = 100.000.000/N. DE INCREMENTOS ;SE = 1, ATUALIZAR VALOR DO DISPLAY

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

INICIO

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

INT_TIMER_0 BCF INTCON,T0IF DECFSZ DISP_DELAY,F GOTO TESTA_DIG_ATIVO BSF ATUALIZA_DISP TESTA_DIG_ATIVO BTFSC DIG_MIL GOTO CONT_DIG_CEN BTFSC DIG_CEN GOTO CONT_DIG_DEZ BTFSC DIG_DEZ GOTO CONT_DIG_UNI GOTO CONT_DIG_MIL CONT_DIG_CEN BCF DIG_MIL BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_CEN MOVF CENTENA,W GOTO CONV_BIN_7_SEG

;APAGA FLAG ;DECREMENTA DISP_DELAY. DISP_DELAY = 0? ;NO ;SIM, SETA FLAG ;DGITO DO MILHAR EST ATIVADO? ;SIM ;NO, DGITO DA CENTENA EST ATIVADO? ;SIM ;NO, DGITO DA DEZENA EST ATIVADO? ;SIM ;NAO

;DESATIVA DGITO DO MILHAR ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA CENTENA ;COPIA CENTENA PARA O W ;CHAMA SUBROTINA

193

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

CONT_DIG_DEZ BCF DIG_CEN BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_DEZ MOVF DEZENA,W GOTO CONV_BIN_7_SEG CONT_DIG_UNI BCF DIG_DEZ BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_UNI MOVF UNIDADE,W GOTO CONV_BIN_7_SEG CONT_DIG_MIL BCF DIG_UNI BCF SEG_A BCF SEG_B BCF SEG_C BCF SEG_D BCF SEG_E BCF SEG_F BCF SEG_G BSF DIG_MIL MOVF MILHAR,W GOTO CONV_BIN_7_SEG CONV_BIN_7_SEG ADDWF PCL,F GOTO NUM_ZERO GOTO NUM_UM GOTO NUM_DOIS GOTO NUM_TRES GOTO NUM_QUATRO GOTO NUM_CINCO GOTO NUM_SEIS GOTO NUM_SETE GOTO NUM_OITO GOTO NUM_NOVE NUM_ZERO BSF BSF BSF BSF BSF BSF GOTO

;DESATIVA DGITO DA CENTENA ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA DEZENA ;COPIA DEZENA PARA O W ;CHAMA SUBROTINA ;DESATIVA DGITO DA DEZENA ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA UNIDADE ;COPIA UNIDADE PARA O W ;CHAMA SUBROTINA ;DESATIVA DGITO DA UNIDADE ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;APAGA SEGMENTO ;ATIVA DGITO DA MILHAR ;COPIA MILHAR PARA O W ;CHAMA SUBROTINA

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

SEG_A SEG_B SEG_C SEG_D SEG_E SEG_F SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

194

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

NUM_UM BSF BSF GOTO NUM_DOIS BSF BSF BSF BSF BSF GOTO NUM_TRES BSF BSF BSF BSF BSF GOTO

SEG_B SEG_C SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_B SEG_D SEG_E SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_B SEG_C SEG_D SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

NUM_QUATRO BSF SEG_B BSF SEG_C BSF SEG_F BSF SEG_G GOTO SAI_INT NUM_CINCO BSF BSF BSF BSF BSF GOTO NUM_SEIS BSF BSF BSF BSF BSF BSF GOTO NUM_SETE BSF BSF BSF GOTO NUM_OITO BSF BSF BSF BSF BSF

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_C SEG_D SEG_F SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_C SEG_D SEG_E SEG_F SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_B SEG_C SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_B SEG_C SEG_D SEG_E

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

195

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BSF BSF GOTO NUM_NOVE BSF BSF BSF BSF BSF BSF GOTO INT_TIMER_1 BCF INCF GOTO INT_CCP CLRF INCF MOVLW XORWF BTFSC GOTO MOVLW XORWF BTFSC GOTO MOVLW XORWF BTFSS GOTO BSF GOTO

SEG_F SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO

SEG_A SEG_B SEG_C SEG_D SEG_F SEG_G SAI_INT

;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO ;ACENDE SEGMENTO

PIR1,TMR1IF REG3B SAI_INT

;APAGA FLAG ;INCREMENTA REG3B ;SAI DA INTERRUPO

PIR1,CCP1IF CAPTURA,F .1 CAPTURA,W STATUS,Z PRIMEIRA_CAPTURA .2 CAPTURA,W STATUS,Z CALC_INC .101 CAPTURA,W STATUS,Z SAI_INT CEM_MILHOES CALC_INC

;APAGA FLAG ;INCREMENTA CAPTURA ;W = 1 ;W = CAPTURA XOR 1 ;CAPTURA = 1? ;SIM ;NO, W = 2 ;W = CAPTURA XOR 2 ;CAPTURA = 2? ;SIM ;NO, W = 101 ;W = CAPTURA XOR 101 ;CAPTURA = 101? ;NAO, SAI DA INTERRUPO ;SIM, SETA FLAG

PRIMEIRA_CAPTURA MOVF CCPR1L,W MOVWF REG1A MOVF CCPR1H,W MOVWF REG2A CLRF REG3B GOTO SAI_INT CALC_INC MOVF MOVWF MOVF MOVWF MOVF SUBWF BTFSC GOTO DECF MOVLW XORWF

;W = CCPR1L ;REG1A = CCPR1L ;W = CCPR1H ;REG2A = CCPR1H ;REG3B = 0 ;SAI DA INTERRUPO

CCPR1L,W REG1B CCPR1H,W REG2B REG1A,W REG1B,F STATUS,C SEG_SUB REG2B,F .255 REG2B,W

;W = CCPR1L ;REG1B = CCPR1L ;W = CCPR1H ;REG2B = CCPR1H ;W = REG1A ;REG1B = REG1B - REG1A ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA REG2B ;W = 255 ;W = REG2B XOR 255

196

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

BTFSS GOTO DECF SEG_SUB MOVF SUBWF BTFSC GOTO DECF

STATUS,Z SEG_SUB REG3B,F REG2A,W REG2B,F STATUS,C TST_NR_INC REG3B,F

;REG2B = 255? ;NO ;SIM, DECREMENTA REG3B ;W = REG2A ;REG2B = REG2B - REG2A ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA REG3B

TST_NR_INC MOVF REG2B,W SUBLW .3 BTFSC STATUS,C GOTO TST_MENOR_3 CLRF CAPTURA BTFSC CALCULAR_FREQ GOTO SAI_INT GOTO COPIA_NR_INC TST_MENOR_3 MOVF REG2B,W SUBLW .2 BTFSC STATUS,C GOTO SAI_INT MOVF REG1B,W SUBLW .232 BTFSC STATUS,C GOTO SAI_INT CLRF CAPTURA BTFSC CALCULAR_FREQ GOTO SAI_INT GOTO COPIA_NR_INC SAI_INT SWAPF MOVWF SWAPF SWAPF RETFIE

;W = REG2B ;W = 3 REG2B ;REG2B MAIOR DO QUE 3? ;NAO ;SIM, CAPTURA = 0 ;FREQUNCIA SENDO CALCULADA? ;SIM, SAI DA INTERRUPO ;NAO, DESVIA ;W = REG2B ;W = 2 REG2B ;REG2B MENOR DO QUE 3? ;SIM, SAI DA INTERRUPO ;NO, W = REG1B ;W = 232 REG1B ;REG1B MAIOR DO QUE 232? ;NO, SAI DA INTERRUPO ;SIM, CAPTURA = 0 ;FREQUNCIA SENDO CALCULADA? ;SIM, SAI DA INTERRUPO ;NAO, DESVIA

STATUS_TEMP,W STATUS W_TEMP,F W_TEMP,W

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

;*********************************************************************************************** ; CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO INICIO BANCO_1 MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF MOVLW MOVWF BANCO_0 MOVLW MOVWF MOVLW ;SELECIONA BANCO 1 DE MEMORIA ;W = B'10000010'
;TIMER 0 INCREMENTADO PELO CICLO DE INSTRUCAO, PRESCALER 1:8

B'10000010' OPTION_REG B'11110000' TRISA B'00001000' TRISB B'00000101' PIE1 B'00000111' CMCON B'11100000'

;W = B'11110000'
;CONFIGURA RA0, RA1, RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS ;CONFIGURA O PINO RB3 COMO ENTRADA E DEMAIS COMO SAIDAS

;HABILITA AS INTERRUPES DO TIMER 1 E DO MDULO CCP ;SELECIONA BANCO 0 DE MEMORIA ;CONFIGURA RA3, RA2, RA1 E RA0 COMO I/O

197

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

MOVWF MOVLW MOVWF MOVLW MOVWF

INTCON B'00000001' T1CON B'00000101' CCP1CON

;HABILITA INTERRUPO DO TIMER 0 ;HABILITA TIMER 1 COM PRESCALER DE 1:1 ;HABILITA MODO CAPTURE A CADA MUDANA DE BAIXO PARA ALTO

;*********************************************************************************************** ; INICIALIZACAO DAS VARIAVEIS CLRF CLRF CLRF CLRF CLRF CLRF CLRF FLAGS UNIDADE DEZENA CENTENA MILHAR REG3B CAPTURA ;INICIALIZA FLAGS ;INICIALIZA UNIDADE ;INICIALIZA DEZENA ;INICIALIZA CENTENA ;INICIALIZA MILHAR ;INICIALIZA REG3B ;INICIALIZA CAPTURA

;*********************************************************************************************** PRINCIPAL ;ROTINA PRINCIPAL DO PROGRAMA CLRWDT BTFSS CALCULAR_FREQ GOTO PRINCIPAL BTFSC CEM_MILHOES GOTO DIV_CEM_MILHOES MOVLW .64 MOVWF MILHAO_1 MOVLW .66 MOVWF MILHAO_2 MOVLW .15 MOVWF MILHAO_3 CLRF MILHAO_4 GOTO INICIA_DIVISAO DIV_CEM_MILHOES BCF CEM_MILHOES CLRF MILHAO_1 MOVLW .225 MOVWF MILHAO_2 MOVLW .245 MOVWF MILHAO_3 MOVLW .5 MOVWF MILHAO_4 INICIA_DIVISAO CLRF UNI_TEMP CLRF DEZ_TEMP CLRF CEN_TEMP CLRF MIL_TEMP CICLO_DE_SUBTRACAO CLRWDT MOVF REG1C,W SUBWF MILHAO_1,F BTFSC STATUS,C GOTO SEG_DIV_1 DECF MILHAO_2,F MOVLW .255 XORWF MILHAO_2,W ;LIMPA O WDT ;CALCULAR A FREQUNCIA? ;NO ;SIM, DIVIDIR 1.000.000 OU 100.000.000? ;100.000.000 ;1.000.000. W = 64 ;MILHAO_1 = 64 ;W = 66 ;MILHAO_2 = 66 ;W = 15 ;MILHAO_3 = 15 ;MILHAO_4 = 0

;APAGA FLAG ;MILHAO_1 = 0 ;W = 225 ;MILHAO_2 = 225 ;W = 245 ;MILHAO_3 = 245 ;W = 5 ;MILHAO_3 = 4

;UNI_TEMP = 0 ;DEZ_TEMP = 0 ;CEN_TEMP = 0 ;MIL_TEMP = 0

;LIMPA O WDT ;W = REG1C ;MILHAO_1 = MILHAO_1 - REG1C ;RESULTADO NEGATIVO? ;NO ;SIM, DECREMENTA MILHAO_2 ;W = 255 ;W = MILHAO_2 XOR 255

198

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

199

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

XORWF BTFSS GOTO CLRF GOTO

MIL_TEMP,W STATUS,Z CICLO_DE_SUBTRACAO MIL_TEMP DIVISAO_TERMINOU

;W = MIL_TEMP XOR 10 ;MIL_TEMP = 10? ;NO ;SIM, MIL_TEMP = 0

DIVISAO_TERMINOU BCF CALCULAR_FREQ BTFSS ATUALIZA_DISP GOTO PRINCIPAL BCF ATUALIZA_DISP MOVF UNI_TEMP,W MOVWF UNIDADE MOVF DEZ_TEMP,W MOVWF DEZENA MOVF CEN_TEMP,W MOVWF CENTENA MOVF MIL_TEMP,W MOVWF MILHAR GOTO PRINCIPAL

;APAGA FLAG ;ATUALIZAR O DISPLAY? ;NO ;SIM, APAGA FLAG ;W = UNI_TEMP ;UNIDADE = UNI_TEMP ;W = DEZ_TEMP ;DEZENA = DEZ_TEMP ;W = CEN_TEMP ;CENTENA = CEN_TEMP ;W = MIL_TEMP ;MILHAR = MIL_TEMP

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

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

200

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Figura 3

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

201

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Figura 4

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

202

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

Figura 5

203

Tutorial de Programao Assembly para Microcontroladores PIC - Parte 8 Frequencmetro

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

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

204