Para Microcontroladores
Modelo MMDB-01
01 SOFTWARES RECOMENDADOS............................... 02
_______________________________________________
01
01. SOFTWARES RECOMENDADOS
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Existem vários programas de uso livre ou shareware que podem
se constituir em importantes auxiliares no estudo e
desenvo lvi men to de sof twares para apli cações com
microcontroladores.
http://www.metaice.com/ASM51/ASM51.htm
2. SIM8052.
Si mulador de 8051 para ambiente Windows.
Endereço para download:
http://www.vaultbbs.com/sim8052
3. ConTEXT.
Editor de texto para programadores.
Endereço para download:
http://www.context.cx
4. PICcom.
Ferramenta de desenvolvimento que auxilia na depuração de
programas através da porta serial.
Endereço para download:
http://www.semis.demon.co.uk/PICcom/PICcom.htm
http://www.microchip.com
_______________________________________________
02
6. AVR Studio.
Conjunto de ferramentas para desenvolvimento de
aplicações com microcontroladores da família AVR, incluindo
montador assembly e simulador.
Endereço para download:
http://www.atmel.com
http://www.atmel.com
8. SpiPgm.
Programa de gravação serial.
Endereço para download:
http://www.geocities.com/asim1108/spipgm/spipgm.zip
http://www.serial-port-monitor.com/
http://sdcc.sourceforge.net/
_______________________________________________
03
02. EXEMPLOS DE PROGRAMAS
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Nesta seção são mostrados alguns exemplos de programas
escritos em linguagem assembly para microcontroladores da família
MCS-51. Para todos os exemplos o teclado deverá ser programado
para 4 teclas através do jumper JP16.
;-------------------------------------------------------------------------------
$MOD89S52
$TITLE(Contador binario mostrado em P1)
;-------------------------------------------------------------------------------
;
; Esta rotina serve para demonstrar que pode ser usada uma posição da
; memória RAM como um contador, no presente caso o resultado da contagem
; vai ser mostrado através dos LEDs da porta P1, e o contador será
; incrementado a cada segundo.
;
;-------------------------------------------------------------------------------
; Segmento de Bits
;
; Segmento da memória RAM, onde se pode trabalhar com um único bit, que são
; usados como sinalizadores (Flags).
; Este segmento começa na posição 020h e vai até 02Fh, totalizando 16 bytes,
; o que permite que o usuário tenha até 128 Flags no seu programa
;-------------------------------------------------------------------------------
BSEG at 0h
ContadorBinario: DS 1
Temporario: DS 3
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
04
IcializaPlaca:
mov P0,#0 ; Coloca "0" em todos os pinos da
; porta 0 para apagar os LEDs
mov P1,#0 ; Coloca "0" em todos os pinos da
; porta 1 para apagar os LEDs
mov P2,#0 ; Coloca "0" em todos os pinos da
; porta 2 para apagar os LEDs
mov P3,#0 ; Coloca "0" em todos os pinos da
; porta 3 para apagar os LEDs
;-------------------------------------------------------------------------------
Delay1Seg:
mov Temporario,#84 ; Carrega 3 bytes para contar 921600
mov Temporario+1,#254 ; ciclos de máquina, que é a quantidade
mov Temporario+2,#7 ; de ciclos que
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do codigo
_______________________________________________
05
02.02. Acendimento Seqüencial de Todos os LED’s:
ByteSequencial: DS 1
Temporario: DS 3
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
org 0000h ; Endereço de inicialização do
; microcontrolador, o qual vai para este
; quando é resetado
;-------------------------------------------------------------------------------
InicializaPlaca: ; Vai inicializar a placa
mov P0,#0 ; Coloca "0" em todos os pinos da
; porta 0 para apagar os LEDs
mov P1,#0 ; Coloca "0" em todos os pinos da
; porta 1 para apagar os LEDs
mov P2,#0 ; Coloca "0" em todos os pinos da
; porta 2 para apagar os LEDs
mov P3,#0 ; Coloca "0" em todos os pinos da
; porta 3 para apagar os LEDs
LoopSequencialP1:
mov P1,A ; Envia o conteúdo do acumulador para P1
rr A ; Desloca o acumulador para a direita
call Delay1Seg ; Aguarda 1 segundo
cjne A,#080h,LoopSequencialP1 ;
; Quando chegar a 080h é porque já fez
; toda a seqüência em P1
mov P1,#0 ; Apaga todos os LEDs da porta 1
LoopSequencialP2:
mov P2,A ; Envia o conteúdo do acumulador para P2
rr A ; Desloca o acumulador para a direita
call Delay1Seg ; Aguarda 1 segundo
cjne A,#080h,LoopSequencialP2 ;
; Quando chegar a 080h é porque já fez
; toda a seqüência em P2
mov P2,#0 ; Apaga todos os LEDs da porta 2
LoopSequencialP3:
mov P3,A ; Envia o conteúdo do acumulador para P3
rr A ; Desloca o acumulador para a direita
call Delay1Seg ; Aguarda 1 segundo
cjne A,#080h,LoopSequencialP3 ;
; Quando chegar a 080h é porque já fez
; toda a seqüência em P3
mov P3,#0 ; Apaga todos os LEDs da porta 3
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do código
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
;-------------------------------------------------------------------------------
Delay1Seg:
mov Temporario,#84 ; Carrega 3 bytes para contar 921600
mov Temporario+1,#254 ; ciclos de máquina, que é a quantidade
mov Temporario+2,#7 ; de ciclos que
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do código
_______________________________________________
09
02.04. Cronômetro Binário nos LED’s da Porta P1:
;-------------------------------------------------------------------------------
; Segmento de Bits
;
; Segmento da memória RAM, onde se pode trabalhar com um único bit, que são
; usados como sinalizadores (Flags).
; Este segmento começa na posição 020h e vai até 02Fh, totalizando 16 bytes,
; o que permite que o usuário tenha até 128 Flags no seu programa
;-------------------------------------------------------------------------------
BSEG at 0h
Passou1Segundo: DBIT 1
PartePara: DBIT 1
Zera: DBIT 1
TeclaValida: DBIT 1
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
DSEG at 22h
ContadorBinario: DS 1
Tempo1Segundo: DS 1
Temporario: DS 3
Debounce: DS 1
_______________________________________________
10
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
SaiTimer2:
reti ; Saída da interupção do timer 2
;-------------------------------------------------------------------------------
InicializaPlaca: ; Vai inicializar a placa
setb TR2 ; Habilita timer 2
setb PT2 ; Timer 2 com prioridade alta
setb ET2 ; Habilita interrupção do timer 2
setb EA ; Habilita o controlador de interrupt
clr CAP2 ; Coloca o timer 2 para recarregar
; automaticamente
_______________________________________________
11
; teclas com 10 x 10 mS = 100 mS
Principal:
mov Tempo1Segundo,#100 ; Carrega o contador de 1 segundo com
; (100 x 10 mS = 1 S)
clr Passou1Segundo ; Sinaliza que ainda não passou o
; segundo
orl PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
jb PartePara,IncCronometro ; Se o flag PartePara estiver ligado,
; vai incrementar o cronometro
jnb Zera,Principal ; Se o flag PartePara estiver desligado
; e o flag Zera também, vai para a
; Principal caso contrario vai zerar o
; cronometro
;-------------------------------------------------------------------------------
ZeraCronometro:
mov ContadorBinario,#0 ; Carrega ContadorBinario com '0'
mov P1,ContadorBinario ; Copia o valor do Contador binário
; em P1
clr Zera ; Desliga o flag Zera, pois já zerou
; o cronômetro
sjmp Principal ; Volta para Principal
;-------------------------------------------------------------------------------
IncCronometro:
mov P1,ContadorBinario ; Copia o valor do Contador binário
; em P1
inc ContadorBinario ; Incrementa o Contador binário
jnb Passou1Segundo,$ ; Espera passar 1 segundo
sjmp Principal ; Volta para Principal
;-------------------------------------------------------------------------------
TrataTecla:
jb TeclaValida,AguardaFimDeTecla ;
; Se tiver tecla apertada, vai aguardar
; que a mesma seja liberada
jb TeclaPartePara,TestaTeclaZera ;
; Se a tecla parte para não estiver
; pressionada, vai testar tecla zera
djnz Debounce,SaiTrataTecla ; Sai enquanto não passar o tempo de
; debounce
setb TeclaValida ; Sinaliza que tem uma tecla válida
cpl PartePara ; Sinaliza que é para partir ou parar
; o cronometro
sjmp SaiTrataTecla ; Sai da rotina
TestaTeclaZera:
jb PartePara,SaiTrataTecla ; Não testa tecla zera se o cronometro
; estiver rodando
jb TeclaZera,SaiTrataTecla ; Sai se a tecla zera não estiver
; pressionada
djnz Debounce,SaiTrataTecla ; Sai enquanto não passar o tempo de
; debounce
setb TeclaValida ; Sinaliza que tem uma tecla válida
setb Zera ; Sinaliza que é para zerar o cronômetro
sjmp SaiTrataTecla ; Sai da rotina
AguardaFimDeTecla:
mov A,P2 ; Le a porta 2 para testar se ainda tem
; tecla apertada
orl A,#11110110b ; Coloca "1" nos bits não usados
cpl A ; Inverte o conteúdo do acumulador
_______________________________________________
12
jnz SaiTrataTecla ; Sai se o acumulador não estiver com
; "0", é sinal de que ainda tem tecla
; apertada
mov Debounce,#10 ; Recarrega o contador de debounce
; com 100 mS
clr TeclaValida ; Sinaliza que não tem mais nenhuma
; tecla apertada
SaiTrataTecla:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do codigo
_______________________________________________
13
02.05. Cronômetro Digital no Display LCD:
;-------------------------------------------------------------------------------
; Segmento de Bits
;
; Segmento da memória RAM, onde se pode trabalhar com um único bit, que são
; usados como sinalizadores (Flags).
; Este segmento começa na posição 020h e vai até 02Fh, totalizando 16 bytes,
; o que permite que o usuário tenha até 128 Flags no seu programa
;-------------------------------------------------------------------------------
BSEG at 0h
PartePara: DBIT 1
LAP: DBIT 1
Zera: DBIT 1
TeclaValida: DBIT 1
_______________________________________________
14
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
DSEG at 22h
Horas: DS 1
Minutos: DS 1
Segundos: DS 1
CentesimosDeSegundos: DS 1
Tempo1Segundo: DS 1
Debounce: DS 1
ComandoLCD: DS 1 ; Registro destinado ao envio de
; comandos para o display LCD
Temporario: DS 3
DSEG at 40h
Linha1doDisplay: DS 16
Linha2doDisplay: DS 16
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
;-------------------------------------------------------------------------------
InicializaPlaca:
InicializaLCD:
call Retardo4mS
call Retardo4mS
call Retardo4mS
_______________________________________________
call Retardo4mS
15
clr EnLCD
clr RsLCD ; Coloca o display para receber Comandos
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
call Retardo4mS
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#080h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#060h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#0C0h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#010h
call EnviaNibleAltoParaDisplayLCD
setb RsLCD ; Coloca o display para receber Dados
call Retardo4mS
call ApagaDisplay
;-------------------------------------------------------------------------------
; Inicializa timer
;-------------------------------------------------------------------------------
setb TR2 ; Habilita timer 2
setb PT2 ; Timer 2 com prioridade alta
setb ET2 ; Habilita interrupção do timer 2
setb EA ; Habilita o controlador de interrupt
clr CAP2 ; Coloca o timer 2 para recarregar
; automaticamente
TestaTeclaLAP:
jnb PartePara,TestaTeclaZera ;
; Vai testar tecla zera somente se o
; cronometro estiver parado
jb TeclaLAP,SaiTrataTecla ; Sai da rotina se a tecla LAP não
; estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer o
; tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
cpl LAP ; Entra ou sai do modo LAP
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
TestaTeclaZera:
jb PartePara,SaiTrataTecla ; Não testa tecla zera se o cronometro
; estiver rodando
jb TeclaZera,SaiTrataTecla ; Sai da rotina se a tecla zera não
; estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer o
; tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
setb Zera ; Sinaliza que é para zerar o cronometro
_______________________________________________
17
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
AguardaFimDeTecla:
mov A,P2 ; Le a porta 2 para testar se ainda tem
; tecla apertada
orl A,#11110010b ; Coloca "1" nos bits não usados
cpl A ; Inverte o conteúdo do acumulador
jnz SaiTrataTecla ; Sai se o acumulador não estiver com
; '0', sinal de que ainda tem tecla
; apertada
mov Debounce,#10 ; Recarrega o contador de debounce com
; 100 mS
clr TeclaValida ; Sinaliza que não tem nenhuma tecla
; apertada
SaiTrataTecla:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
IncrementaCronometro:
inc CentesimosDeSegundos ; Incrementa o contador de centésimos
; de segundos
mov A,CentesimosDeSegundos ; Carrega acumulador com o contador
; de centésimos de segundos
cjne A,#100,SaiIncrementaCronometro ;
; Testa se já chegou a 100, se não
; chegou sai da rotina de incrementar
; cronometro
mov CentesimosDeSegundos,#0 ; Carrega o contador de centésimos de
; segundos com '0'
ContaSegundos:
inc Segundos ; Incrementa contador de segundos
mov A,Segundos ; Carrega acumulador com o contador
; de segundos
cjne A,#60,SaiIncrementaCronometro ;
; Testa se já chegou a 60, se não chegou
; sai da rotina de incrementar
; cronometro
mov Segundos,#0 ; Carrega o contador de segundos com '0'
ContaMinutos:
inc Minutos ; Incrementa contador de minutos
mov A,Minutos ; Carrega acumulador com o contador
; de minutos
cjne A,#60,SaiIncrementaCronometro ;
; Testa se já chegou a 60, se não chegou
; sai da rotina de incrementar
; cronometro
mov Minutos,#0 ; Carrega o contador de minutos com '0'
ContaHoras:
inc Horas ; Incrementa contador de horas
mov A,Horas ; Carrega acumulador com o contador
; de horas
cjne A,#100,SaiIncrementaCronometro ;
; Testa se já chegou a 100, se não
; chegou sai da rotina de incrementar
mov Horas,#0 ; Carrega o contador de horas com '0'
SaiIncrementaCronometro:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
EscreveCronometroNoLCD:
mov A,Horas ; Carrega o acumulador com Horas
mov B,#10 ; Carrega o registrador 'B' com 10
_______________________________________________
18
div AB ; Divide 'A' por 'B', então 'A' sai com
; a dezena de horas e 'B' com a unidade
;-------------------------------------------------------------------------------
_______________________________________________
19
; Escreve Mensagem no Display LCD
;-------------------------------------------------------------------------------
EscreveMensagem:
clr A ; Zera o acumulador para que na próxima
; instrução só tenha valor o DPTR
movc A,@A+DPTR ; Busca caractere da mensagem na memória
; de programa
cjne A,#ETX,EscreveMensagem1 ; Testa se chegou ao fim da mensagem
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
EscreveMensagem1:
mov @R0,A ; Escreve no buffer o que
; pegou na mensagem
inc R0 ; Incrementa o ponteiro
; do buffer do Display
inc DPTR ; Incrementa o ponteiro da mensagem
jmp EscreveMensagem ; Volta para escrever o próximo
; caractere no display
; Fim EscreveMensagem
;-------------------------------------------------------------------------------
; Apaga Display
;-------------------------------------------------------------------------------
ApagaDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#32 ; Carrega tamanho do buffer do Display
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaDisplay
;-------------------------------------------------------------------------------
; Apaga Linha 1 do Display
;-------------------------------------------------------------------------------
ApagaLinha1doDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 1
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha1doDisplay ; Vai transferir para a linha 1 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha1doDisplay
;-------------------------------------------------------------------------------
; Apaga linha 2 do Display
;-------------------------------------------------------------------------------
ApagaLinha2doDisplay:
mov R0,#Linha2doDisplay ; Carrega ponteiro com inicio
; da linha 2 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 2
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha2doDisplay ; Vai transferir para a linha 2 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha2doDisplay
;-------------------------------------------------------------------------------
; Limpa buffer do Display LCD
; Escreve espaços (brancos) no buffer do display
;-------------------------------------------------------------------------------
_______________________________________________
20
LimpaBufferDisplay:
mov A,#' ' ; Carrega ACC com espaço
CLS1: mov @R0,A ; Escreve espaço na memória de Display
inc R0 ; Incrementa ponteiro da memória
djnz R1,CLS1 ; Testa se ja apagou toda memória
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
; Escreve no display
; Escreve todo o conteúdo do buffer do display na memória do mesmo
;-------------------------------------------------------------------------------
EscreveDisplay:
call EscreveLinha1doDisplay ; Vai escrever a Linha 1 do display
call EscreveLinha2doDisplay ; Vai escrever a Linha 2 do display
ret ; Retorna para onde veio
; Fim EscreveDisplay
;-------------------------------------------------------------------------------
; Escreve linha 1 do display
; Esta rotina escreve o conteudo do buffer
; da linha 1 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha1doDisplay:
; Envia o comando para mudar para o início da linha 1
mov ComandoLCD,#080h ; Comando para mudar para o inicio
; da linha 1 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 1 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha1doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha1doDisplay+16,LoopLinha1doDisplay ;
; Testa o fim da linha 1
ret ; Retorna para onde veio
; Fim EscreveLinha1doDisplay
;-------------------------------------------------------------------------------
; Escreve linha 2 do display
; Esta rotina escreve o conteudo do buffer
; da linha 2 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha2doDisplay:
; Envia o comando para mudar para o início da linha 2
mov ComandoLCD,#0C0h ; Comando para mudar para o inicio
; da linha 2 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 2 do display
setb RsLCD ; Coloca o display para receber DADOS
; Fim EscreveLinha2doDisplay
;-------------------------------------------------------------------------------
; Envia byte para o display LCD
; Esta rotina envia um byte de comando ou de dado para o display LCD
;-------------------------------------------------------------------------------
EnviaByteParaDisplayLCD:
mov A,@R0 ; Carrega ACC com a memória de Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Fim EnviaByteParaDisplayLCD
;-------------------------------------------------------------------------------
; Envia nibble alto para o display LCD
; Esta rotina é usada apenas na inicialização do display
;-------------------------------------------------------------------------------
EnviaNibleAltoParaDisplayLCD:
; Coloca nible alto no barramento
_______________________________________________
22
anl A,#0F0h ; Mascara para não perturbar a parte
; baixa da Porta 2
anl BarramentoDoDisplay,#00Fh ;
; Zera o nibble alto para que a próxima
; instrução funcione corretamente
orl BarramentoDoDisplay,A ; Envia nibble alto para o Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 200 uS
mov R7,#100 ; Carrega para 200 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 200 uS
; Fim EnviaNibleAltoParaDisplayLCD
;-------------------------------------------------------------------------------
Retardo100mS:
mov R3,#181 ; Carrega R3 para um retardo de 100 mS,
; com um cristal de 11,0592 MHz
sjmp Retardo4mS1
;-------------------------------------------------------------------------------
Retardo4mS:
mov R3,#8 ; Carrega R3 para um retardo de 4 mS,
; com um cristal de 11,0592 MHz
Retardo4mS1:
mov R4,#39
Retardo4mS2: ; Fica neste loop até que os 2 registros
; cheguem a '0', quando então terá
; transcorrido 4 mS ou 100 mS,
; dependendo do valor de R3
djnz R4,Retardo4mS2
djnz R3,Retardo4mS2
ret ; Retorna para onde veio
_______________________________________________
23
02.06. Mensagem com Deslocamento no Display LCD:
;-------------------------------------------------------------------------------
; Segmento de bits
; Segmento da memória RAM, onde se pode trabalhar com um único bit, que são
; usados como sinalizadores (Flags).
; Este segmento começa na posição 020h e vai até 02Fh, totalizando 16 bytes,
; o que permite que o usuário tenha até 128 Flags no seu programa
BSEG at 0h
Passou300mS: DBIT 1
TeclaValida: DBIT 1
PassouSegundos: DBIT 1
;-------------------------------------------------------------------------------
; Segmento da memória RAM
DSEG at 22h
Segundos: DS 1
Tempo1Segundo: DS 1
ComandoLCD: DS 1
Debounce: DS 1
Tempo300mS: DS 1
Temporario: DS 3
DSEG at 40h
_______________________________________________
24
Linha1doDisplay: DS 16
Linha2doDisplay: DS 16
call TrataTecla
djnz Tempo1Segundo,SaiTimer2
mov Tempo1Segundo,#100
djnz Segundos,SaiTimer2
setb PassouSegundos
SaiTimer2:
reti
;-------------------------------------------------------------------------------
IcializaPlaca:
InicializaLCD:
call Retardo4mS
call Retardo4mS
call Retardo4mS
call Retardo4mS
clr EnLCD
clr RsLCD ; Coloca o display para receber Comandos
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
call Retardo4mS
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#080h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#060h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#0C0h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
_______________________________________________
25
mov A,#010h
call EnviaNibleAltoParaDisplayLCD
setb RsLCD ; Coloca o display para receber Dados
call Retardo4mS
call ApagaDisplay
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
mov DPTR,#MsgMMDB ; Carrega DPTR com endereço da mensagem
mov R0,#Linha1doDisplay ; Carrega R0 com endereço de início do
; buffer do display
call EscreveMensagem ; Vai escrever a mensagem
ScrollMensagem:
mov DPTR,#MsgMMDB1 ; Carrega o DPTR com a mensagem a
; deslocar
call ApagaLinha2doDisplay ; Apaga a linha 2 do display
;-------------------------------------------------------------------------------
DeslocaMsg:
call DeslocaLinha2 ; Vai deslocar todo o buffer da linha 2
; uma posição para esquerda
clr A ; Zera o acumulador para usar na próxima
; instrução
movc A,@A+DPTR ; Busca 1 caractere da mensagem
inc DPTR ; Incrementa ponteiro da mensagem para
; usar quando for buscar o próximo
; caractere da mensagem
cjne A,#ETX,DeslocaMsg1 ; Testa caractere para ver se já chegou
; ao fim da mensagem, se não vai
; escrever o caractere na última posição
; do buffer da linha 2
sjmp TerminaDeDeslocar ; Vai deslocar 16 vezes com espaços,
; para terminar o deslocamento
DeslocaMsg1:
_______________________________________________
26
mov Linha2doDisplay+15,A ; Escreve o caractere na última posição
; do buffer da linha 2
call EscreveLinha2doDisplay ; Escreve o conteúdo do buffer da linha
; linha 2 no display
call Retardo200mS ; Espera 200 mS (velocidade de
; deslocamento da mensagem)
sjmp DeslocaMsg ; Volta para deslocar de novo
TerminaDeDeslocar:
mov R3,#16 ; carrega R3 com 16 para terminar o
; deslocamento
TerminaDeDeslocar1:
mov Linha2doDisplay+15,#' ' ; Carrega a última posição do buffer
; com espaço
call DeslocaLinha2 ; Vai deslocar todo o buffer da linha 2
; uma posição para esquerda
call EscreveLinha2doDisplay ; Escreve o conteúdo do buffer da linha
; linha 2 no display
call Retardo200mS ; Espera 200 mS (velocidade de
; deslocamento da mensagem)
djnz R3,TerminaDeDeslocar1 ; Se R3 não chegou a '0' volta para
; deslocar mais uma vez
sjmp ScrollMensagem ; Quando termina o deslocamento volta
; a fazer novamente
; Fim DeslocaMsg
;-------------------------------------------------------------------------------
DeslocaLinha2:
mov R0,#Linha2doDisplay ; Carrega R0 com a primeira posição do
; buffer da linha 2
mov R1,#Linha2doDisplay+1 ; Carrega R1 com a segunda posição do
; buffer da linha 2
DeslocaLinha21:
mov A,@R1 ; Carrega acumulador com o caractere da
; segunda posição
mov @R0,A ; Escreve caractere da segunda posição
; na primeira posição
inc R0 ; Incrementa R0 para usar no próximo
; deslocamento
inc R1 ; Incrementa R1 para usar no próximo
; deslocamento
cjne R0,#Linha2doDisplay+15,DeslocaLinha21 ;
; Testa se já chegou na última posição
; da linha 2
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
Retardo200mS:
jb Passou300mS,Retardo200mS1 ;
; Se flag Passou300mS estiver ligado vai
; aguardar 200 mS e então fazer novo
; deslocamento
jb TeclaValida,Retardo200mS ;
; Enquanto flag TeclaValida estiver
; ligada volta a testar se já passou
; 300 mS
jnb TeclaValida,$ ; Fica aqui aguardando que a tecla de
; passo a passo seja pressionada
sjmp SaiRetardo200mS ; Sai da rotina
Retardo200mS1:
mov R7,#22 ; Carrega R7 para esperar 200 mS
Retardo200mS2:
orl PCON,#1 ; A CPU se desativa, e só volta a se
_______________________________________________
27
; ativar quando ocorrer uma interrupção
djnz R7,Retardo200mS2 ; Volta enquanto R7 não chegar a '0'
SaiRetardo200mS:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
TrataTecla:
jb TeclaValida,AguardaFimDeTecla ;
; Vai aguardar finalização de qualquer
; tecla
jb TeclaPasso,SaiTrataTecla ;
; Vai testar tecla Alarme somente se a
; tecla parte/para não estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer o
; tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
clr Passou300mS ; Desliga flag para parar o deslocamento
; automático
sjmp SaiTrataTecla ; Sai da rotina de tratar tecla
AguardaFimDeTecla:
mov A,P2 ; Le a porta 2 para testar se ainda tem
; tecla apertada
orl A,#11111110b ; Coloca "1" nos bits não usados
cpl A ; Inverte o conteúdo do acumulador
jnz AguardaFimDeTecla1 ; Sai se o acumulador não estiver com
; '0', sinal de que ainda tem tecla
; apertada
mov Debounce,#10 ; Recarrega o contador de debounce com
; 100 mS
clr TeclaValida ; Sinaliza que não tem nenhuma tecla
; apertada
mov Tempo300mS,#30 ; Recarrega o contador de tempo
; de 300 mS
AguardaFimDeTecla1:
djnz Tempo300mS,SaiTrataTecla ;
; Decrementa o contador de tempo de
; 300 mS, e sai se ainda não tiver
; passado os 300 mS
setb Passou300mS ; Sinaliza que já passou os 300 mS
SaiTrataTecla:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
; Escreve Mensagem no Display LCD
;-------------------------------------------------------------------------------
EscreveMensagem:
clr A ; Zera o acumulador para que na próxima
; instrução só tenha valor o DPTR
movc A,@A+DPTR ; Busca caractere da mensagem na memória
; de programa
cjne A,#ETX,EscreveMensagem1 ; Testa se chegou ao fim da mensagem
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
EscreveMensagem1:
mov @R0,A ; Escreve no buffer o que
; pegou na mensagem
inc R0 ; Incrementa o ponteiro
; do buffer do Display
inc DPTR ; Incrementa o ponteiro da mensagem
jmp EscreveMensagem ; Volta para escrever o próximo
_______________________________________________
28
; caractere no display
; Fim EscreveMensagem
;-------------------------------------------------------------------------------
; Apaga Display
;-------------------------------------------------------------------------------
ApagaDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#32 ; Carrega tamanho do buffer do Display
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaDisplay
;-------------------------------------------------------------------------------
; Apaga Linha 1 do Display
;-------------------------------------------------------------------------------
ApagaLinha1doDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 1
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha1doDisplay ; Vai transferir para a linha 1 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha1doDisplay
;-------------------------------------------------------------------------------
; Apaga linha 2 do Display
;-------------------------------------------------------------------------------
ApagaLinha2doDisplay:
mov R0,#Linha2doDisplay ; Carrega ponteiro com inicio
; da linha 2 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 2
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha2doDisplay ; Vai transferir para a linha 2 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha2doDisplay
;-------------------------------------------------------------------------------
; Limpa buffer do Display LCD
; Escreve espaços (brancos) no buffer do display
;-------------------------------------------------------------------------------
LimpaBufferDisplay:
mov A,#' ' ; Carrega ACC com espaço
CLS1: mov @R0,A ; Escreve espaço na memória de Display
inc R0 ; Incrementa ponteiro da memória
djnz R1,CLS1 ; Testa se ja apagou toda memória
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
; Escreve no display
; Escreve todo o conteúdo do buffer do display na memória do mesmo
;-------------------------------------------------------------------------------
EscreveDisplay:
call EscreveLinha1doDisplay ; Vai escrever a Linha 1 do display
call EscreveLinha2doDisplay ; Vai escrever a Linha 2 do display
ret ; Retorna para onde veio
; Fim EscreveDisplay
;-------------------------------------------------------------------------------
_______________________________________________
29
; Escreve linha 1 do display
; Esta rotina escreve o conteúdo do buffer
; da linha 1 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha1doDisplay:
; Envia o comando para mudar para o início da linha 1
mov ComandoLCD,#080h ; Comando para mudar para o inicio
; da linha 1 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 1 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha1doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha1doDisplay+16,LoopLinha1doDisplay ;
; Testa o fim da linha 1
ret ; Retorna para onde veio
; Fim EscreveLinha1doDisplay
;-------------------------------------------------------------------------------
; Escreve linha 2 do display
; Esta rotina escreve o conteúdo do buffer
; da linha 2 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha2doDisplay:
; Envia o comando para mudar para o início da linha 2
mov ComandoLCD,#0C0h ; Comando para mudar para o inicio
; da linha 2 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 2 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha2doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha2doDisplay+16,LoopLinha2doDisplay ;
; Testa o fim da linha 2
ret ; Retorna para onde veio
; Fim EscreveLinha2doDisplay
;-------------------------------------------------------------------------------
; Envia byte para o display LCD
; Esta rotina envia um byte de comando ou de dado para o display LCD
;-------------------------------------------------------------------------------
EnviaByteParaDisplayLCD:
mov A,@R0 ; Carrega ACC com a memória de Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Fim EnviaByteParaDisplayLCD
;-------------------------------------------------------------------------------
; Envia nible alto para o display LCD
; Esta rotina é usada apenas na inicialização do display
;-------------------------------------------------------------------------------
EnviaNibleAltoParaDisplayLCD:
; Coloca nible alto no barramento
anl A,#0F0h ; Mascara para não perturbar a parte
; baixa da Porta 2
anl BarramentoDoDisplay,#00Fh ;
; Zera o nibble alto para que a próxima
; instrução funcione corretamente
orl BarramentoDoDisplay,A ; Envia nibble alto para o Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 200 uS
mov R7,#100 ; Carrega para 200 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 200 uS
_______________________________________________
32
02.07. Relógio Calendário Baseado no HT1380:
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
_______________________________________________
33
DSEG at 21h
NumeroDeBits: DS 1
; Os registros a seguir devem estar na seqüência que se segue, pois é a que o
; HT1380 recebe e envia
R_Segundo: DS 1 ; Registro de segundos
R_Minuto: DS 1 ; Registro de minutos
R_Hora: DS 1 ; Registro de horas
R_Dia: DS 1 ; Registro de dias
R_Mes: DS 1 ; Registro de mês
R_DiaDaSemana: DS 1 ; Registro de dia da semana
R_Ano: DS 1 ; Registro de anos
; Fim da sequencia
Tempo250ms: DS 1 ; Registro o tempo de 250 mS
TempoDeMenssagem: DS 1 ; Registro o tempo de apresentação de
; mensagem
Linha: DS 1 ; Registro para a linha do teclado
Coluna: DS 1 ; Registro para a coluna do teclado
DebounceDeTecla: DS 1 ; Registro para o contador de debounce
TeclaAtual: DS 1 ; Registro para salvar a tecla
ComandoLCD: DS 1 ; Registro destinado ao envio de
; comandos para o display LCD
TrataTimer:
mov TH0,#(high TempoDoTimer) ;#0DBh ; 10 mS a 11,059200 MHz
mov TL0,#(low TempoDoTimer) ;#0FFh
push P2
push PSW ; Salva o PSW na pilha
push ACC ; Salva o ACC na pilha
push B ; Salva o B na pilha
;-------------------------------------------------------------------------------
; | | | | |
; | Col 0 | Col 1 | Col 2 | Col 3 |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 0 | 1 | 2 | 3 | A |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 1 | 4 | 5 | 6 | B |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 2 | 7 | 8 | 9 | C |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 3 | * | 0 | # | D |
; ________|_______|_______|_______|_______|________
; | | | | |
; | | | | |
_______________________________________________
34
;-------------------------------------------------------------------------------
Teclado:
jb TeclaValida,DesligaTecla ;
; Se tiver tecla válida, vai esperar
; o fim da tecla
mov DPTR,#ColunaLinha ; Carrega ponteiro com a tabela
; de Coluna/Linha
mov Linha,#0FFh ; Carrega para começar a varrer na Linha
; '0', pois vai incrementar quando for
; varrer o teclado
clr TeclaApertada ; Limpa flag para testar no retorno
VarreTeclado:
inc Linha ; Incrementa contador de Linha
mov A,Linha ; Carrega para converter número da Linha
movc A,@A+DPTR ; Converte número da Linha para fazer
; a varredura
jz DebounceDeTeclado ; Sai se já varreu todas as linhas
VarreLinhas:
swap A ; Para acionar a linha na parte alta da
; porta 2
mov P2,A ; Aciona a saída correspondente a Linha
mov A,P2 ; Lê retorno do teclado
orl A,#0F0h ; Mascara para ignorar a parte alta
cpl A ; Complementa para testar na próxima
; instrução
jz VarreTeclado ; Volta para varrer a próxima linha,
; pois não tinha tecla acionada nesta
; linha
cpl A ; Complementa para voltar ao que era
; antes
mov TeclaAtual,A ; Salva temporariamente a leitura da
; tecla
jb TeclaApertada,SaiTeclado ;
; Sai se já tiver tecla apertada
mov Coluna,#4 ; Carrega contador de colunas com '4'
; porque vai decrementar na rotina
; VarreColunas
VarreColunas:
mov A,Coluna ; Carrega o acumulador com o número da
; coluna
dec A ; Decrementa o acumulador para buscar a
; coluna certa na tabela
movc A,@A+DPTR ; Converte para testar retorno do
; teclado
xrl A,TeclaAtual ; Testa para saber em que coluna esta o
; retorno
jnz VarreColunas1 ; Vai continuar a varredura se não tiver
; tecla apertada na coluna, ou se tiver
; mais de uma tecla apertada
SalvaTecla:
mov A,Linha ; Carrega o acumulador com o número da
; linha
rl A ; Desloca 2 vezes para poder anexar ao
rl A ; número da coluna
dec Coluna ; Para chegar ao número correto da
; coluna e na próxima instrução anexar a
; linha
xrl A,Coluna ; Anexa o número da coluna ao da linha
mov TeclaAtual,A ; Salva valor da tecla em binário
setb TeclaApertada ; Sinaliza que tem apenas uma tecla
; apertada
sjmp VarreTeclado ; Volta para varrer o teclado até o fim
_______________________________________________
35
VarreColunas1:
djnz Coluna,VarreColunas ; Chega a 0 se tiver mais de uma tecla
; apertada na mesma Linha
SaiTeclado:
clr TeclaApertada ; Sinaliza que não tem nenhuma tecla
; apertada
DebounceDeTeclado:
jnb TeclaApertada,DesligaTecla ;
; Se não tiver mais tecla apertada, vai
; fazer o debounce do desligamento
inc DebounceDeTecla ; Incrementa o contador de debounce
mov A,DebounceDeTecla ; Carrega o acumulador para testar na
; próxima instrução
cjne A,#08h,TrataSegundo ; Testa se já passou 80 mS com mesma
; tecla
dec DebounceDeTecla ; Decrementa para não ultrapassar '8'
; no próximo teste
setb TeclaValida ; Sinaliza tecla válida depois de 80 mS
DesligaTecla:
mov P2,#00Fh ; Aciona todas as linhas
mov A,P2 ; Lê retorno do teclado
orl A,#0F0h ; Para garantir que o nibble alto fique
; com 'F'
cpl A ; Complementa para testar na próxima
; instrução
jnz TrataSegundo ; Vai sair da interrupção se o
; acumulador não estiver com '0', pois
; ainda tem tecla apertada
djnz DebounceDeTecla,TrataSegundo ;
; Conta tempo de debounce de desliga
inc DebounceDeTecla ; Para
clr TeclaValida ; Desliga tecla válida depois 80 mS
TrataSegundo:
djnz Tempo250ms,SaiInt
mov Tempo250ms,#25
setb Passou250ms
SaiInt:
pop B ; Recupera B
pop ACC ; Recupera ACC
pop PSW ; Recupera PSW
pop P2
_______________________________________________
36
db 0F7h
db 000h
;-------------------------------------------------------------------------------
ConverteTeclaASCII: ; Rotina para converter o valor binário
; da tecla em ASCII
inc A ; Incrementa para que a instrução 'ret'
; não tenha efeito na tabela
movc A,@A+PC ; O acumulador volta com o caractere
; ASCII correspondente ao valor binário
ret ; Retorna para onde veio
; Vem Volta
; com com
; Hex ASCII
db '1' ; 0 1
db '2' ; 1 2
db '3' ; 2 3
db 'A' ; 3 A
db '4' ; 4 4
db '5' ; 5 5
db '6' ; 6 6
db 'B' ; 7 B
db '7' ; 8 7
db '8' ; 9 8
db '9' ; A 9
db 'C' ; B C
db '*' ; C *
db '0' ; D 0
db '#' ; E #
db 'D' ; F D
;-------------------------------------------------------------------------------
InicializaPlaca:
;-------------------------------------------------------------------------------
; Apaga memoria RAM interna
;-------------------------------------------------------------------------------
mov R0,#0FFh ; Carrega ponteiro com o tamanho
; da memória
ApagaMemoria:
mov @R0,#0 ; Escreve "0" na posição de memória
; apontada por R0
djnz R0,ApagaMemoria ; Decrementa o ponteiro e volta para
; apagar a posição anterior até
; chegar a posição "0"
; Fim apaga memoria
;-------------------------------------------------------------------------------
mov SP,#FimDosDados ; O stack pointer é carregado com o fim
; da memória ocupada para evitar que a
; área de dados seja invadida pela pilha
;-------------------------------------------------------------------------------
; InicializaLCD
;-------------------------------------------------------------------------------
mov P2,#0F0h
InicializaLCD:
call Retardo4mS
call Retardo4mS
call Retardo4mS
call Retardo4mS
clr EnLCD
clr RsLCD ; Coloca o display para receber Comandos
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
call Retardo4mS
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
_______________________________________________
37
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#080h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#060h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#0C0h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#010h
call EnviaNibleAltoParaDisplayLCD
setb RsLCD ; Coloca o display para receber Dados
call Retardo4mS
call ApagaDisplay
; Fim InicializaLCD
;-------------------------------------------------------------------------------
; Inicializa Timer
;-------------------------------------------------------------------------------
InicializaTimer:
mov TH0,#(high TempoDoTimer); Carrega timer 0 com
mov TL0,#(low TempoDoTimer) ; 10 mS a 11,0592 MHz
; Fim InicializaTimer
;-------------------------------------------------------------------------------
AguardaMenssagem:
clr Passou250ms ; Desliga o flag que informa que passou
; 250 mS
jnb Passou250ms,$ ; Espera passar 250 mS
djnz TempoDeMenssagem,AguardaMenssagem ;
; Decrementa 8 vezes para um total
; de 2 segundos (8 x 250 mS)
call ApagaDisplay ; Vai apgar o display
mov DPTR,#MsgHoraInicio
; Carrega o DPTR com o Endereço do
; horário de início do relógio
mov R0,#Linha1doDisplay ; Carrega R0 com endereço de início do
; buffer do display
_______________________________________________
call EscreveMensagem ; Vai escrever o horário de início no
38
; buffer do display
call CarregaHora ; Vai converter o horário que esta no
; buffer do display e enviar para
; o HT1380
Principal:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
jb TeclaValida,TestaAcerta ; Se tiver tecla válida, vai testar se é
; para entrar no modo de acerto
jnb Passou250ms,Principal ; Volta para Principal enquanto não
; passar 250 mS
Principal1:
call Relogio ; Vai ler o relógio HT1380 e escrever
; no display
clr Passou250ms ; Desliga o flag Passou250ms, para
; esperar novamente
sjmp Principal ; Volta para Principal para esperar mais
; 250 mS
TestaAcerta:
mov A,TeclaAtual ; Carrega o acumulador com a tecla atual
cjne A,#'A',Principal1 ; Testa se é 'A', se positivo segue e
; entra na rotina de acerto, caso
; contrario vai para Principal1
;-------------------------------------------------------------------------------
mov R1,#Linha1doDisplay ; Carrega R1 com endereço de início do
; buffer do display
AcertaRelogio:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
jb TeclaValida,AcertaRelogio ;
; Aguarda o fim da tecla
Testa250ms:
mov B,#' ' ; Carrega B com espaço para piscar o
; digito
Testa250ms1:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
jb TeclaValida,TestaTecla ; Se tiver tecla válida, vai testar
; tecla
PiscaDigito:
mov A,B ; Carrega o acumulador com B
xch A,@R1 ; Troca o conteúdo da posição apontada
; por R1 com o acumulador
mov B,A ; Salva em B o que estava na posição
; apontada por R1
jnb Passou250ms,$ ; Espera passar 250 mS
clr Passou250ms ; Desliga o flag Passou250ms, para
; esperar novamente
call EscreveDisplay ; Vai escrever o display
sjmp Testa250ms1 ; Volta para Testa250ms1, e fica neste
; loop, piscando o digito correspondente
; até ter outra tecla válida
TestaTecla:
mov A,TeclaAtual ; Carrega o acumulador com a tecla atual
cjne A,#'D',EscreveDigito ; Testa se é 'D', se positivo segue e
; encerra o acerto
cjne @R1,#' ',TestaTecla1 ; Testa se a posição é igual a espaço,
; se não for pula a próxima instrução
mov @R1,B ; Torna a escrever o valor correto no
; buffer do display antes de converter
; e enviar para o HT1380
TestaTecla1:
call CarregaHora ; Vai converter o horário que esta no
_______________________________________________
; buffer do display e enviar para
39
; o HT1380
sjmp Principal1 ; Volta para Principal1
EscreveDigito:
mov @R1,A ; Carrega a posição do buffer
; correspondente ao digito com o valor
; da tecla atual que esta no acumulador
call EscreveDisplay ; Vai reescrever o display
jb TeclaValida,$ ; Aguarda o fim da tecla
inc R1 ; Incrementa o ponteiro do digito
TestaDoisPontos:
cjne @R1,#':',TestaBarra ; Testa se é um caractere separador para
; pular o separador
inc R1 ; Incrementa o ponteiro para pular o
; separador
sjmp Testa250mS ; Volta para acertar o próximo digito
TestaBarra:
cjne @R1,#'/',TestaPonteiroLinha1 ;
; Testa se é um caractere separador para
; pular o separador
inc R1 ; Incrementa o ponteiro para pular o
; separador
sjmp Testa250mS ; Volta para acertar o próximo digito
TestaPonteiroLinha1:
cjne R1,#Linha1doDisplay+8,TestaPonteiroLinha2 ;
; Testa se já chegou no fim do que esta
; na linha 1
mov R1,#Linha2doDisplay ; Carrega o ponteiro com o início
; da linha 2
sjmp Testa250mS ; Volta para acertar o próximo digito
TestaPonteiroLinha2:
cjne R1,#Linha2doDisplay+8,Testa250mS ;
; Testa se já chegou no fim do que esta
; na linha 2
mov R1,#Linha1doDisplay ; Carrega o ponteiro com o início
; da linha 1
sjmp Testa250mS ; Volta para acertar o próximo digito
;-------------------------------------------------------------------------------
CarregaHora:
mov R0,#Linha1doDisplay ; Carrega R0 com endereço de início do
; buffer do display da linha 1 (Hora)
call ConverteRelogioBCDPack ; Vai converter 'HH' ASCII para BCD Pack
mov R_Hora,A ; Salva horas para depois enviar para o
; HT1380
;-------------------------------------------------------------------------------
ConverteRelogioBCDPack:
mov A,@R0 ; Carrega o acumulador com a dezena
anl A,#00Fh ; Converte a dezena em ASCII para BCD
swap A ; Transfere a dezena BCD para o nible
; alto
mov B,A ; Salva a dezena
inc R0 ; Incrementa para buscar a unidade
mov A,@R0 ; Carrega o acumulador com a unidade
anl A,#00Fh ; Converte a unidade em ASCII para BCD
xrl A,B ; Anexa a unidade a dezena
inc R0 ; Incrementa para pular o separador
; (':' ou '/')
inc R0 ; Incrementa para buscar o próximo
LeRelogio:
call RecebeHT1380 ; Vai receber 1 byte do HT1380
mov @R0,A ; Salva o byte recebido
inc R0 ; Incrementa o ponteiro para salvar o
; próximo byte
djnz R7,LeRelogio ; Volta a receber enquanto não receber
; os 7 bytes
clr REST ; Desabilita comunicação com HT1380
MostraRelogio:
mov R0,#R_Hora
mov R1,#Linha1doDisplay ; Buffer da linha 1 do display
_______________________________________________
41
call EscreveRelogio ; Escreve dezena e unidade de Hora
mov @R1,#':' ; Escreve ":"
inc R1 ; Incrementa para pular o separador
dec R0 ; Decrementa para buscar minutos
call EscreveRelogio ; Escreve dezena e unidade de Minuto
mov @R1,#':' ; Escreve ":"
inc R1 ; Incrementa para pular o separador
dec R0 ; Decrementa para buscar segundos
call EscreveRelogio ; Escreve dezena e unidade de Segundo
mov R0,#R_Dia
mov R1,#Linha2doDisplay ; Buffer da linha 2 do display
;-------------------------------------------------------------------------------
EnviaRelogio:
clr SCLK ; Para garantir que o sinal de clock
; esteja em '0' quando o HT1380 for
; selecionado
setb REST ; Habilita comunicação com HT1380
_______________________________________________
42
EnviaRelogio1: ; Loop para enviar 7 bytes
mov A,@R0 ; Carrega o acumulador com o que vai
; enviar
call EnviaHT1380 ; Vai enviar para o HT1380
inc R0 ; Incrementa o ponteiro para quando for
; buscar o próximo byte a enviar
djnz R7,EnviaRelogio1 ; Fim do loop para enviar 7 bytes
; Fim de EnviaRelogio
;-------------------------------------------------------------------------------
HabilitaHT1380:
clr REST ; Coloca o REST em '0' para garantir a
; transição de '0' para '1' na primeira
; vez que enviar dados para o HT1380
clr SCLK ; Inicializa o sinal de clock com '0'
; Fim de HabilitaHT1380
;-------------------------------------------------------------------------------
EnviaHT1380:
mov NumeroDeBits,#8 ; Carrega para enviar 8 bits
EnviaHT1380_1:
rrc A ; Transfere o bit menos significativo do
; acumulador para o carry
mov IO,C ; Transfere o carry para a linha de IO
; para enviar ao HT1380
setb SCLK ; Início do pulso de clock
clr SCLK ; Fim do pulso de clock
djnz NumeroDeBits,EnviaHT1380_1 ;
; Enquanto não chegar a zero é porque
; ainda tem bits a enviar
setb IO ; Coloca a linha de IO em '1' para
; quando for receber dados do HT1380
; Fim de EnviaHT1380
;-------------------------------------------------------------------------------
RecebeHT1380:
setb IO ; Para garantir que a linha de IO esteja
_______________________________________________
43
; para receber dados do HT1380
mov NumeroDeBits,#8 ; Carrega para receber 8 bits
RecebeHT1380_1:
mov C,IO ; Carrega o carry com o que esta na
; linha de IO
rrc A ; Transfere o carry para o bit mais
; significativo do acumulador
setb SCLK ; Início do pulso de clock
clr SCLK ; Fim do pulso de clock
djnz NumeroDeBits,RecebeHT1380_1 ;
; Enquanto não chegar a zero é porque
; ainda tem bits a receber
; Fim de RecebeHT1380
;-------------------------------------------------------------------------------
; Escreve Mensagem no Display LCD
;-------------------------------------------------------------------------------
EscreveMensagem:
clr A ; Zera o acumulador para que na próxima
; instrução só tenha valor o DPTR
movc A,@A+DPTR ; Busca caractere da mensagem na memória
; de programa
cjne A,#ETX,EscreveMensagem1 ; Testa se chegou ao fim da mensagem
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
EscreveMensagem1:
mov @R0,A ; Escreve no buffer o que
; pegou na mensagem
inc R0 ; Incrementa o ponteiro
; do buffer do Display
inc DPTR ; Incrementa o ponteiro da mensagem
jmp EscreveMensagem ; Volta para escrever o próximo
; caractere no display
; Fim EscreveMensagem
;-------------------------------------------------------------------------------
; Apaga Display
;-------------------------------------------------------------------------------
ApagaDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#32 ; Carrega tamanho do buffer do Display
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaDisplay
;-------------------------------------------------------------------------------
; Apaga Linha 1 do Display
;-------------------------------------------------------------------------------
ApagaLinha1doDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 1
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha1doDisplay ; Vai transferir para a linha 1 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
_______________________________________________
; Fim ApagaLinha1doDisplay
44
;-------------------------------------------------------------------------------
; Apaga linha 2 do Display
;-------------------------------------------------------------------------------
ApagaLinha2doDisplay:
mov R0,#Linha2doDisplay ; Carrega ponteiro com inicio
; da linha 2 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 2
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha2doDisplay ; Vai transferir para a linha 2 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha2doDisplay
;-------------------------------------------------------------------------------
; Limpa buffer do Display LCD
; Escreve espaços (brancos) no buffer do display
;-------------------------------------------------------------------------------
LimpaBufferDisplay:
mov A,#' ' ; Carrega ACC com espaço
CLS1: mov @R0,A ; Escreve espaço na memória de Display
inc R0 ; Incrementa ponteiro da memória
djnz R1,CLS1 ; Testa se já apagou toda memória
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
; Escreve no display
; Escreve todo o conteúdo do buffer do display na memória do mesmo
;-------------------------------------------------------------------------------
EscreveDisplay:
call EscreveLinha1doDisplay ; Vai escrever a Linha 1 do display
call EscreveLinha2doDisplay ; Vai escrever a Linha 2 do display
ret ; Retorna para onde veio
; Fim EscreveDisplay
;-------------------------------------------------------------------------------
; Escreve linha 1 do display
; Esta rotina escreve o conteúdo do buffer
; da linha 1 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha1doDisplay:
; Envia o comando para mudar para o início da linha 1
mov ComandoLCD,#080h ; Comando para mudar para o inicio
; da linha 1 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 1 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha1doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha1doDisplay+16,LoopLinha1doDisplay ;
; Testa o fim da linha 1
ret ; Retorna para onde veio
; Fim EscreveLinha1doDisplay
;-------------------------------------------------------------------------------
; Escreve linha 2 do display
; Esta rotina escreve o conteúdo do buffer
_______________________________________________
45
; da linha 2 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha2doDisplay:
; Envia o comando para mudar para o início da linha 2
mov ComandoLCD,#0C0h ; Comando para mudar para o inicio
; da linha 2 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 2 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha2doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha2doDisplay+16,LoopLinha2doDisplay ;
; Testa o fim da linha 2
ret ; Retorna para onde veio
; Fim EscreveLinha2doDisplay
;-------------------------------------------------------------------------------
; Envia byte para o display LCD
; Esta rotina envia um byte de comando ou de dado para o display LCD
;-------------------------------------------------------------------------------
EnviaByteParaDisplayLCD:
mov A,@R0 ; Carrega ACC com a memória de Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
_______________________________________________
46
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Fim EnviaByteParaDisplayLCD
;-------------------------------------------------------------------------------
; Envia nible alto para o display LCD
; Esta rotina é usada apenas na inicialização do display
;-------------------------------------------------------------------------------
EnviaNibleAltoParaDisplayLCD:
; Coloca nible alto no barramento
anl A,#0F0h ; Mascara para não perturbar a parte
; baixa da Porta 2
anl BarramentoDoDisplay,#00Fh ;
; Zera o nibble alto para que a próxima
; instrução funcione corretamente
orl BarramentoDoDisplay,A ; Envia nibble alto para o Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 200 uS
mov R7,#100 ; Carrega para 200 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 200 uS
; Fim EnviaNibleAltoParaDisplayLCD
;-------------------------------------------------------------------------------
Retardo4mS:
mov R3,#8 ; Carrega R3 para um retardo de 4 mS,
; com um cristal de 11,0592 MHz
mov R4,#39
Retardo4mS1: ; Fica neste loop até que os 2 registros
; cheguem a '0', quando então terá
; transcorrido 4 mS ou 100 mS,
; dependendo do valor de R3
djnz R4,Retardo4mS1
djnz R3,Retardo4mS1
ret ; Retorna para onde veio
; Fim Retardo4mS
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do codigo
_______________________________________________
47
02.08. Relógio Com Alarme:
R1 R2
4K7 4K7
C1
220nF,100V
P1.0
LS1
P1.1
Buzzer Piezoeletrico
Figura 13.01
_______________________________________________
48
TempoDoTimer2 EQU 65535-9216 ; Tempo para 10 mS
DSEG at 40h
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
SaiTimer2:
call EscreveLinha1doDisplay ; Vai escrever o buffer do display na
; linha 1 do mesmo
pop PSW
pop B
pop ACC
reti ; Saída da interrupção do timer 2
;-------------------------------------------------------------------------------
InicializaPlaca:
InicializaLCD:
call Retardo4mS
call Retardo4mS
_______________________________________________
50
call Retardo4mS
call Retardo4mS
clr EnLCD
clr RsLCD ; Coloca o display para receber Comandos
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
call Retardo4mS
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#080h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#060h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#0C0h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#010h
call EnviaNibleAltoParaDisplayLCD
setb RsLCD ; Coloca o display para receber Dados
call Retardo4mS
call ApagaDisplay
;-------------------------------------------------------------------------------
; Inicializa timer
;-------------------------------------------------------------------------------
setb TR2 ; Habilita timer 2
setb PT2 ; Timer 2 com prioridade alta
setb ET2 ; Habilita interrupção do timer 2
setb EA ; Habilita o controlador de interrupt
clr CAP2 ; Coloca o timer 2 para recarregar
; automaticamente
Principal:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
Principal1:
jb Alarme,AjustaAlarme ; Se estiver no modo de ajustar alarme,
; vai para AjustaAlarme
jnb Acerta,Principal ; Se não estiver no modo de acerta hora
; volta a aguardar na Principal
;-------------------------------------------------------------------------------
; Rotina de acertar o relógio
;-------------------------------------------------------------------------------
AcertaRelogio:
mov Segundos,#0 ; Carrega o contador de segundos
; com '0'
jb IncrementaHora,AcertaHora ;
; Vai incrementar as horas se o flag
; IncrementaHora estiver ligado
jnb IncrementaMinuto,Principal ;
; Volta para Principal se o flag
; IncrementaMinuto estiver desligado,
; caso contrario vai incrementar minutos
AcertaMinuto:
inc Minutos ; Incrementa o contador de minutos
mov A,Minutos ; Carrega o acumulador com minutos
cjne A,#60,AtualizaRelogio ; Testa se minutos esta igual a '60', se
; estiver igual, zera minutos na
; instrução a seguir
mov Minutos,#0 ; Carrega o contador de minutos
; com '0'
jmp AtualizaRelogio
AcertaHora:
inc Horas ; Incrementa o contador de horas
mov A,Horas ; Carrega o acumulador com horas
cjne A,#24,AtualizaRelogio
; Testa se horas esta igual a '24', se
; estiver igual, zera horas na
_______________________________________________
; instrução a seguir
52
mov Horas,#0 ; Carrega o contador de horas
; com '0'
AtualizaRelogio:
call EscreveRelogioNoLCD ; Vai escrever relógio no buffer do
; display
jmp IncrementaRapido ; Vai testar se é para incrementar
; rápido
;-------------------------------------------------------------------------------
; Rotina de ajustar o alarme
;-------------------------------------------------------------------------------
AjustaAlarme:
jb IncrementaHora,AjustaHoraAlarme ;
; Vai incrementar horas do alarme se o
; flag IncrementaHora estiver ligado
jnb IncrementaMinuto,Principal ;
; Volta para a Principal se o flag
; IncrementaMinuto estiver desligado,
; caso contrario vai incrementar minutos
; do alarme
AjustaMinutoAlarme:
inc AlarmeMinutos ; Incrementa o registro dos minutos do
; alarme
mov A,AlarmeMinutos ; Carrega o acumulador com minutos do
; alarme
cjne A,#60,AtualizaAlarme ; Testa se minutos do alarme esta igual
; a '60', se estiver igual, zera minutos
; do alarme na instrução a seguir
mov AlarmeMinutos,#0 ; Carrega o registro de minutos do
; alarme com '0'
jmp AtualizaAlarme ; Vai atualizar display do alarme
AjustaHoraAlarme:
inc AlarmeHoras ; Incrementa o registro das horas do
; alarme
mov A,AlarmeHoras ; Carrega o acumulador com horas do
; alarme
cjne A,#24,AtualizaAlarme ; Testa se horas do alarme esta igual
; a '24', se estiver igual, zera horas
; do alarme na instrução a seguir
mov AlarmeHoras,#0 ; Carrega o registro de horas do alarme
; com '0'
AtualizaAlarme:
call EscreveAlarmeNoLCD ; Escreve horas e minutos do alarme no
; buffer do display LCD
;-------------------------------------------------------------------------------
IncrementaRapido:
call Retardo100mS ; Espera 100 mS
IncrementaRapido1:
jnb TeclaValida,Principal ; Se não tiver tecla válida volta para
; Principal
jnb Passou300mS,IncrementaRapido1 ;
; Volta a testar tecla válida se não
; tiver passado 300 mS
jb Acerta,AcertaRelogio ; Se tiver passado 300 mS e o flag
; Acerta ligado vai incrementar horas ou
; minutos de modo rápido
jb Alarme,AjustaAlarme ; Se tiver passado 300 mS e o flag
; Alarme ligado vai incrementar horas ou
; minutos do alarme de modo rápido
jmp Principal ; Volta para Principal se não estiver
; no modo acerta relógio ou ajusta
; alarme
_______________________________________________
53
;-------------------------------------------------------------------------------
TrataTecla:
jb TeclaValida,AguardaFimDeTecla ;
; Vai aguardar finalização de qualquer
; tecla
jb TocaAlarme,TestaQualquerTecla ;
; Se o alarme estiver tocando, vai
; aceitar qualquer tecla para desligar
; o alarme
jb TeclaAcerta,TestaTeclaAlarme ;
; Vai testar tecla Alarme somente se a
; tecla parte/para não estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer o
; tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
jb Alarme,LigaDesligaAlarme ;
; Se estiver no modo ajusta alarme, a
; tecla acerta serve para ligar ou
; desligar o alarme
cpl Acerta ; Entra ou sai do modo acerta relógio
jnb Acerta,SaiTrataTecla ; Se o flag acerta estiver em '0' é
; porque saiu do modo acerta relógio
LigaDesligaAlarme:
cpl AlarmeLigado ; Liga ou desliga o alarme
mov Linha1doDisplay+9,#'*' ; Coloca '*' na coluna 10 da linha 1 do
; buffer do display
jb AlarmeLigado,SaiTrataTecla ;
; Sai da rotina de tratar teclas se o
; flag AlarmeLigado estiver ligado
mov Linha1doDisplay+9,#' ' ; Coloca espaço na coluna 10 da linha 1
; do buffer do display
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
TestaTeclaAlarme:
jb Acerta,TestaTeclaIncrementaHora
jb TeclaAlarme,TestaTeclaIncrementaHora
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
cpl Alarme ; Se ligado, sinaliza que é para ajustar
; horário do alarme
jnb Alarme,SaiTrataTecla ; Se desligado sai da rotina de tratar
; teclas
call EscreveAlarmeNoLCD ; Vai escrever horário do alarme no
; buffer do display
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
TestaTeclaIncrementaHora:
jb TeclaIncrementaHora,TestaTeclaIncrementaMinuto
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
setb IncrementaHora ; Sinaliza que é para incrementar hora
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
_______________________________________________
54
TestaTeclaIncrementaMinuto:
jb TeclaIncrementaMinuto,SaiTrataTecla
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
setb IncrementaMinuto ; Sinaliza que é para incrementar minuto
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
TestaQualquerTecla:
mov A,P2 ; Lê a porta 2 para testar
orl A,#11110000b ; Coloca "1" nos bits não usados
cpl A ; Complementa o acumulador para testar
; se o mesmo chegou aqui com '0FFh'
jz SaiTrataTecla ; Sai da rotina se não tiver nenhuma
; tecla apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
clr TocaAlarme ; Desliga o flag TocaAlarme para parar
; de tocar o alarme
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
AguardaFimDeTecla:
mov A,P2 ; Le a porta 2 para testar se ainda tem
; tecla apertada
orl A,#11110000b ; Coloca "1" nos bits não usados
cpl A ; Inverte o conteúdo do acumulador
jnz AguardaFimDeTecla1 ; Sai se o acumulador não estiver com
; '0', sinal de que ainda tem tecla
; apertada
mov Debounce,#10 ; Recarrega o contador de debounce com
; 100 mS
clr TeclaValida ; Sinaliza que não tem nenhuma tecla
; apertada
clr IncrementaHora ; Desliga flag que sinaliza que é para
; incrementar o contador de horas
clr IncrementaMinuto ; Desliga flag que sinaliza que é para
; incrementar o contador de minutos
clr Passou300mS ; Desliga flag que sinaliza que já
; passou mais de 300 mS com uma mesma
; tecla apertada
mov Tempo300mS,#30 ; Recarrega o contador de tempo
; de 300 mS
AguardaFimDeTecla1:
djnz Tempo300mS,SaiTrataTecla ;
; Decrementa o contador de tempo de
; 300 mS, e sai se ainda não tiver
; passado os 300 mS
setb Passou300mS ; Sinaliza que já passou os 300 mS
SaiTrataTecla:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
Relogio:
inc Segundos ; Incrementa contador de segundos
mov A,Segundos ; Carrega acumulador com o contador
; de segundos
cjne A,#60,SaiRelogio ; Testa se já chegou a 60, se não chegou
; sai da rotina de relógio
mov Segundos,#0 ; Carrega o contador de segundos com '0'
ContaMinutos:
inc Minutos ; Incrementa contador de minutos
mov A,Minutos ; Carrega acumulador com o contador
; de minutos
_______________________________________________
55
cjne A,#60,SaiRelogio ; Testa se já chegou a 60, se não chegou
; sai da rotina de relógio
mov Minutos,#0 ; Carrega o contador de minutos com '0'
ContaHoras:
inc Horas ; Incrementa contador de horas
mov A,Horas ; Carrega acumulador com o contador
; de horas
cjne A,#24,SaiRelogio ; Testa se já chegou a 24, se não chegou
; sai da rotina de relógio
mov Horas,#0 ; Carrega o contador de horas com '0'
SaiRelogio:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
EscreveRelogioNoLCD:
mov A,Horas ; Carrega o acumulador com Horas
mov B,#10 ; Carrega o registrador 'B' com 10
div AB ; Divide 'A' por 'B', então 'A' sai com
; a dezena de horas e 'B' com a unidade
_______________________________________________
56
;-------------------------------------------------------------------------------
EscreveAlarmeNoLCD:
mov A,AlarmeHoras ; Carrega o acumulador com AlarmeHoras
mov B,#10 ; Carrega o registrador 'B' com 10
div AB ; Divide 'A' por 'B', então 'A' sai com
; a dezena de horas e 'B' com a unidade
;-------------------------------------------------------------------------------
ComparaHora:
mov A,Horas ; Carrega acumulador com a hora atual
cjne A,AlarmeHoras,SaiComparaHora ;
; Compara a hora atual com a hora de
; alarme, se diferente sai da comparação
mov A,Minutos ; Carrega acumulador com o minuto atual
cjne A,AlarmeMinutos,SaiComparaHora ;
; Compara o minuto atual com o minuto de
; alarme, se diferente sai da comparação
mov A,Segundos ; Carrega acumulador com o segundo atual
jnz SaiComparaHora ; Se o segundo atual não for '00' sai
; para não voltar a tocar o alarme, caso
; o mesmo tenha sido desligado dentro do
; mesmo minuto
setb TocaAlarme ; Liga o flag que sinaliza que é para
; tocar o alarme
SaiComparaHora:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
Buzina:
setb Buzina0 ; Liga saída '0' da buzina
clr Buzina1 ; Desliga saída '1' da buzina
mov R7,#54 ; Para um retardo aproximado de 125 uS
djnz R7,$ ; Quando R7 chegar a '0' é porque passou
; os 125 uS
_______________________________________________
57
setb Buzina1 ; Liga saída '1' da buzina
clr Buzina0 ; Desiga saída '0' da buzina
mov R7,#54 ; Para um retardo aproximado de 125 uS
djnz R7,$ ; Quando R7 chegar a '0' é porque passou
; os 125 uS
jb TocaAlarme,Buzina
clr Buzina0 ; Desliga saída '0' da buzina
clr Buzina1 ; Desliga saída '1' da buzina
;-------------------------------------------------------------------------------
; Escreve Mensagem no Display LCD
;-------------------------------------------------------------------------------
EscreveMensagem:
clr A ; Zera o acumulador para que na próxima
; instrução só tenha valor o DPTR
movc A,@A+DPTR ; Busca caractere da mensagem na memória
; de programa
cjne A,#ETX,EscreveMensagem1 ; Testa se chegou ao fim da mensagem
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
EscreveMensagem1:
mov @R0,A ; Escreve no buffer o que
; pegou na mensagem
inc R0 ; Incrementa o ponteiro
; do buffer do Display
inc DPTR ; Incrementa o ponteiro da mensagem
jmp EscreveMensagem ; Volta para escrever o próximo
; caractere no display
; Fim EscreveMensagem
;-------------------------------------------------------------------------------
; Apaga Display
;-------------------------------------------------------------------------------
ApagaDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#32 ; Carrega tamanho do buffer do Display
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaDisplay
;-------------------------------------------------------------------------------
; Apaga Linha 1 do Display
;-------------------------------------------------------------------------------
ApagaLinha1doDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 1
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha1doDisplay ; Vai transferir para a linha 1 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha1doDisplay
;-------------------------------------------------------------------------------
; Apaga linha 2 do Display
;-------------------------------------------------------------------------------
ApagaLinha2doDisplay:
_______________________________________________
mov R0,#Linha2doDisplay ; Carrega ponteiro com inicio
58
; da linha 2 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 2
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha2doDisplay ; Vai transferir para a linha 2 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha2doDisplay
;-------------------------------------------------------------------------------
; Limpa buffer do Display LCD
; Escreve espaços (brancos) no buffer do display
;-------------------------------------------------------------------------------
LimpaBufferDisplay:
mov A,#' ' ; Carrega ACC com espaço
CLS1: mov @R0,A ; Escreve espaço na memória de Display
inc R0 ; Incrementa ponteiro da memória
djnz R1,CLS1 ; Testa se já apagou toda memória
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
; Escreve no display
; Escreve todo o conteúdo do buffer do display na memória do mesmo
;-------------------------------------------------------------------------------
EscreveDisplay:
call EscreveLinha1doDisplay ; Vai escrever a Linha 1 do display
call EscreveLinha2doDisplay ; Vai escrever a Linha 2 do display
ret ; Retorna para onde veio
; Fim EscreveDisplay
;-------------------------------------------------------------------------------
; Escreve linha 1 do display
; Esta rotina escreve o conteudo do buffer
; da linha 1 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha1doDisplay:
; Envia o comando para mudar para o início da linha 1
mov ComandoLCD,#080h ; Comando para mudar para o inicio
; da linha 1 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 1 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha1doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha1doDisplay+16,LoopLinha1doDisplay ;
; Testa o fim da linha 1
ret ; Retorna para onde veio
; Fim EscreveLinha1doDisplay
;-------------------------------------------------------------------------------
; Escreve linha 2 do display
; Esta rotina escreve o conteúdo do buffer
; da linha 2 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha2doDisplay:
; Envia o comando para mudar para o início da linha 2
_______________________________________________
mov ComandoLCD,#0C0h ; Comando para mudar para o inicio
59
; da linha 2 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 2 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha2doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha2doDisplay+16,LoopLinha2doDisplay ;
; Testa o fim da linha 2
ret ; Retorna para onde veio
; Fim EscreveLinha2doDisplay
;-------------------------------------------------------------------------------
; Envia byte para o display LCD
; Esta rotina envia um byte de comando ou de dado para o display LCD
;-------------------------------------------------------------------------------
EnviaByteParaDisplayLCD:
mov A,@R0 ; Carrega ACC com a memória de Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Fim EnviaByteParaDisplayLCD
;-------------------------------------------------------------------------------
; Envia nibble alto para o display LCD
; Esta rotina é usada apenas na inicialização do display
;-------------------------------------------------------------------------------
EnviaNibleAltoParaDisplayLCD:
; Coloca nible alto no barramento
anl A,#0F0h ; Mascara para não perturbar a parte
; baixa da Porta 2
anl BarramentoDoDisplay,#00Fh ;
; Zera o nibble alto para que a próxima
; instrução funcione corretamente
orl BarramentoDoDisplay,A ; Envia nibble alto para o Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 200 uS
mov R7,#100 ; Carrega para 200 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 200 uS
; Fim EnviaNibleAltoParaDisplayLCD
;-------------------------------------------------------------------------------
Retardo100mS:
mov R3,#181 ; Carrega R3 para um retardo de 100 mS,
; com um cristal de 11,0592 MHz
sjmp Retardo4mS1
;-------------------------------------------------------------------------------
Retardo4mS:
mov R3,#8 ; Carrega R3 para um retardo de 4 mS,
; com um cristal de 11,0592 MHz
Retardo4mS1:
mov R4,#39
Retardo4mS2: ; Fica neste loop até que os 2 registros
; cheguem a '0', quando então terá
; transcorrido 4 mS ou 100 mS,
; dependendo do valor de R3
djnz R4,Retardo4mS2
djnz R3,Retardo4mS2
ret ; Retorna para onde veio
_______________________________________________
61
02.09. Relógio no Display de Sete Segmentos:
;-------------------------------------------------------------------------------
$MOD89S52
$TITLE (Relogio com Display de LED de 7 segmentos)
;-------------------------------------------------------------------------------
;
; Esta rotina demonstra uma das formas de implementar um relógio
; através de software com display de LED de 7 segmentos
;
; O teclado deve ser configurado para 16 teclas, pois temos que controlar
; o mesmo para evitar conflito com a rotina de multiplexar display que
; usa todos os bits do Barramento de dados
;
; Função das teclas:
; Tecla 1 - Incrementa Hora
; Tecla 2 - Incrementa Minuto
; Tecla A - Entra e sai do modo de ajustar relógio
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
DSEG at 22h
BufferDoDisplay: DS 16
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
TrataTimer2:
clr TF2 ; No caso do timer 2 o flag TF2 tem que
; ser zerado pelo software para que não
; aconteça uma nova interupção logo que
; sair desta interupção
TrataTimer21:
jb Traco,SaiTimer2 ; Se o flag Traco estiver ligado, sai
; da interrupção e não incrementa
; o relógio
;-------------------------------------------------------------------------------
InicializaPlaca:
;-------------------------------------------------------------------------------
; Apaga memoria RAM interna
;-------------------------------------------------------------------------------
mov R0,#0FFh ; Carrega ponteiro com o tamanho
; da memória
ApagaMemoria:
mov @R0,#0 ; Escreve "0" na posição de memória
; apontada por R0
djnz R0,ApagaMemoria ; Decrementa o ponteiro e volta para
; apagar a posição anterior até
; chegar a posição "0"
; Fim apaga memoria
;-------------------------------------------------------------------------------
Principal:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
Principal1:
jnb Acerta,Principal ; Se não estiver no modo de acerto
; volta a aguardar na Principal
;-------------------------------------------------------------------------------
AcertaRelogio:
jb IncrementaHora,AcertaHora ;
; Se o flag IncrementaHora estiver
; ligado vai incrementar o contador de
; horas
jnb IncrementaMinuto,Principal ;
; Se chegar aqui e o flag
; IncrementaMinuto estiver ligado, vai
; incrementar o contador de minutos,
; caso contrário volta a esperar na
; Principal
AcertaMinuto:
inc Minutos ; Incrementa o contador de minutos
mov A,Minutos ; Carrega o acumulador com o contador
; de minutos
cjne A,#60,AtualizaDisplay ; Teste se o contador de minutos chegou
; a '60', se não vai atualizar o display
mov Minutos,#0 ; Zera o contador de minutos
jmp AtualizaDisplay ; Vai atualizar o display
AcertaHora:
inc Horas ; Incrementa o contador de horas
mov A,Horas ; Carrega o acumulador com o contador
; de horas
cjne A,#24,AtualizaDisplay ; Teste se o contador de horas chegou
; a '24', se não chegou
mov Horas,#0 ; Zera o contador de horas e atualiza
; o display
AtualizaDisplay:
call EscreveRelogio ; Vai escrever Horas e Minutos no buffer
; do display
call Retardo100mS ; Aguarda 100 mS para fazer novo
; incremento de hora ou minuto se tiver
; com a tecla Incrementa hora ou minuto
; apertada por mais de 300 mS
AtualizaDisplay1:
jnb TeclaValida,Principal ; Volta para Principal enquanto não
; tiver uma tecla válida
jnb Passou300mS,AtualizaDisplay1 ;
; Testa se já passou 300 mS com uma
; tecla válida
_______________________________________________
65
jb Acerta,AcertaRelogio ; Se ainda estiver no modo de acertar
; relógio, volta para a rotina
; AcertaRelogio
sjmp Principal ; Volta para a Principal, se a rotina de
; tratar teclas informar que já saiu do
; modo acerta
;-------------------------------------------------------------------------------
TrataTecla:
setb HabilitaTeclado ; Habilita leitura do teclado
mov P2,#11101111b ; Habilita linha 1 do teclado (1,2,3,A)
jb TeclaValida,AguardaFimDeTecla ;
; Vai aguardar finalização de qualquer
; tecla
jb TeclaAcerta,TestaTeclaIncrementaHora ;
; Vai testar tecla Incrementa hora,
; se a tecla Acerta não estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla apertada
cpl Acerta ; Entra ou sai do modo acerta relógio
jnb Acerta,SaiTrataTecla ; Se o flag acerta estiver em '0' é
; porque saiu do modo acerta relógio
TestaTeclaIncrementaHora:
jnb Acerta,SaiTrataTecla ; Sai da rotina de tratar teclas se não
; estiver no modo de acerta relógio
jb TeclaIncrementaHora,TestaTeclaIncrementaMinuto ;
; Vai testar a tecla Incrementa minuto,
; se a tecla Incrementa hora não
; estiver apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla
; apertada
setb IncrementaHora ; Sinaliza para rotina de acerta relógio
; que é para incrementar o contador
; de horas
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
TestaTeclaIncrementaMinuto:
jb TeclaIncrementaMinuto,SaiTrataTecla ;
; Sai da rotina de tratar teclas se não
; tiver nenhuma tecla apertada
djnz Debounce,SaiTrataTecla ; Sai da rotina enquanto não vencer
; o tempo de Debounce
setb TeclaValida ; Sinaliza que tem tecla
; apertada
setb IncrementaMinuto ; Sinaliza para rotina de acerta relógio
; que é para incrementar o contador
; de minutos
sjmp SaiTrataTecla ; Sai da rotina de tratar teclas
AguardaFimDeTecla:
mov A,P2 ; Lê a porta 2 para testar se ainda tem
; tecla apertada
orl A,#11110010b ; Coloca "1" nos bits não usados
cpl A ; Inverte o conteúdo do acumulador
_______________________________________________
66
jnz AguardaFimDeTecla1 ; Sai se o acumulador não estiver com
; "0", é sinal de que ainda tem tecla
; apertada
mov Debounce,#10 ; Recarrega o contador de debounce
; com 100 mS
clr TeclaValida ; Sinaliza que não tem nenhuma tecla
; apertada
clr IncrementaHora ; Desliga flag que sinaliza que é para
; incrementar o contador de horas
clr IncrementaMinuto ; Desliga flag que sinaliza que é para
; incrementar o contador de minutos
clr Passou300mS ; Desliga flag que sinaliza que já
; passou mais de 300 mS com uma mesma
; tecla apertada
mov Tempo300mS,#30 ; Recarrega o contador de tempo
; de 300 mS
AguardaFimDeTecla1:
djnz Tempo300mS,SaiTrataTecla ;
; Decrementa o contador de tempo de
; 300 mS, e sai se ainda não tiver
; passado os 300 mS
setb Passou300mS ; Sinaliza que já passou os 300 mS
SaiTrataTecla:
clr HabilitaTeclado ; Desabilita leitura do teclado
;-------------------------------------------------------------------------------
Relogio:
inc Segundos ; Incrementa contador de segundos
mov A,Segundos ; Carrega acumulador com o contador
; de segundos
cjne A,#60,SaiRelogio ; Testa se já chegou a 60, se não chegou
; sai da rotina de relógio
mov Segundos,#0 ; Carrega o contador de segundos com '0'
ContaMinutos:
inc Minutos ; Incrementa contador de minutos
mov A,Minutos ; Carrega acumulador com o contador
; de minutos
cjne A,#60,SaiRelogio ; Testa se já chegou a 60, se não chegou
; sai da rotina de relógio
mov Minutos,#0 ; Carrega o contador de minutos com '0'
ContaHoras:
inc Horas ; Incrementa contador de horas
mov A,Horas ; Carrega acumulador com o contador
; de horas
cjne A,#24,SaiRelogio ; Testa se já chegou a 24, se não chegou
; sai da rotina de relógio
mov Horas,#0 ; Carrega o contador de horas com '0'
SaiRelogio:
ret ; Retorna para onde veio
;-------------------------------------------------------------------------------
EscreveRelogio:
mov A,Horas ; Carrega acumulador com byte Horas
mov B,#10 ; Carrega registrador 'B' com 10 para
; executar a próxima instrução
div AB ; Divide o acumulador p/ 10 para separar
; dezena de horas de unidade de horas
_______________________________________________
67
mov BufferDoDisplay+1,A ; Transfere dezena de horas para o
; buffer do display
mov BufferDoDisplay+2,B ; Transfere unidade de horas para
; o buffer do display
;-------------------------------------------------------------------------------
MultiplexaDisplay:
mov BarramentoDoDisplay,#0 ; Coloca dado no barramento para apagar
; o display que estiver aceso, para
; evitar fantasma
clr Clk7Seg ; Baixa o sinal de clock, para permitir
; a transferência do dado na subida
setb Clk7Seg ; Transfere dado do barramento para
; latch (74HC374) do display
mov BarramentoDoDisplay,#0FFh ;
; Libera o barramento para que outras
; rotinas possam usar o mesmo
;-------------------------------------------------------------------------------
Retardo100mS:
mov R3,#181 ; Carrega R3 para um retardo de 100 mS,
; com um cristal de 11,0592 MHz
mov R4,#39
Retardo4mS1: ; Fica neste loop até que os 2 registros
; cheguem a '0', quando então terá
; transcorrido 4 mS ou 100 mS,
; dependendo do valor de R3
djnz R4,Retardo4mS1
djnz R3,Retardo4mS1
ret ; Retorna para onde veio
; Fim Retardo100mS
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do código
_______________________________________________
69
02.10. Exemplo de Uso do Conversor AD:
;-------------------------------------------------------------------------------
$MOD89S52
$TITLE (Rotina para conversor AD MCP3004/8 ou MCP3204/8 da Microchip)
;-------------------------------------------------------------------------------
;
; Esta rotina serve para demonstrar o funcionamento dos conversores
; AD tipo MCP3004/8 ou MCP3204/8 da Microchip, sendo que o resultado da
; conversão é apresentado no formato hexadecimal, correspondente ao número
; de degraus do sinal convertido, este valor depende da tensão de
; referência e do tipo do conversor AD (10 ou 12 bits)
;
; Neste programa tem 8 entradas para a leitura do conversor AD denominadas
; LeConversorAD0 a LeConversorAD7, neste exemplo usamos LeConversorAD5, e
; ligamos o cursor de um potenciometro na entrada 5 do AD e os estremos do
; potenciometro é ligado ao GND e ao VCC.
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; Segmento de Bits
;
; Segmento da memória RAM, onde se pode trabalhar com um único bit, que são
; usados como sinalizadores (Flags).
; Este segmento começa na posição 020h e vai até 02Fh, totalizando 16 bytes,
; o que permite que o usuário tenha até 128 Flags no seu programa
;-------------------------------------------------------------------------------
BSEG at 0
_______________________________________________
70
Passou1Segundo: dbit 1 ; Para sinalizar que passou 1 segundo
PassouSegundos: dbit 1 ; Para sinalizar que passou segundos
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
DSEG at 23h
TrataTimer0:
mov TH0,#0DBh ; Recarrega timer 0 com
mov TL0,#0FFh ; 10 mS a 11,0592 MHz
TrataSegundo:
djnz Tempo1Segundo,SaiInt ; Sai enquanto Tempo1Segundo não chegar
; a '0'
mov Tempo1Segundo,#100 ; Recarrega contador para contar mais
; 1 segundo
setb Passou1Segundo ; Sinaliza que já passou 1 segundo
djnz Segundos,SaiInt ; Sai enquanto Segundos não chegar a '0'
setb PassouSegundos ; Sinaliza que já passou segundos
SaiInt:
reti ; Saída da interrupção do timer 0
; Fim TrataTimer0
;-------------------------------------------------------------------------------
InicializaPlaca:
;-------------------------------------------------------------------------------
; Apaga memoria RAM interna
;-------------------------------------------------------------------------------
mov R0,#0FFh ; Carrega ponteiro com o tamanho
; da memória
ApagaMemoria:
mov @R0,#0 ; Escreve "0" na posição de memória
; apontada por R0
djnz R0,ApagaMemoria ; Decrementa o ponteiro e volta para
_______________________________________________
71
; apagar a posição anterior até
; chegar a posição "0"
; Fim apaga memoria
;-------------------------------------------------------------------------------
; InicializaLCD
;-------------------------------------------------------------------------------
InicializaLCD:
call Retardo4mS ; Espera 16 mS
call Retardo4mS
call Retardo4mS
call Retardo4mS
clr EnLCD
clr RsLCD ; Coloca o display para receber Comandos
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
call Retardo4mS
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#030h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#020h
call EnviaNibleAltoParaDisplayLCD
mov A,#080h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#060h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#0C0h
call EnviaNibleAltoParaDisplayLCD
mov A,#000h
call EnviaNibleAltoParaDisplayLCD
mov A,#010h
call EnviaNibleAltoParaDisplayLCD
setb RsLCD ; Coloca o display para receber Dados
call Retardo4mS
call ApagaDisplay
; Fim InicializaLCD
;-------------------------------------------------------------------------------
; Inicializa Timer
;-------------------------------------------------------------------------------
InicializaTimer:
mov TH0,#0DBh ; Carrega timer 0 com
mov TL0,#0FFh ; 10 mS a 11,0592 MHz
mov TMOD,#011h ; Programa timer 0 e 1 para o modo 1
; 16 bits
setb ET0 ; Habilita interrupção do timer 0
setb EA ; Habilita interrupts
setb TR0 ; Habilita timer 0
; Fim InicializaTimer
;-------------------------------------------------------------------------------
MenssagemInicial:
mov DPTR,#MsgMMDB ; Carrega DPTR com endereço da mensagem
mov R0,#Linha1doDisplay ; Carrega R0 com endereço de início do
; buffer do display
call EscreveMensagem ; Vai escrever a mensagem
_______________________________________________
72
mov Tempo1Segundo,#100 ; Carrega o contador de tempo de 1 S
mov Segundos,#2 ; Carrega com 2 para esperar 2 segundos
clr PassouSegundos ; Desliga flag que sinaliza que já
; passou a quantidade de segundos
; carregada anteriormente
jnb PassouSegundos,$ ; Espera passar os 2 segundos exibindo
; a mensagem inicial
; Fim MenssagemInicial
;-------------------------------------------------------------------------------
call ApagaLinha2doDisplay ; Vai apagar a linha 2 para mostrar
; a leitura do conversor AD nesta linha
TrataConversor:
mov PCON,#1 ; A CPU se desativa, e só volta a se
; ativar quando ocorrer uma interrupção
call LeConversorAD5 ; Lê a entrada 5 do conversor AD
; Fim TrataConversor
;-------------------------------------------------------------------------------
; Le os canais 0 a 7 do conversor AD
;-------------------------------------------------------------------------------
LeConversorAD0:
mov A,#11000111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD1:
mov A,#11001111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD2:
mov A,#11010111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD3:
mov A,#11011111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD4:
mov A,#11100111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD5:
mov A,#11101111b
; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
_______________________________________________
; conversor AD correspondente ao
73
; endereço contido no byte de comando
LeConversorAD6:
mov A,#11110111b ; Carrega o acumulador com Comando do AD
sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeConversorAD7:
mov A,#11111111b ; Carrega o acumulador com Comando do AD
; sjmp LeAD ; Vai executar a leitura da entrada do
; conversor AD correspondente ao
; endereço contido no byte de comando
LeAD:
mov NumeroDeBits,#6 ; 1 (bit 7) Start
; 1 (bit 6) Modo
; 3 (bits 5,4 e 3) Endereço
; 1 (bit 2) Vago para o tempo de
; amostragem do sinal de entrada do AD
EnviaComandoParaAD:
clr CLK ; Inicializa o pulso de deslocamento
; de dados
rlc A ; Transfere para o carry o bit 7
; do acumulador
mov Din,C ; Coloca na entrada do AD o bit
; contido no carry
setb CLK ; Transfere para o AD o sinal que
; esta em Din do AD e finaliza
; o pulso de deslocamento
djnz NumeroDeBits,EnviaComandoParaAD ;
; Volta para EnviaComandoParaAD,
; até enviar todos os bits previstos
setb Din ; Coloca e entrada de em '1'
RecebeADH:
clr CLK ; Disponibiliza 1 bit de dado na saída
; do AD e inicializa o pulso
; de deslocamento
mov C,Dout ; Coloca no carry o sinal de saída do AD
rlc A ; Transfere para o bit 0 do acumulador
; o carry
setb CLK ; Desloca dados no interior do AD
; e finaliza o pulso de deslocamento
djnz NumeroDeBits,RecebeADH ; Volta para RecebeADH, até receber
; todos os bits previstos
mov ByteADH,A ; Transfere para ByteADH o que
; recebeu no acumulador
anl ByteADH,#00001111b ; Zera bits não usados do byte ADH
; 00000011b para MCP3008
; 00001111b para MCP3208
_______________________________________________
74
rlc A ; Transfere para o bit 0 do acumulador
; o carry
setb CLK ; Desloca dados no interior do AD
; e finaliza o pulso de deslocamento
djnz NumeroDeBits,RecebeADL ; Volta para RecebeADL, até receber
; todos os bits previstos
mov ByteADL,A ; Transfere para ByteADL o que
; recebeu no acumulador
; Fim LeConversorAD
;-------------------------------------------------------------------------------
; Rotina de Mostrar em Hexadecimal no Disply LCD
; R0 vem com o endereço do que vai ser mostrado (byte mais significativo)
; R1 com a posição que deve ser mostrado
; R7 com o número de bytes
;-------------------------------------------------------------------------------
MostraHex:
LoopMostraHex:
mov A,@R0 ; Carrega acumulador com
; o byte a converter
; Coverte a parte alta
swap A ; Troca nibles para tratar a parte alta
anl A,#00Fh ; Limpa parte alta do acumulador
; e fica somente com o nible alto
; na parte baixa do byte
cjne A,#00Ah,NibleAlto ; Compara com 00Ah para testar se esta
; abaixo ou acima de 9
NibleAlto:
jnc NibleAltoDeAaF ; Se o carry for '0' significa
; que o nibble é maior que '9'
NibleAltoDe0a9:
add A,#030h ; Converte nibble alto para ASCII(0 a 9)
sjmp NibleAltoDe0aF ; Vai salvar o resultado da conversão
NibleAltoDeAaF:
add A,#037h ; Converte nibble alto para ASCII(A a F)
NibleAltoDe0aF:
mov @R1,A ; Salva o resultado da conversão
; no buffer de saída
inc R1 ; Incrementa ponteiro do buffer de saída
NibleBaixoDeAaF:
add A,#037h ; Converte nibble baixo para ASCII (A a
F)
_______________________________________________
75
NibleBaixoDe0aF:
mov @R1,A ; Salva o resultado da conversão
; no buffer de saída
inc R1 ; Incrementa ponteiro do buffer de saída
inc R0 ; Incrementa ponteiro do buffer
; de entrada
djnz R7,LoopMostraHex ; Volta para LoopMostraHex até completar
; o número de bytes a converter
; Fim MostraHex
;-------------------------------------------------------------------------------
; Escreve Mensagem no Display LCD
;-------------------------------------------------------------------------------
EscreveMensagem:
clr A ; Zera o acumulador para que na próxima
; instrução só tenha valor o DPTR
movc A,@A+DPTR ; Busca caractere da mensagem na memória
; de programa
cjne A,#ETX,EscreveMensagem1 ; Testa se chegou ao fim da mensagem
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
EscreveMensagem1:
mov @R0,A ; Escreve no buffer o que
; pegou na mensagem
inc R0 ; Incrementa o ponteiro
; do buffer do Display
inc DPTR ; Incrementa o ponteiro da mensagem
jmp EscreveMensagem ; Volta para escrever o próximo
; caractere no display
; Fim EscreveMensagem
;-------------------------------------------------------------------------------
; Apaga Display
;-------------------------------------------------------------------------------
ApagaDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#32 ; Carrega tamanho do buffer do Display
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveDisplay ; Vai transferir para o display o
; que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaDisplay
;-------------------------------------------------------------------------------
; Apaga Linha 1 do Display
;-------------------------------------------------------------------------------
ApagaLinha1doDisplay:
mov R0,#Linha1doDisplay ; Carrega ponteiro com inicio
; da linha 1 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 1
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha1doDisplay ; Vai transferir para a linha 1 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha1doDisplay
;-------------------------------------------------------------------------------
; Apaga linha 2 do Display
;-------------------------------------------------------------------------------
ApagaLinha2doDisplay:
_______________________________________________
76
mov R0,#Linha2doDisplay ; Carrega ponteiro com inicio
; da linha 2 do display
mov R1,#16 ; Carrega tamanho do buffer da linha 2
call LimpaBufferDisplay ; Vai carregar o buffer com espaços
call EscreveLinha2doDisplay ; Vai transferir para a linha 2 do
; display o que escreveu no buffer
ret ; Retorna para onde veio
; Fim ApagaLinha2doDisplay
;-------------------------------------------------------------------------------
; Limpa buffer do Display LCD
; Escreve espaços (brancos) no buffer do display
;-------------------------------------------------------------------------------
LimpaBufferDisplay:
mov A,#' ' ; Carrega ACC com espaço
CLS1: mov @R0,A ; Escreve espaço na memória de Display
inc R0 ; Incrementa ponteiro da memória
djnz R1,CLS1 ; Testa se ja apagou toda memória
ret ; Retorna para onde veio
; Fim LimpaBufferDisplay
;-------------------------------------------------------------------------------
; Escreve no display
; Escreve todo o conteúdo do buffer do display na memória do mesmo
;-------------------------------------------------------------------------------
EscreveDisplay:
call EscreveLinha1doDisplay ; Vai escrever a Linha 1 do display
call EscreveLinha2doDisplay ; Vai escrever a Linha 2 do display
ret ; Retorna para onde veio
; Fim EscreveDisplay
;-------------------------------------------------------------------------------
; Escreve linha 1 do display
; Esta rotina escreve o conteudo do buffer
; da linha 1 na memória de dados do display
;-------------------------------------------------------------------------------
EscreveLinha1doDisplay:
; Envia o comando para mudar para o início da linha 1
mov ComandoLCD,#080h ; Comando para mudar para o inicio
; da linha 1 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 1 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha1doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha1doDisplay+16,LoopLinha1doDisplay ;
; Testa o fim da linha 1
ret ; Retorna para onde veio
; Fim EscreveLinha1doDisplay
;-------------------------------------------------------------------------------
; Escreve linha 2 do display
; Esta rotina escreve o conteudo do buffer
; da linha 2 na memória de dados do display
;-------------------------------------------------------------------------------
_______________________________________________
77
EscreveLinha2doDisplay:
; Envia o comando para mudar para o início da linha 2
mov ComandoLCD,#0C0h ; Comando para mudar para o inicio
; da linha 2 do display
clr RsLCD ; Coloca o display para receber COMANDOS
mov R0,#ComandoLCD ; Carrega R0 com o endereço de onde esta
; o comando a ser enviado para o display
call EnviaByteParaDisplayLCD ; Envia o comando de mudar para
; o inicio da linha 2 do display
setb RsLCD ; Coloca o display para receber DADOS
LoopLinha2doDisplay:
call EnviaByteParaDisplayLCD ; Vai enviar 1 byte para o display LCD
cjne R0,#Linha2doDisplay+16,LoopLinha2doDisplay ;
; Testa o fim da linha 2
ret ; Retorna para onde veio
; Fim EscreveLinha2doDisplay
;-------------------------------------------------------------------------------
; Envia byte para o display LCD
; Esta rotina envia um byte de comando ou de dado para o display LCD
;-------------------------------------------------------------------------------
EnviaByteParaDisplayLCD:
mov A,@R0 ; Carrega ACC com a memória de Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 100 uS
_______________________________________________
78
mov R7,#50 ; Carrega para 100 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 100 uS
; Fim EnviaByteParaDisplayLCD
;-------------------------------------------------------------------------------
; Envia nible alto para o display LCD
; Esta rotina é usada apenas na inicialização do display
;-------------------------------------------------------------------------------
EnviaNibleAltoParaDisplayLCD:
; Coloca nible alto no barramento
anl A,#0F0h ; Mascara para não perturbar a parte
; baixa da Porta 2
anl BarramentoDoDisplay,#00Fh ;
; Zera o nibble alto para que a próxima
; instrução funcione corretamente
orl BarramentoDoDisplay,A ; Envia nibble alto para o Display
; Pulso de escrita
setb EnLCD ; Início do pulso de escrita
nop ; Prolonga o pulso de escrita
clr EnLCD ; Fim do pulso de escrita
; Retardo de 200 uS
mov R7,#100 ; Carrega para 200 uS com clock de
; 11,059200 MHz
djnz R7,$ ; Aguarda 200 uS
; Fim EnviaNibleAltoParaDisplayLCD
;-------------------------------------------------------------------------------
Retardo4mS:
mov R3,#8 ; Carrega R3 para um retardo de 4 mS,
; com um cristal de 11,0592 MHz
mov R4,#39
Retardo4mS1: ; Fica neste loop até que os 2 registros
; cheguem a '0', quando então terá
; transcorrido 4 mS ou 100 mS,
; dependendo do valor de R3
djnz R4,Retardo4mS1
djnz R3,Retardo4mS1
ret ; Retorna para onde veio
; Fim Retardo4mS
;-------------------------------------------------------------------------------
; Textos
MsgMMDB:
DB ' MMDB-01 '
DB ' Kit Didatico',ETX
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do código
;-------------------------------------------------------------------------------
; Segmento de Bytes
;
; Segmento da memória RAM, reservada para as variáveis usadas no programas
;-------------------------------------------------------------------------------
DSEG at 22h
;-------------------------------------------------------------------------------
FimDosDados EQU $ ; Serve para indicar o fim da memória
; RAM usada para os dados.
;-------------------------------------------------------------------------------
CSEG ; Informa ao montador que a partir daqui
; começa o código fonte do programa
_______________________________________________
80
org 0000h ; Endereço de inicialização do
; microcontrolador, o qual vai para este
; quando é resetado
;-------------------------------------------------------------------------------
jmp IcializaPlaca ; Vai inicializar a placa
TIMER:
ORG 000BH ; Vetor do Interrupt 0
mov TH0,#0DBh ; Recarrega timer 0 com
mov TL0,#0FFh ; 10 mS a 11,0592 MHz
;-------------------------------------------------------------------------------
; | | | | |
; | Col 0 | Col 1 | Col 2 | Col 3 |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 0 | 1 | 2 | 3 | A |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 1 | 4 | 5 | 6 | B |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 2 | 7 | 8 | 9 | C |
; ________|_______|_______|_______|_______|________
; | | | | |
; Linha 3 | * | 0 | # | D |
; ________|_______|_______|_______|_______|________
; | | | | |
; | | | | |
;-------------------------------------------------------------------------------
Teclado:
jb TeclaValida,DesligaTecla ;
; Se tiver tecla válida, vai esperar
; o fim da tecla
mov DPTR,#ColunaLinha ; Carrega ponteiro com a tabela
; de Coluna/Linha
mov Linha,#0FFh ; Carrega para começar a varrer na Linha
; '0', pois vai incrementar quando for
; varrer o teclado
clr TeclaApertada ; Limpa flag para testar no retorno
VarreTeclado:
inc Linha ; Incrementa contador de Linha
mov A,Linha ; Carrega para converter número da Linha
movc A,@A+DPTR ; Converte número da Linha para fazer
; a varredura
jz DebounceDeTeclado ; Sai se já varreu todas as linhas
VarreLinhas:
swap A ; Para acionar a linha na parte alta da
; porta 2
mov P2,A ; Aciona a saída correspondente a Linha
mov A,P2 ; Lê retorno do teclado
orl A,#0F0h ; Mascara para ignorar a parte alta
cpl A ; Complementa para testar na próxima
; instrução
jz VarreTeclado ; Volta para varrer a próxima linha,
; pois não tinha tecla acionada nesta
; linha
cpl A ; Complementa para voltar ao que era
; antes
mov TeclaAtual,A ; Salva temporariamente a leitura da
; tecla
jb TeclaApertada,SaiTeclado ;
_______________________________________________
81
; Sai se já tiver tecla apertada
mov Coluna,#4 ; Carrega contador de colunas com '4'
; porque vai decrementar na rotina
; VarreColunas
VarreColunas:
mov A,Coluna ; Carrega o acumulador com o número da
; coluna
dec A ; Decrementa o acumulador para buscar a
; coluna certa na tabela
movc A,@A+DPTR ; Converte para testar retorno do
; teclado
xrl A,TeclaAtual ; Testa para saber em que coluna esta o
; retorno
jnz VarreColunas1 ; Vai continuar a varredura se não tiver
; tecla apertada na coluna, ou se tiver
; mais de uma tecla apertada
SalvaTecla:
mov A,Linha ; Carrega o acumulador com o número da
; linha
rl A ; Desloca 2 vezes para poder anexar ao
rl A ; número da coluna
dec Coluna ; Para chegar ao número correto da
; coluna e na próxima instrução anexar a
; linha
xrl A,Coluna ; Anexa o número da coluna ao da linha
mov TeclaAtual,A ; Salva valor da tecla em binário
setb TeclaApertada ; Sinaliza que tem apenas uma tecla
; apertada
sjmp VarreTeclado ; Volta para varrer o teclado até o fim
VarreColunas1:
djnz Coluna,VarreColunas ; Chega a 0 se tiver mais de uma tecla
; apertada na mesma Linha
SaiTeclado:
clr TeclaApertada ; Sinaliza que não tem nenhuma tecla
; apertada
DebounceDeTeclado:
jnb TeclaApertada,DesligaTecla ;
; Se não tiver mais tecla apertada, vai
; fazer o debounce do desligamento
inc DebounceDeTecla ; Incrementa o contador de debounce
mov A,DebounceDeTecla ; Carrega o acumulador para testar na
; próxima instrução
cjne A,#08h,SaiInt ; Testa se já passou 80 mS com mesma
; tecla
dec DebounceDeTecla ; Decrementa para não ultrapassar '8'
; no próximo teste
setb TeclaValida ; Sinaliza tecla válida depois de 80 mS
;*******************************************************************************
mov P1, TeclaAtual ; Teste
;*******************************************************************************
_______________________________________________
82
DesligaTecla:
mov P2,#00Fh ; Aciona todas as linhas
mov A,P2 ; Le retorno do teclado
orl A,#0F0h ; Para garantir que o nibble alto fique
; com 'F'
cpl A ; Complementa para testar na próxima
; instrução
jnz SaiInt ; Vai sair da interrupção se o
; acumulador não estiver com '0', pois
; ainda tem tecla apertada
djnz DebounceDeTecla,SaiInt ; Conta tempo de debounce de desliga
inc DebounceDeTecla ; Para
clr TeclaValida ; Desliga tecla válida depois 80 mS
SaiInt:
mov P2,#0FFh ; Desliga acionamento de Linhas
;*******************************************************************************
mov C,TeclaValida ; Teste
mov P0.0,C ; Teste
;*******************************************************************************
; Vem Volta
; com com
; Hex ASCII
db '1' ; 0 1
db '2' ; 1 2
db '3' ; 2 3
db 'A' ; 3 A
db '4' ; 4 4
db '5' ; 5 5
db '6' ; 6 6
db 'B' ; 7 B
db '7' ; 8 7
db '8' ; 9 8
db '9' ; A 9
db 'C' ; B C
db '*' ; C *
db '0' ; D 0
db '#' ; E #
db 'D' ; F D
;-------------------------------------------------------------------------------
IcializaPlaca:
;-------------------------------------------------------------------------------
; Inicializa Timer
;-------------------------------------------------------------------------------
_______________________________________________
83
InicializaTimer:
mov TH0,#0DBh ; Carrega timer 0 com
mov TL0,#0FFh ; 10 mS a 11,0592 MHz
mov TMOD,#011h ; Programa timer 0 e 1 para o modo 1
; 16 bits
setb ET0 ; Habilita interrupção do timer 0
setb EA ; Habilita interupts
setb TR0 ; Habilita timer 0
; Fim InicializaTimer
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
CodeSize equ $ ; Neste ponto o montador informa
; o tamanho do código
_______________________________________________
84
ANOTAÇÕES
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
______________________
_______________________________________________
85
CI - Circuitos Inteligentes Ltda.
SIA Quadra 5C, Área Especial 36, Sobreloja 01.
71.200-055 Brasília - DF.
Fone: 61 3362-9101 Fax: 61 3362-9102
www.circuitosinteligentes.com.br