Escolar Documentos
Profissional Documentos
Cultura Documentos
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
Figura 2
Configurao
dos registradores
Inicializao das
variveis
Passou 0,5
segundo?
no
sim
Acende LED
Apaga LED
sim
Indica o incio
Figura 3
;***********************************************************************************************
;
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
;***********************************************************************************************
;**********************************************************************************************
Figura 4
O prximo passo definir as variveis que iremos utilizar em nosso
programa.
Uma varivel um Registrador de Uso Geral, ou seja, uma das posies da
memria de dados que podemos usar para armazenar os valores dos dados que vamos manipular no
nosso programa.
medida que vamos escrevendo o programa, vamos precisando criar
variveis. Por esse motivo, minha forma preferida para defini-las com o uso da diretiva CBLOCK:
8
;**********************************************************************************************
;
VARIAVEIS
CBLOCK
ENDC
0X20
DELAY_0
DELAY_1
DELAY_2
;**********************************************************************************************
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
;***********************************************************************************************
10
0X00
GOTO
INICIO
;***********************************************************************************************
0X04
;VETOR DAS INTERRUPES
RETFIE
;RETORNA
;***********************************************************************************************
11
BANCO_0
MOVLW
MOVWF
;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;TODOS OS PINOS DO PORTB COMO ENTRADAS
;SELECIONA BANCO 0 DE MEMORIA
B'00000111'
CMCON
;***********************************************************************************************
12
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
13
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
;***********************************************************************************************
INI_DELAY_0
DELAY_0
DELAY_1,F
PRINCIPAL
15
INI_DELAY_1
DELAY_1
DELAY_2,F
PRINCIPAL
INI_DELAY_2
DELAY_2
16
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
LED
LED
LED
LED
LED
Faremos assim:
17
BTFSS
GOTO
BCF
GOTO
LED
ACENDE_LED
LED
PRINCIPAL
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>
;***********************************************************************************************
;
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
VARIAVEIS
CBLOCK 0X20
DELAY_0
DELAY_1
DELAY_2
ENDC
;**********************************************************************************************
;
CONSTANTES
INI_DELAY_0
INI_DELAY_1
INI_DELAY_2
EQU .255
EQU .50
EQU .13
;***********************************************************************************************
;
SADA
#DEFINE
LED PORTA,0
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
RETFIE
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
;***********************************************************************************************
19
;**********************************************************************************************
;
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
DELAY_0,F
PRINCIPAL
INI_DELAY_0
DELAY_0
DELAY_1,F
PRINCIPAL
INI_DELAY_1
DELAY_1
DELAY_2,F
PRINCIPAL
INI_DELAY_2
DELAY_2
LED
ACENDE_LED
LED
PRINCIPAL
;LIMPA O WDT
;DECREMENTA DELAY_0. DELAY_0 = 0?
;NO
;SIM, W = INI_DELAY_0
;REINICIALIZA DELAY_0
;DECREMENTA DELAY_1. DELAY_1 = 0?
;NO
;SIM, W = INI_DELAY_1
;REINICIALIZA DELAY_1
;DECREMENTA DELAY_2. DELAY_2 = 0?
;NO
;SIM, W = INI_DELAY_2
;REINICIALIZA DELAY_2
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;DESVIA
LED
PRINCIPAL
;ACENDE O LED
;DESVIA
;**********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************
20
Figura 5
Na janela seguinte (Step One), selecione o PIC16F628A e clique em
Avanar:
Figura 6
21
Figura 7
Na prxima janela (Step Three), clique em Browse:
Figura 8
22
Figura 9
Figura 10
23
Figura 11
Na janela seguinte (Summary), clique em concluir:
Figura 12
24
Figura 13
A seguir, expanda a janela chamada Output:
25
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
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
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
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
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
31
Figura 21
32
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
Figura 23
34
Figura 24
35
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
Figura 27
37
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
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
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
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
Figura 35
42
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
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
;***********************************************************************************************
;
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
;**********************************************************************************************
0X20
45
;**********************************************************************************************
EQU .131
EQU .125
;***********************************************************************************************
;
SADA
#DEFINE
LED PORTA,0
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
RETFIE
;***********************************************************************************************
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
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
INICIALIZACAO DA VARIAVEL
MOVLW
MOVWF
INI_CONT_EST_TMR0
CONT_EST_TMR0
;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0
;***********************************************************************************************
PRINCIPAL
INTCON,TOIF
;TMR0 ESTOUROU?
PRINCIPAL
;NAO
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
CONT_EST_TMR0,F
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
;***********************************************************************************************
;
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
;**********************************************************************************************
;
VARIVEIS
CBLOCK
0X20
CONT_EST_TMR0
ENDC
;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
EQU .131
EQU .125
;***********************************************************************************************
;
SADA
#DEFINE
LED PORTA,0
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
RETFIE
48
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
INICIALIZACAO DA VARIAVEL
MOVLW
MOVWF
INI_CONT_EST_TMR0
CONT_EST_TMR0
;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0
;***********************************************************************************************
PRINCIPAL
;ROTINA PRINCIPAL DO PROGRAMA
CLRWDT
BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
GOTO
BCF
GOTO
ACENDE_LED
BSF
GOTO
INTCON,T0IF
PRINCIPAL
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
PRINCIPAL
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED
ACENDE_LED
LED
PRINCIPAL
;LIMPA O WDT
;TMR0 ESTOUROU?
;NAO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;DESVIA
LED
PRINCIPAL
;ACENDE O LED
;DESVIA
;**********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************
Salve o arquivo.
A seguir iremos simular a execuo do programa com o MPLAB SIM.
No menu Project, clique em Open. Localize o projeto de nome Pisca
LED, selecione-o e clique em Abrir.
No menu Project, em Remove Files to Project, clique no arquivo Pisca
LED.asm (o da parte I) para remov-lo.
No menu Project, clique em Add Files to Project..., localize o arquivo
Pisca LED II.asm (o novo), selecione-o e clique em Abrir.
No menu Project, clique em Buid All.
Verifique se a montagem foi feita com sucesso, selecionando a janela
Output no menu Window:
49
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
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
52
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>
53
;***********************************************************************************************
;
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
;**********************************************************************************************
;**********************************************************************************************
54
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
EQU .131
EQU .125
;***********************************************************************************************
;
SADA
#DEFINE
LED PORTA,0
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
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
INTCON,T0IF
;TMR0 ESTOUROU?
55
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
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
INI_TMR0
TMR0
;W = INI_TMR0
;REINICIA TMR0
CONT_EST_TMR0,F
SAI_INT
;NAO
56
INI_CONT_EST_TMR0
CONT_EST_TMR0
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
LED
ACENDE_LED
LED
SAI_INT
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
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
W_TEMP
STATUS,W
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
SAI_INT
;NAO
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
57
GOTO
BCF
GOTO
ACENDE_LED
BSF
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
ACENDE_LED
LED
SAI_INT
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO
LED
;ACENDE O LED
STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W
;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO
;**********************************************************************************************
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
;**********************************************************************************************
58
;***********************************************************************************************
;
PROGRAMA: PISCA LED III
;
VERSO 1.0
;
DESENVOLVIDO POR: MULDER_FOX
;
DATA DE CONCLUSO: / /
;***********************************************************************************************
#INCLUDE <P16F628A.INC>
;***********************************************************************************************
;
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
;**********************************************************************************************
;
VARIVEIS
CBLOCK 0X20
W_TEMP
STATUS_TEMP
CONT_EST_TMR0
ENDC
;***********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
EQU .131
EQU .125
;***********************************************************************************************
;
SADA
#DEFINE
LED PORTA,0
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
W_TEMP
STATUS,W
STATUS_TEMP
59
BTFSS
GOTO
BCF
MOVLW
MOVWF
DECFSZ
GOTO
MOVLW
MOVWF
BTFSS
GOTO
BCF
GOTO
INTCON,T0IF
SAI_INT
INTCON,T0IF
INI_TMR0
TMR0
CONT_EST_TMR0,F
SAI_INT
INI_CONT_EST_TMR0
CONT_EST_TMR0
LED
ACENDE_LED
LED
SAI_INT
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO
ACENDE_LED
BSF
LED
;ACENDE O LED
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
;W = SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO
STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON
;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
INICIALIZACAO DA VARIVEL
MOVLW
MOVWF
INI_CONT_EST_TMR0
CONT_EST_TMR0
;W = INI_CONT_EST_TMR0
;INICIALIZA CONT_EST_TMR0
;***********************************************************************************************
PRINCIPAL
CLRWDT
GOTO
;**********************************************************************************************
END
;FIM DO PROGRAMA
60
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
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
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
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:
64
65
;********************************************************************************************
;
VARIVEIS
CBLOCK 0X20
W_TEMP
STATUS_TEMP
CONT_EST_TMR0
FLAGS
DB_BTA
DB_BTB
ENDC
;********************************************************************************************
EQU
EQU
EQU
EQU
.131
.125
.255
.50
;**********************************************************************************************
BOTAO
PORTA,1
;***********************************************************************************************
SOLTAR_BOTAO FLAGS,0
ESTADO_DO_LED FLAGS,1
;***********************************************************************************************
66
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
SOLTAR_BOTAO
TESTA_BOTAO
BOTAO
PRINCIPAL
SOLTAR_BOTAO
TESTA_BOTAO
BTFSC
BOTAO
GOTO
REINC_CONT_DEB
DECFSZ
DB_BTA,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
DECFSZ
DB_BTB,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTB
MOVWF
DB_BTB
BTFSS
ESTADO_DO_LED
GOTO
PISCAR_O_LED
BCF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
PISCAR_O_LED
BSF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
REINC_CONT_DEB
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
MOVLW
INI_DB_BTB
;LIMPA O WDT
;AGUARDA SOLTAR O BOTAO?
;NAO, DESVIA
;SIM, O BOTO EST SOLTO?
;NAO, DESVIA
;SIM, APAGA FLAG
;DESVIA
;DESVIA
;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB
68
MOVWF
GOTO
DB_BTB
PRINCIPAL
;INICIALIZA DB_BTB
;DESVIA
;*********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSC
GOTO
BCF
GOTO
W_TEMP
STATUS,W
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
ESTADO_DO_LED
CONT_INTERRUPCAO
LED
SAI_INT
CONT_INTERRUPCAO
MOVLW
INI_TMR0
MOVWF
TMR0
DECFSZ
CONT_EST_TMR0,F
GOTO
SAI_INT
MOVLW
INI_CONT_EST_TMR0
MOVWF
CONT_EST_TMR0
BTFSS
LED
GOTO
ACENDE_LED
BCF
LED
GOTO
SAI_INT
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;LED DEVER PISCAR?
;SIM, DESVIA
;NAO, APAGA O LED
;SAIR DA INTERRUPCAO
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO
ACENDE_LED
BSF
LED
;ACENDE O LED
SAI_INT
SWAPF
;SWAP EM STATUS_TEMP
STATUS_TEMP,W
69
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>
;***********************************************************************************************
;
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
;**********************************************************************************************
;
VARIVEIS
CBLOCK 0X20
W_TEMP
STATUS_TEMP
CONT_EST_TMR0
FLAGS
DB_BTA
DB_BTB
ENDC
;**********************************************************************************************
;
CONSTANTES
INI_TMR0
INI_CONT_EST_TMR0
INI_DB_BTA
INI_DB_BTB
EQU
EQU
EQU
EQU
.131
.125
.255
.50
;***********************************************************************************************
;
SADA
70
#DEFINE
LED
PORTA,0
;***********************************************************************************************
;
ENTRADA
#DEFINE
BOTAO
PORTA,1
;***********************************************************************************************
;
FLAGS
#DEFINE
#DEFINE
SOLTAR_BOTAO
ESTADO_DO_LED
FLAGS,0
FLAGS,1
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSC
GOTO
BCF
GOTO
W_TEMP
STATUS,W
;SALVA W
;W = SWAP EM STATUS
;SELECIONA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
;LED DEVER PISCAR?
;SIM, DESVIA
;NAO, APAGA O LED
;SAIR DA INTERRUPCAO
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
ESTADO_DO_LED
CONT_INTERRUPCAO
LED
SAI_INT
CONT_INTERRUPCAO
MOVLW
INI_TMR0
MOVWF
TMR0
DECFSZ
CONT_EST_TMR0,F
GOTO
SAI_INT
MOVLW
INI_CONT_EST_TMR0
MOVWF
CONT_EST_TMR0
BTFSS
LED
GOTO
ACENDE_LED
BCF
LED
GOTO
SAI_INT
ACENDE_LED
BSF
LED
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W
;W = INI_TMR0
;REINICIA TMR0
;DECREMENTA CONT_EST_TMR0. CONT_EST_TMR0 = 0?
;NAO
;SIM, W = INI_CONT_EST_TMR0
;REINICIALIZA CONT_EST_TMR0
;TESTA O VALOR DO BIT 0 DO PORTA
;VALOR = 0, DESVIA
;VALOR = 1, APAGA O LED
;SAIR DA INTERRUPCAO
;ACENDE O LED
;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO
71
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
B'11010100'
OPTION_REG
B'11111110'
TRISA
B'11111111'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON
;W = B'11111110'
;CONFIGURA RA0 COMO SADA E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
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
SOLTAR_BOTAO
TESTA_BOTAO
BOTAO
PRINCIPAL
SOLTAR_BOTAO
TESTA_BOTAO
BTFSC
BOTAO
GOTO
REINC_CONT_DEB
DECFSZ
DB_BTA,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTA
MOVWF
DB_BTA
DECFSZ
DB_BTB,F
GOTO
PRINCIPAL
MOVLW
INI_DB_BTB
MOVWF
DB_BTB
BTFSS
ESTADO_DO_LED
GOTO
PISCAR_O_LED
BCF
ESTADO_DO_LED
BSF
SOLTAR_BOTAO
GOTO
PRINCIPAL
;LIMPA O WDT
;AGUARDA SOLTAR O BOTAO?
;NAO, DESVIA
;SIM, O BOTO EST SOLTO?
;NAO, DESVIA
;SIM, APAGA FLAG
;DESVIA
72
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
;DESVIA
;W = INI_DB_BTA
;INICIALIZA DB_BTA
;W = INI_DB_BTB
;INICIALIZA DB_BTB
;DESVIA
;*********************************************************************************************
END
;FIM DO PROGRAMA
;**********************************************************************************************
73
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
Figura 2
Na caixa de seleo do campo Action ao lado, selecione Set High:
Figura 3
75
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
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
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
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
Figura 9
Arraste a janela do programa para baixo para liberar espao:
80
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
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
Parte 5
Figura 1
83
84
Figura 2
85
Figura 3
86
;***********************************************************************************************
;
VARIVEIS
CBLOCK
0X20
W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB
UNIDADE
DEZENA
;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2
ENDC
;***********************************************************************************************
EQU
EQU
EQU
EQU
.255
.20
.255
.20
;***********************************************************************************************
DIGITO_1
DIGITO_2
PORTA,2
PORTA,3
;***********************************************************************************************
BOTAO_1
BOTAO_2
PORTA,0
PORTA,1
;***********************************************************************************************
87
SOLTAR_BOTAO_1
SOLTAR_BOTAO_2
FLAGS,0
FLAGS,1
;***********************************************************************************************
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
W_TEMP
STATUS,W
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, SAIR DA INTERRUPO
;SIM
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
A seguir, vamos verificar qual o dgito que est ativo, desativ-lo, e ativar o
outro:
BTFSS
GOTO
BCF
CLRF
BSF
GOTO
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE
DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1
;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1
88
RB0
RB1
RB2
RB3
RB4
RB5
RB6
Tabela 1
O display utilizado do tipo catodo comum, portanto os segmentos so
ativados com nvel alto. Sendo assim, os valores a serem escritos no PORTB para cada algarismo a
ser exibido no display so os constantes na tabela abaixo. O bit 7 do PORTB est desconectado,
portanto, seu valor indiferente, pelo que lhe atribumos o valor 0 para todos os algarismos.
Algarismo
PORTB
00111111
00000110
01011011
01001111
01100110
01101101
01111101
00000111
01111111
01101111
Tabela 2
89
00111111
00000110
01011011
01001111
90
01100110
01111101
01101101
00000111
91
01101111
01111111
Aps o dgito ser ativado, devemos enviar para o PORTB o valor referente
ao algarismo que deve ser exibido.
O dgito 1 do display exibe a dezena do nmero e o dgito 2, a unidade.
O algarismo da dezena est gravado na varivel DEZENA, enquanto que
o da unidade est gravado na varivel UNIDADE, porm, esses algarismos esto gravados nessas
variveis no formato binrio, conforme a tabela abaixo:
Algarismo Valor binrio
0
00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
Tabela 3
92
Esses valores so diferentes dos que deve assumir o PORTB para que os
algarismos sejam exibidos no display de 7 segmentos, conforme a tabela comparativa abaixo:
Algarismo Valor binrio
PORTB
00000000
00111111
00000001
00000110
00000010
01011011
00000011
01001111
00000100
01100110
00000101
01101101
00000110
01111101
00000111
00000111
00001000
01111111
00001001
01101111
Tabela 4
Por isso, no podemos simplesmente copiar o valor da varivel para o
PORTB.
Existe uma maneira prtica de converter o valor binrio para o
correspondente a 7 segmentos, que consiste em somar o valor binrio ao Contador de Programa (PC
- Program Counter) para provocar um desvio no programa (Computed GOTO) para uma localidade
onde exista uma instruo que faa o programa retornar com o nmero j convertido no registrador
W.
O Contador de Programa (PC), armazena o endereo da prxima instruo
que ser executada.
Quando o microcontrolador ligado e tambm depois de um reset, o valor
do PC igual a 0h (nmero 0 no formato hexadecimal), o que quer dizer que ele ir executar a
instruo gravada nessa localidade da memria de programa.
A cada instruo que executada, o PC incrementado em 1 unidade,
portanto, depois de executar a instruo contida no endereo 0h, ele ir executar a instruo contida
no endereo 1h, depois a do endereo 2h e assim por diante. Isso se as instrues contidas nesses
endereos no provocarem o desvio do programa para outra localidade da memria.
Um exemplo de instruo que provoca o desvio para outra localidade de
memria a GOTO.
O PC do PIC16F628A composto de 13 bits, sendo que os 8 bits menos
significativos (do 0 ao 7) compe o registrador PCL. Este registrador pode ser acessado diretamente
para ser alterado. Os 5 bits mais significativos do PC (do 8 ao 12), chamados de PCH s podem ser
alterados indiretamente atravs do registrador PCLATH.
Quando uma instruo GOTO executada, o endereo para onde o
programa dever ser desviado consta na prpria instruo sendo copiado para o PC; portanto, a
prxima instruo que ser executada aquela que consta na instruo GOTO.
Outro tipo de instruo que provoca um desvio no programa a instruo
CALL.
93
.5
PCL,F
;W = 5
;PCL = PCL + 5
94
;W = UNIDADE
CONVERTE_BINARIO_7_SEGMENTOS
;CHAMA SUBROTINA
95
PORTB
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO
W_TEMP
STATUS,W
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE
DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1
MOVF
DEZENA,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT
;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1
;W = DEZENA
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA
COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT
;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA
CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'
;PCL = PCL + W
;W = 0
96
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
B'00000110'
B'01011011'
B'01001111'
B'01100110'
B'01101101'
B'01111101'
B'00000111'
B'01111111'
B'01101111'
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
;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
;***********************************************************************************************
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
;***********************************************************************************************
97
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
;***********************************************************************************************
TRATA_BOTAO_1
TRATA_BOTAO_2
PRINCIPAL
;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA
;***********************************************************************************************
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
98
RETURN
BCF
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BTFSC
BOTAO_1
GOTO
REINC_CONT_DEB_1
DECFSZ
DB1_BTA,F
RETURN
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
DECFSZ
DB1_BTB,F
RETURN
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
;NAO, RETORNA
;SIM, APAGA FLAG
SOLTAR_BOTAO_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
.10
;W = 10
UNIDADE,W
;W = W XOR UNIDADE
99
BTFSS
STATUS,Z
;UNIDADE = 10?
;NAO, RETORNA
UNIDADE
DEZENA,F
;SIM, UNIDADE = 0
;INCREMENTA DEZENA
.10
DEZENA,W
STATUS,Z
DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1
BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
100
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN
UNIDADE,F
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA
REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN
;INCREMENTA UNIDADE
;W = 10
;W = W XOR UNIDADE
;UNIDADE = 10?
;NAO, RETORNA
;SIM, UNIDADE = 0
;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA
;**********************************************************************************************
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2
BOTAO_2
REINC_CONT_DEB_2
DB2_BTA,F
INI_DB2_BTA
DB2_BTA
DB2_BTB,F
INI_DB2_BTB
DB2_BTB
SOLTAR_BOTAO_2
UNIDADE,F
;DECREMENTA UNIDADE
101
.255
UNIDADE,W
STATUS,Z
.9
UNIDADE
;W = 255
;W = W XOR UNIDADE
;UNIDADE = 255?
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
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
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
102
RETURN
MOVLW
MOVWF
DECF
MOVLW
XORWF
BTFSS
RETURN
MOVLW
MOVWF
RETURN
.9
UNIDADE
DEZENA,F
.255
DEZENA,W
STATUS,Z
.9
DEZENA
REINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
RETURN
;NAO, RETORNA
;SIM, W = 9
;UNIDADE = 9
;DECREMENTA DEZENA
;W = 255
;W = W XOR DEZENA
;DEZENA = 255?
;NAO, RETORNA
;SIM, W = 9
;DEZENA = 9
;RETORNA
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;RETORNA
;**********************************************************************************************
;***********************************************************************************************
;
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
;***********************************************************************************************
;
VARIVEIS
CBLOCK
0X20
W_TEMP
STATUS_TEMP
FLAGS
DB1_BTA
DB1_BTB
DB2_BTA
DB2_BTB
;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
UNIDADE
DEZENA
ENDC
;***********************************************************************************************
;
CONSTANTES
INI_DB1_BTA
INI_DB1_BTB
INI_DB2_BTA
INI_DB2_BTB
EQU
EQU
EQU
EQU
.255
.20
.255
.20
;***********************************************************************************************
;
SADAS
#DEFINE
#DEFINE
DIGITO_1
DIGITO_2
PORTA,2
PORTA,3
;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE
BOTAO_1
BOTAO_2
PORTA,0
PORTA,1
;***********************************************************************************************
;
FLAGS
#DEFINE
SOLTAR_BOTAO_1 FLAGS,0
;SE = 1 AGUARDA SOLTAR O BOTO 1
#DEFINE
SOLTAR_BOTAO_2 FLAGS,1
;SE = 1 AGUARDA SOLTAR O BOTO 2
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO
W_TEMP
STATUS,W
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE
DESATIVA_DIGITO_2
BCF
DIGITO_2
;DESATIVA DIGITO 2
104
CLRF
BSF
MOVF
CALL
MOVWF
GOTO
PORTB
DIGITO_1
DEZENA,W
CONVERTE_BINARIO_7_SEGMENTOS
PORTB
SAI_INT
COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT
;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA
CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'
RETLW B'00000110'
RETLW B'01011011'
RETLW B'01001111'
RETLW B'01100110'
RETLW B'01101101'
RETLW B'01111101'
RETLW B'00000111'
RETLW B'01111111'
RETLW B'01101111'
;PCL = PCL + W
;W = 0
;W = 1
;W = 2
;W = 3
;W = 4
;W = 5
;W = 6
;W = 7
;W = 8
;W = 9
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO
STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
B'11010011'
OPTION_REG
B'11110011'
TRISA
B'10000000'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON
;W = B'11110011'
;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
INICIALIZACAO DAS VARIAVEIS
CLRF
MOVLW
MOVWF
FLAGS
INI_DB1_BTA
DB1_BTA
;INICIALIZA FLAGS
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
105
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
TRATA_BOTAO_1
TRATA_BOTAO_2
PRINCIPAL
;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA
;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1
BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA
REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA
106
;********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN
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
107
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
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
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
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
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
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
Figura 10
Clique novamente no boto Fire da primeira linha e repare que a unidade
foi incrementada novamente, passando para 2.
Continue clicando nesse boto e repare que a unidade passa do valor 9 para
o valor 0 enquanto a dezena incrementada para 1, ou seja, o valor do contador igual a 10.
Agora, clique no boto Fire da segunda linha para simular que o boto 2
foi pressionado e solto em seguida. Repare que agora o contador decrementado, voltando a
unidade para 9 e a dezena para 0.
Continue decrementando-o e repare que de 00 passa a 99.
Agora o incremente e veja que o seu valor volta a 00.
Incremente-o at que o seu valor seja igual a 19 e a seguir clique no boto
Halt do simulador.
Vamos conferir a rotina de interrupo.
Insira um breakpoint na linha da primeira instruo da rotina de interrupo
(MOVWF
WTEMP).
Clique no boto Run da barra do simulador e quando o programa parar no
breakpoint, v para a janela do Stopwatch e clique em Zero.
Clique no boto Run novamente e quando o programa parar outra vez no
breakpoint, verifique no Stopwatch que o tempo entre uma interrupo e outra foi de 4
milissegundos.
V clicando no boto Step Into e observando a execuo da rotina de
interrupo.
114
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
Parte 6 Contador II
Parte 6
Contador Crescente e Decrescente II
116
Parte 6 Contador II
117
Parte 6 Contador II
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
;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
;***********************************************************************************************
EQU
EQU
EQU
EQU
EQU
EQU
.255
.8
.255
.8
.255
.2
;***********************************************************************************************
SOLTAR_BOTAO_1
FLAGS,0
118
#DEFINE SOLTAR_BOTAO_2
#DEFINE APAGAR_UNIDADE
#DEFINE GRAVAR_UNIDADE
#DEFINE GRAVAR_DEZENA
#DEFINE ESP_FIM_GRV_EEPROM
#DEFINE CONF_GRV_EEPROM
FLAGS,1
FLAGS,2
FLAGS,3
FLAGS,4
FLAGS,5
FLAGS,6
Parte 6 Contador II
;***********************************************************************************************
0000 0000
0000 0101
0000 0001
0000 0110
0000 0010
0000 0111
0000 0011
0000 1000
0000 0100
0000 1001
Tabela 1
Sendo assim, usaremos os bits 5 a 8 para gravar um cdigo que far com que
o programa identifique a localidade onde est armazenado o valor da unidade.
O cdigo que utilizaremos ser este: 0110, ou seja, esses sero os valores dos
bits 5 a 8 da localidade onde o valor da unidade estiver salvo. Esse cdigo ser gravado todas as
vezes que salvarmos o valor da unidade, porm, na gravao do programa no microcontrolador,
devemos escrever o cdigo na primeira localidade da memria EEPROM, caso contrrio, no haver
nenhuma localidade com o cdigo para que o programa encontre na primeira vez que o
microcontrolador for ligado. Isso feito com o uso da diretiva DE, desta forma:
119
Parte 6 Contador II
;**********************************************************************************************
;
INICIALIZAO DA EEPROM
ORG
DE
2100
B'01100000', .0
120
Parte 6 Contador II
121
Parte 6 Contador II
;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
Parte 6 Contador II
TRATA_BOTAO_1
TRATA_BOTAO_2
GRAVA_EEPROM
PRINCIPAL
;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA
;***********************************************************************************************
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1
BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
.10
UNIDADE,W
STATUS,Z
UNIDADE
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA
123
REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN
Parte 6 Contador II
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA
;********************************************************************************************
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN
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
Parte 6 Contador II
ESP_FIM_GRV_EEPROM
Se esse flag estiver setado, o programa desviado para onde est a label
TESTA_FIM_DA_GRAVACAO:
GOTO
TESTA_FIM_DA_GRAVACAO
;SIM
CONF_GRV_EEPROM
Se esse flag estiver setado, o programa desviado para onde est a label
CONFERE_DEZENA:
GOTO
CONFERE_DEZENA
;SIM
125
BTFSC
APAGAR_UNIDADE
Parte 6 Contador II
Se esse flag estiver setado, o programa desviado para onde est a label
APAGA_UNIDADE_ANTERIOR:
GOTO
APAGA_UNIDADE_ANTERIOR
;SIM
GRAVAR_UNIDADE
Se esse flag estiver setado, o programa desviado para onde est a label
GRAVA_A_UNIDADE:
GOTO
GRAVA_A_UNIDADE
;SIM
GRAVAR_DEZENA
Se esse flag estiver setado, o programa desviado para onde est a label
GRAVA_A_DEZENA:
GOTO
GRAVA_A_DEZENA
;SIM
;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
EEDATA
;EEDATA = 0
EECON1,WREN
INTCON,GIE
;DESABILITA AS INTERRUPES
Aps isso, testamos esse bit para confirmarmos que ele foi zerado:
BTFSC
INTCON,GIE
126
Parte 6 Contador II
$-2
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
EECON1,WR
;INICIA A GRAVAO
INTCON,GIE
;HABILITA INTERRUPES
APAGAR_UNIDADE
;APAGA O FLAG
ESP_FIM_GRV_EEPROM
127
Parte 6 Contador II
128
GRAVA_A_UNIDADE
BANCO_1
INCF
EEADR,F
INCF
EEADR,F
Parte 6 Contador II
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
;W = UNIDADE
;EEDATA = UNIDADE
B'01100000'
EEDATA,F
;W = 01100000
;EEDATA = EEDATA OR 01100000
EECON1,WREN
INTCON,GIE
INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE
129
BCF
BSF
BANCO_0
RETURN
GRAVAR_UNIDADE
ESP_FIM_GRV_EEPROM
Parte 6 Contador II
;APAGA O FLAG
;SETA O FLAG PARA ESPERAR PELO FIM DA GRAVAO
DEZENA,W
EEDATA
;W = DEZENA
;EEDATA = DEZENA
EECON1,WREN
INTCON,GIE
INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE
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
130
Parte 6 Contador II
DEZENA,W
;W = DEZENA
EEDATA,W
;W = W XOR EEDATA
STATUS,Z
Estando setado,
CONFERE_APAGAMENTO:
GOTO
CONFERE_APAGAMENTO
desviamos
programa
para
onde
est
label
;SIM
CONF_GRV_EEPROM
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
;APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE
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
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
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
STATUS,Z
CONFERE_UNIDADE
CONF_GRV_EEPROM
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
;SIM
;NAO, APAGA FLAG
;SETA O FLAG PARA APAGAR LOCALIDADE ANTERIOR DA UNIDADE
132
CONFERE_UNIDADE
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONF_UNIDADE
CLRF
EEADR
Parte 6 Contador II
;INCREMENTA EEADR
;INCREMENTA EEADR
;W = 128
;W = W XOR EEADR
;EEADR = 128?
;NAO, DESVIA
;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
133
Parte 6 Contador II
BITS DE CONFIGURAO
__CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOREN_OFF &
_LVP_OFF & _CP_OFF & DATA_CP_OFF
;**********************************************************************************************
;
INICIALIZAO DA EEPROM
ORG
DE
2100
B'01100000', .0
;***********************************************************************************************
;
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
;REGISTRADOR DE FLAGS
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 1
;PRIMEIRO REGISTRADOR DO DE-BOUNCING DO BOTO 2
;SEGUNDO REGISTRADOR DO DE-BOUNCING DO BOTO 2
ENDC
;***********************************************************************************************
;
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
;***********************************************************************************************
;
SADAS
#DEFINE
#DEFINE
DIGITO_1
DIGITO_2
PORTA,2
PORTA,3
;***********************************************************************************************
134
Parte 6 Contador II
ENTRADAS
#DEFINE
#DEFINE
BOTAO_1
BOTAO_2
PORTA,0
PORTA,1
;***********************************************************************************************
;
FLAGS
#DEFINE SOLTAR_BOTAO_1
#DEFINE SOLTAR_BOTAO_2
#DEFINE APAGAR_UNIDADE
FLAGS,0
FLAGS,1
FLAGS,2
#DEFINE GRAVAR_UNIDADE
FLAGS,3
;SE = 1, GRAVAR UNIDADE NA EEPROM
#DEFINE GRAVAR_DEZENA
FLAGS,4
;SE = 1, GRAVAR DEZENA NA EEPROM
#DEFINE ESP_FIM_GRV_EEPROM FLAGS,5
;SE = 1, ESPERA O FIM DA GRAVAO NA EEPROM
#DEFINE CONF_GRV_EEPROM
FLAGS,6
;SE = 1, CONFERE A GRAVAO NA EEPROM
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
MOVWF
SWAPF
BANCO_0
MOVWF
BTFSS
GOTO
BCF
BTFSS
GOTO
BCF
CLRF
BSF
GOTO
W_TEMP
STATUS,W
;SALVA W
;W = SWAP EM STATUS
;CHAVEIA PARA BANCO 0 DE MEMORIA
;SALVA STATUS
;TMR0 ESTOUROU?
;NAO, DESVIA
;SIM, APAGA FLAG
;DIGITO 1 ESTA ATIVADO?
;NAO, DESVIA
;SIM, DESATIVA DIGITO 1
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 2
;DESVIA
STATUS_TEMP
INTCON,T0IF
SAI_INT
INTCON,T0IF
DIGITO_1
DESATIVA_DIGITO_2
DIGITO_1
PORTB
DIGITO_2
COPIAR_UNIDADE
DESATIVA_DIGITO_2
BCF
DIGITO_2
CLRF
PORTB
BSF
DIGITO_1
MOVF
DEZENA,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT
;DESATIVA DIGITO 2
;TODOS OS BITS DO PORT B = 0
;ATIVA DIGITO 1
;W = DEZENA
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA
COPIAR_UNIDADE
MOVF
UNIDADE,W
CALL
CONVERTE_BINARIO_7_SEGMENTOS
MOVWF
PORTB
GOTO
SAI_INT
;W = UNIDADE
;CHAMA SUBROTINA
;PORTB RECEBE O VALOR CONVERTIDO
;DESVIA
135
CONVERTE_BINARIO_7_SEGMENTOS
ADDWF
PCL,F
RETLW B'00111111'
RETLW B'00000110'
RETLW B'01011011'
RETLW B'01001111'
RETLW B'01100110'
RETLW B'01101101'
RETLW B'01111101'
RETLW B'00000111'
RETLW B'01111111'
RETLW B'01101111'
;PCL = PCL + W
;W = 0
;W = 1
;W = 2
;W = 3
;W = 4
;W = 5
;W = 6
;W = 7
;W = 8
;W = 9
SAI_INT
SWAPF
MOVWF
SWAPF
SWAPF
RETFIE
;SWAP EM STATUS_TEMP
;RECUPERA STATUS
;SWAP EM W_TEMP
;RECUPERA W
;RETORNA DA INTERRUPO
STATUS_TEMP,W
STATUS
W_TEMP,F
W_TEMP,W
Parte 6 Contador II
;***********************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
B'11010011'
OPTION_REG
B'11110011'
TRISA
B'10000000'
TRISB
B'00000111'
CMCON
B'11100000'
INTCON
;W = B'11110011'
;CONFIGURA RA2 E RA3 COMO SADAS E DEMAIS COMO ENTRADAS
;***********************************************************************************************
;
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
INCF
BSF
MOVF
ANDLW
XORLW
BTFSS
GOTO
MOVF
MOVWF
MOVF
ANDLW
MOVWF
INCF
BSF
MOVF
MOVWF
BANCO_0
EEADR,F
EECON1,RD
EEDATA,W
B'11110000'
B'01100000'
STATUS,Z
INICIALIZA_UNIDADE_E_DEZENA
EEADR,W
LOCAL_DA_UNIDADE
EEDATA,W
B'00001111'
UNIDADE
EEADR,F
EECON1,RD
EEDATA,W
DEZENA
Parte 6 Contador II
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;ZERA BITS 0 A 4 E MANTEM BITS 5 A 8
;W = W XOR 01100000
;W = 01100000?
;NAO
;SIM, W = EEADR
;INICIALIZA A VARIVEL LOCAL_DA_UNIDADE
;SIM, W = VALOR DA LOCALIDADE DA EEPROM
;W = W AND B'00001111'
;INICIALIZA UNIDADE
;INCREMENTA EEADR
;INICIA LEITURA
;W = VALOR DA LOCALIDADE DA EEPROM
;INICIALIZA DEZENA
;SELECIONA BANCO 0 DE MEMORIA
;***********************************************************************************************
PRINCIPAL
CLRWDT
CALL
CALL
CALL
GOTO
TRATA_BOTAO_1
TRATA_BOTAO_2
GRAVA_EEPROM
PRINCIPAL
;LIMPA O WDT
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;CHAMA SUBROTINA
;DESVIA
;***********************************************************************************************
TRATA_BOTAO_1
BTFSS
GOTO
BTFSS
RETURN
BCF
TESTA_BOTAO_1
BTFSC
GOTO
DECFSZ
RETURN
MOVLW
MOVWF
DECFSZ
RETURN
MOVLW
MOVWF
BSF
INCF
BSF
BSF
BSF
MOVLW
XORWF
BTFSS
RETURN
CLRF
SOLTAR_BOTAO_1
TESTA_BOTAO_1
BOTAO_1
SOLTAR_BOTAO_1
BOTAO_1
REINC_CONT_DEB_1
DB1_BTA,F
INI_DB1_BTA
DB1_BTA
DB1_BTB,F
INI_DB1_BTB
DB1_BTB
SOLTAR_BOTAO_1
UNIDADE,F
APAGAR_UNIDADE
GRAVAR_UNIDADE
GRAVAR_DEZENA
.10
UNIDADE,W
STATUS,Z
UNIDADE
137
INCF
MOVLW
XORWF
BTFSS
RETURN
CLRF
RETURN
DEZENA,F
.10
DEZENA,W
STATUS,Z
DEZENA
REINC_CONT_DEB_1
MOVLW
INI_DB1_BTA
MOVWF
DB1_BTA
MOVLW
INI_DB1_BTB
MOVWF
DB1_BTB
RETURN
Parte 6 Contador II
;INCREMENTA DEZENA
;W = 10
;W = W XOR DEZENA
;DEZENA = 10?
;NAO, RETORNA
;SIM, DEZENA = 0
;RETORNA
;W = INI_DB1_BTA
;INICIALIZA DB1_BTA
;W = INI_DB1_BTB
;INICIALIZA DB1_BTB
;RETORNA
;********************************************************************************************
TRATA_BOTAO_2
BTFSS
GOTO
BTFSS
RETURN
BCF
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BOTAO_2
SOLTAR_BOTAO_2
TESTA_BOTAO_2
BTFSC
BOTAO_2
GOTO
REINC_CONT_DEB_2
DECFSZ
DB2_BTA,F
RETURN
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
DECFSZ
DB2_BTB,F
RETURN
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
BSF
SOLTAR_BOTAO_2
DECF
UNIDADE,F
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
MOVLW
.255
XORWF
UNIDADE,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
UNIDADE
DECF
DEZENA,F
MOVLW
.255
XORWF
DEZENA,W
BTFSS
STATUS,Z
RETURN
MOVLW
.9
MOVWF
DEZENA
RETURN
138
EINC_CONT_DEB_2
MOVLW
INI_DB2_BTA
MOVWF
DB2_BTA
MOVLW
INI_DB2_BTB
MOVWF
DB2_BTB
RETURN
Parte 6 Contador II
;W = INI_DB2_BTA
;INICIALIZA DB2_BTA
;W = INI_DB2_BTB
;INICIALIZA DB2_BTB
;RETORNA
;**********************************************************************************************
GRAVA_EEPROM
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
BTFSC
GOTO
RETURN
ESP_FIM_GRV_EEPROM
TESTA_FIM_DA_GRAVACAO
CONF_GRV_EEPROM
CONFERE_DEZENA
APAGAR_UNIDADE
APAGA_UNIDADE_ANTERIOR
GRAVAR_UNIDADE
GRAVA_A_UNIDADE
GRAVAR_DEZENA
GRAVA_A_DEZENA
APAGA_UNIDADE_ANTERIOR
BANCO_1
MOVF
LOCAL_DA_UNIDADE,W
MOVWF
EEADR
CLRF
EEDATA
BSF
EECON1,WREN
BCF
INTCON,GIE
BTFSC
INTCON,GIE
GOTO
$-2
MOVLW
0x55
MOVWF
EECON2
MOVLW
0xAA
MOVWF
EECON2
BSF
EECON1,WR
BSF
INTCON,GIE
BCF
APAGAR_UNIDADE
BSF
ESP_FIM_GRV_EEPROM
BANCO_0
RETURN
GRAVA_A_UNIDADE
BANCO_1
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_GRV_UNIDADE
CLRF
EEADR
CONT_GRV_UNIDADE
MOVF
UNIDADE,W
MOVWF
EEDATA
MOVLW
B'01100000'
IORWF
EEDATA,F
BSF
EECON1,WREN
BCF
INTCON,GIE
;SIM
;NAO, GRAVAR UNIDADE?
;SIM
;NAO, GRAVAR DEZENA?
;SIM
;NAO
139
BTFSC
GOTO
MOVLW
MOVWF
MOVLW
MOVWF
BSF
BSF
BCF
BSF
BANCO_0
RETURN
INTCON,GIE
$-2
0x55
EECON2
0xAA
EECON2
EECON1,WR
INTCON,GIE
GRAVAR_UNIDADE
ESP_FIM_GRV_EEPROM
GRAVA_A_DEZENA
BANCO_1
INCF
EEADR,F
MOVF
DEZENA,W
MOVWF
EEDATA
BSF
EECON1,WREN
BCF
INTCON,GIE
BTFSC
INTCON,GIE
GOTO
$-2
MOVLW
0x55
MOVWF
EECON2
MOVLW
0xAA
MOVWF
EECON2
BSF
EECON1,WR
BSF
INTCON,GIE
BCF
GRAVAR_DEZENA
BSF
ESP_FIM_GRV_EEPROM
BSF
CONF_GRV_EEPROM
BANCO_0
RETURN
Parte 6 Contador II
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
BSF
BCF
BCF
BANCO_0
RETURN
GRAVAR_DEZENA
ESP_FIM_GRV_EEPROM
CONF_GRV_EEPROM
CONFERE_DEZENA
BANCO_1
BSF
EECON1,RD
MOVF
DEZENA,W
XORWF
EEDATA,W
BTFSC
STATUS,Z
GOTO
CONFERE_APAGAMENTO
BCF
CONF_GRV_EEPROM
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
BANCO_0
RETURN
CONFERE_APAGAMENTO
DECF
EEADR,F
DECF
EEADR,F
DECF
EEADR,F
MOVLW
.254
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONFERENCIA
MOVLW
.126
MOVWF
EEADR
CONT_CONFERENCIA
BSF
EECON1,RD
MOVF
EEDATA,W
BTFSC
STATUS,Z
GOTO
CONFERE_UNIDADE
BCF
CONF_GRV_EEPROM
BSF
APAGAR_UNIDADE
BSF
GRAVAR_UNIDADE
BSF
GRAVAR_DEZENA
BANCO_0
RETURN
CONFERE_UNIDADE
INCF
EEADR,F
INCF
EEADR,F
MOVLW
.128
XORWF
EEADR,W
BTFSS
STATUS,Z
GOTO
CONT_CONF_UNIDADE
CLRF
EEADR
CONT_CONF_UNIDADE
BSF
EECON1,RD
MOVF
UNIDADE,W
IORLW
B'01100000'
XORWF
EEDATA,W
BTFSC
STATUS,Z
GOTO
GRAVACAO_CORRETA
BCF
CONF_GRV_EEPROM
Parte 6 Contador II
;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
;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
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
142
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
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
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
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
Parte 6 Contador II
Figura 5
147
Parte 6 Contador II
Figura 6
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
Figura 3
Por outro lado, se aumentarmos o tempo de durao do semiciclo ativo,
mantendo o do ciclo, conforme figura abaixo, teremos a impresso de que o brilho do LED aumentou.
Figura 4
Como voc pode observar, o tempo de durao do ciclo do sinal no muda,
portanto a frequncia do sinal PWM, que igual ao inverso do valor do tempo de durao do ciclo,
no muda. O que ir mudar o tempo de durao do semiciclo ativo, isto , o tempo em que o sinal
ficar em nvel alto.
150
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
Para que no se perceba que o LED est piscando, temos de escolher uma
frequncia de, pelo menos, 75 Hz para o sinal PWM.
Vamos ver como o PIC16F628A produz o sinal PWM.
Na parte 2 deste tutorial, falamos sobre o Timer 0. O PIC16F628A possui
outros dois circuitos semelhantes: o Timer 1 e o Timer 2.
A principal diferena do Timer 1 em relao ao Timer 0 que ele composto
por dois registradores de 8 bits enquanto que o Timer 0 possui apenas um. Os registradores do Timer
1 so o TMR1L e o TMR1H.
Quando o Timer 1 incrementado, esse incremento ocorre no TMR1L que
pode ir at o valor 255. No prximo incremento, ele volta para o valor 0 e o TMR1H incrementado.
Assim, o Timer 1 pode ser incrementado at o valor 65535, o que o torna ideal para contagem de
tempos mais longos.
O Timer 1 pode ser incrementado tanto a partir do ciclo de instruo como a
partir de um sinal externo aplicado no pino 13 (RB7/T1OSI/PGD). Um cristal pode ser ligado entre
esse pino e o pino 12 (RB6/T1OSO/T1CKI/PGC), para fazer funcionar um oscilador interno
otimizado para a frequncia de 32.768 KHz, ideal para relgios.
O Timer 1 possui um prescaler que pode ser configurado para 1:1, 1:2, 1:4 ou
1:8.
O Timer 2, assim como o Timer 0, constitudo de apenas um registrador de 8
bits, o TMR2 e, portanto, seu valor pode ser incrementado at 255, porm, somente possvel
increment-lo a partir do ciclo de instruo, no sendo possvel increment-lo a partir de um sinal
externo.
O Timer 2 possui algumas caractersticas diferentes dos demais:
Existe um registrador chamado PR2 cujo valor define at onde o registrador
TMR2 poder ser incrementado. Por exemplo, se o valor do PR2 for igual a 255, o TMR2 poder ser
incrementado at esse valor e, no prximo incremento ele ir estourar, ou seja, seu valor voltar para
0. J, se o valor do PR2 for, por exemplo, 100, o TMR2 poder ser incrementado at esse valor
estourando no prximo incremento. Podemos escrever qualquer valor entre 0 e 255 no PR2.
O seu Prescaler pode assumir apenas os seguintes valores: 1:1, 1:4 ou 1:16, ou
seja, ele pode incrementado a cada ciclo de instruo ou a cada quatro ciclos ou a cada dezesseis
ciclos.
O Timer 2 possui um Postscaler, que pode ser configurado de 1:1 at 1:16. O
Postscaler define o nmero de vezes que o TMR2 dever estourar para gerar uma interrupo. Por
exemplo, se ele estiver configurado para 1:1, a cada vez que o TMR2 estourar, o flag TMR2IF ser
setado, gerando uma interrupo (desde que ela esteja habilitada). J, se o Postscaler estiver
configurado, por exemplo, para 1:5, uma interrupo ser gerada a cada 5 estouros do TMR2.
As configuraes do Prescaler e do Postscaler so feitas no registrador
T2CON, onde tambm h um bit para ligar e desligar o Timer 2.
no mdulo CCP do PIC16F628A que gerado o sinal PWM. A
configurao do mdulo CCP feita no registrador CCP1CON. Devemos setar os bits 3 e 2 desse
registrador para habilitar o modo PWM.
151
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
O ciclo do sinal PWM reinicia toda vez que o TMR2 estoura. A frmula para
o clculo do tempo de durao do ciclo do sinal PWM esta:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
fcil entender essa frmula, considerando que:
O ciclo termina (e um novo inicia) quando o TMR2 estoura.
O TMR2 estoura no prximo incremento aps seu valor se igualar ao PR2
(PR2 +1)
O TMR2 incrementado pelo ciclo de instruo.
O prescaler define de quantos em quantos ciclos de instruo o TMR2 ser
incrementado.
No nosso caso, queremos um sinal PWM com uma frequncia de 75 Hz, o
que equivale a um ciclo de cerca de 13 milissegundos. Como estamos usando o oscilador interno do
PIC, que de 4 MHz, o ciclo de instruo tem a durao de 1 microssegundo, pois o ciclo de instruo igual a quatro vezes o valor do ciclo do oscilador (1/4.000.000 x 4).
Vamos aplicar a frmula com o valor do prescaler em 1:1:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 1
0,013 =
(PR2 + 1) x 0,000001
PR2 + 1 = 0,013/0,000001
PR2 + 1 = 13.000
PR2 = 13.000 1
PR2 = 12.999
Mas, o valor mximo para o PR2 de 255. Vamos ver qual seria o valor do
PR2 para um prescaler de 1:4:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 4
0,013 =
(PR2 + 1) x 0,000004
PR2 + 1 = 0,013/0,000004
PR2 + 1 = 3.250
PR2 = 3.250 1
PR2 = 3.249
Novamente obtivemos um valor muito alto para o PR2. Vamos, ento, aumentar o valor do prescaler para 1:16:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
0,013 =
(PR2 + 1) x 0,000001 x 16
0,013 =
(PR2 + 1) x 0,000016
PR2 + 1 = 0,013/0,000016
PR2 + 1 = 812,5
PR2 = 812,5 1
PR2 = 811,5
152
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
O valor a ser escrito no PR2 continua acima de 255. Isto mostra que no
possvel obter um sinal PWM de 75 Hz se a frequncia de oscilao do microcontrolador de 4 MHz.
Teramos de diminuir a frequncia do oscilador se quisssemos um sinal PWM de 75 Hz. Poderamos
fazer isso alterando a frequncia do oscilador interno para 48 KHz ou ento usando um cristal externo.
Escrevendo no PR2 o seu valor mximo (255) e configurando o prescaler
tambm para seu valor mximo (16), obtemos a mxima durao do ciclo do sinal PWM para uma
frequncia de oscilao de 4 MHz:
Ciclo = (PR2 + 1) x ciclo de instruo x prescaler do TMR2
Ciclo = (255 + 1) x 0,000001 x 16
Ciclo = 256 x 0,000001 x 16
Ciclo = 0,004096 segundo
Esse tempo de durao do ciclo corresponde frequncia de 244 Hz
(1/0,0049096). No nosso circuito, precisamos que o sinal PWM tenha uma frequncia maior do que
75 Hz para evitar que se perceba que o LED est piscando. Sendo assim, podemos usar a frequncia
de 244 Hz, at mesmo porque o LED pode operar em frequncias bem maiores que esta.
Vimos como definir a durao do ciclo do sinal PWM. Vamos ver agora como
se define o tempo de durao do semiciclo ativo. O semiciclo ativo comea junto com o ciclo e termina quando o sinal vai para nvel baixo.
O sinal PWM do PIC16F628A pode ter uma resoluo de at 10 bits, dependendo da frequncia do prprio sinal e da frequncia de oscilao. Uma resoluo de 10 bits significa
que podemos definir 1024 (210) tempos de durao diferentes para o semiciclo ativo.
No nosso caso, o tempo de durao do ciclo de 4,096 milissegundos. Dividindo este valor por 1024, conclumos que podemos variar o tempo de durao do semiciclo ativo em
passos de 0,004 milissegundo desde o mnimo de 0,004 milissegundo at o mximo de 4,092 milissegundos.
Para definirmos o tempo de durao do semiciclo ativo, escrevemos um valor
entre 0 e 1024 na combinao de 10 bits formada pelo registrador CCPR1L e os bits 5 e 4 do registrador CCP1CON. Nessa combinao, o registrador CCPR1L representa os 8 bits mais significativos:
Bit 9
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
CCPR1L
Bit 3
Bit 2
Bit 1
CCP1CON
Bit 5
Bit 0
CCP1CON
Bit 4
Tabela 1
Se escrevermos o valor 0, o sinal ficar o tempo todo em nvel baixo. Se escrevermos o valor 1024, ele ficar o tempo todo em nvel alto. Nesses casos, no teremos um sinal
PWM.
Se escrevermos o valor 1, o semiciclo ter a durao mnima (0,004 milissegundo) e, se escrevermos o valor 1023, a mxima (4,092 milissegundos).
Vamos supor que queiramos que o tempo de durao do semiciclo ativo seja
de 10% do tempo de durao do ciclo. Nesse caso, temos de escrever o valor 102,4 (10% de 1024)
nos 10 bits da referida combinao.
Como o nmero a ser escrito tem de ser inteiro, arredondamos para 102, que,
em binrio, igual a 1100110. Portanto:
153
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
Bit 9
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
CCP1CON
Bit 5
Bit 0
CCP1CON
Bit 4
CCPR1L
Tabela 2
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
BOTAO_1
BOTAO_2
PORTA,0
PORTA,1
;***********************************************************************************************
0X04
BTFSS
RETFIE
BCF
INTCON,T0IF
;TMR0 ESTOUROU?
;NAO, SAI DA INTERRUPO
;SIM, APAGA O FLAG
INTCON,T0IF
.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_2
DECREMENTA_CCPR1L
;W = 255
;W = W XOR CCPRR1L
;CCPR1L = 255?
;SIM, SAI DA INTERRUPO
CCPR1L,F
;W = 0
;W = W XOR CCPRR1L
;CCPR1L = 0?
;SIM, SAI DA INTERRUPO
;NAO, DECREMENTA CCPR1L
;SAI DA INTERRUPO
157
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
;***********************************************************************************************
;
B'11010110'
OPTION_REG
B'11111111'
TRISA
;W = B'11111111'
;CONFIGURA PORTA COMO ENTRADA
B'11110111'
TRISB
;W = B'11110111'
;CONFIGURA BR3/CCP1 COMO SADA E DEMAIS COMO ENTRADA
.255
PR2
;W = 255
;PR2 = 255
B'00000110'
T2CON
Em seguida zeramos o CCPR1L para que quando o circuito for ligado o LED
esteja apagado:
CLRF
CCPR1L
;ZERA CCPR1L
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
;LIMPA O WDT
;RETORNA UMA LINHA
$-1
;**********************************************************************************************
;***********************************************************************************************
;
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
;***********************************************************************************************
;
ENTRADAS
#DEFINE
#DEFINE
BOTAO_1
BOTAO_2
PORTA,0
PORTA,1
;***********************************************************************************************
159
Tutorial de Programao Assembly para Microcontroladores PIC - Parte 7 Dimmer para LED
;***********************************************************************************************
;
VETOR DE RESET
ORG
0X00
GOTO
INICIO
;***********************************************************************************************
;
ROTINA DE INTERRUPO
ORG
0X04
BTFSS
RETFIE
BCF
MOVLW
MOVWF
BTFSS
GOTO
BTFSS
GOTO
RETFIE
INTCON,T0IF
;TMR0 ESTOUROU?
;NAO, SAI DA INTERRUPO
;SIM, APAGA O FLAG
;W = 108
;REINICIA TMR0
;BOTAO 1 EST PRESSIONADO?
;SIM
;NAO, BOTAO 2 EST PRESSIONADO?
;SIM
;NAO, SAI DA INTERRUPO
INTCON,T0IF
.108
TMR0
BOTAO_1
INCREMENTA_CCPR1L
BOTAO_2
DECREMENTA_CCPR1L
INCREMENTA_CCPR1L
MOVLW
.255
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE
INCF
CCPR1L,F
RETFIE
;W = 255
;W = W XOR CCPRR1L
;CCPR1L = 255?
;SIM, SAI DA INTERRUPO
;NAO, INCREMENTA CCPR1L
;SAI DA INTERRUPO
DECREMENTA_CCPR1L
MOVLW
.0
XORWF
CCPR1L,W
BTFSC
STATUS,Z
RETFIE
DECF
CCPR1L,F
RETFIE
;W = 0
;W = W XOR CCPRR1L
;CCPR1L = 0?
;SIM, SAI DA INTERRUPO
;NAO, DECREMENTA CCPR1L
;SAI DA INTERRUPO
;************************************************************************************************
;
CONFIGURACAO DOS REGISTRADORES DE USO ESPECFICO
INICIO
BANCO_1
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
BANCO_0
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
B'11010110'
OPTION_REG
B'11111111'
TRISA
B'11110111'
TRISB
.255
PR2
B'00000111'
CMCON
B'11100000'
INTCON
B'00000110'
;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
;**********************************************************************************************
;
ROTINA PARA AGUARDAR A INTERRUPO
CLRWDT
GOTO
$-1
;LIMPA O WDT
;RETORNA UMA LINHA
;**********************************************************************************************
END
;FIM DO PROGRAMA
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
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