MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
EXPERIÊNCIA 17 – USO DO TEMPORIZADOR INTERNO
Parte I – Fundamentos Teóricos
O que diferencia um microcontrolador (como o 8051) de um microprocessador é o fato de que o primeiro pode apresentar,
integrados na mesma pastilha, além da UCP, outros dispositivos componentes de um sistema computacional, como memória,
conversores A/D e D/A, interfaces de entrada/saída, etc.
Os componentes da família do 8051 apresentam circuitos internos para temporização e contagem de eventos. São os chamados
“timers” – o “timer0” e o “timer1”, no caso do 8051 – aos quais estão associados diversos registradores especiais, cujas funções serão
estudadas a seguir.
Cada “timer” tem 4 possíveis modos de operação. A seleção do modo de operação de cada “timer” é feita por 2 bits do registrador
especial TMOD (endereço 89h). Cada “timer” tem sua configuração independente (isto é, os “timers” não precisam operar no mesmo
modo). A tabela a seguir apresenta a maneira de se configurar o modo de operação de cada “timer”.
“timer1”
M1
M0
“timer0”
M1
M0
(TMOD.5)
(TMOD.4)
(TMOD.1)
(TMOD.0)
0
0
1
1
0
1
0
1
0
0
1
1
0
1
0
1
modo de operação
modo 0: temporizador/contador de 13 bits
modo 1: temporizador/contador de 16 bits
modo 2: temporizador/contador de 8 bits, com recarga automática
modo 3: 2 temporizadores/contadores de 8 bits (apenas “timer0”)
Nesta experiência, utilizaremos apenas o “timer0”, configurado no modo 1. A descrição dos demais modos pode ser vista na
documentação do 8051.
No modo 1, os registradores especiais TH0 (endereço 8Ch) e TL0 (endereço 8Ah), de 8 bits cada, se associam para formar um
único registrador de 16 bits, utilizado pelo “timer0” (analogamente, o “timer1” irá se utilizar dos registradores TH1, endereço 8Dh, e
TL1, endereço 8Bh). Nesse registrador de 16 bits, os 8 bits mais significativos são os do registrador TH0 (“H” de “high”), enquanto
os demais 8 bits, menos significativos, são os do registrador TL0 (“L” de “low”). Nesses 16 bits, é armazenado um valor de
contagem, compreendido entre 0 e 65.535 (= 216­1).
A qualquer momento, o valor da contagem do “timer0” (ou do “timer1”) pode ser verificado pelo programa, através da leitura dos
registradores TH0 e TL0 (ou TH1 e TL1). Da mesma forma, esse valor pode ser alterado, por uma escrita nesses mesmos
registradores. A restrição é a de que esses acessos precisam ser feitos em duas etapas: não existe instrução capaz de acessar os 2
registradores simultaneamente.
No modo 1 de operação (bem como nos demais modos), o valor de contagem é incrementado automaticamente, de acordo com a
forma com que o “timer” foi configurado: se como contador de eventos ou se como temporizador. Se, por exemplo, o “timer0” for
configurado como contador de eventos, o incremento do seu registrador de 16 bits ocorre a cada borda de descida de um sinal
externo, presente no pino T0, que é o pino 4 da porta P3 (analogamente, o registrador do “timer1” é incrementado nas bordas de
descida do pino T1, que é o pino 5 da porta P3). Já se o “timer0” for configurado como temporizador, o valor de contagem é
incrementado a uma taxa fixa, a cada “ciclo de máquina”, que corresponde a 12 períodos do “clock” do oscilador, o que significa
taxa de contagem é 1/12 da freqüência do “clock” do oscilador (como, no nosso caso, o “clock” é de 12MHz, a taxa de contagem é de
1MHz = 106Hz, isto é, a contagem é incrementada a cada 1µs = 10­6s, quando o “timer” é configurado como temporizador).
Portanto,
configuração
contagem é incrementada ...
freqüência
contador de eventos
temporizador
... a cada borda de descida do
sinal no pino T0 (ou T1)
... a cada ciclo de máquina (12
períodos de “clock”)
variável (depende do sinal no
pino T0 (ou T1))
constante (=1MHz)
Exemplo de aplicação do “timer” como contador ou como temporizador: o computador de bordo de bicicleta
O computador de bordo de bicicleta é um dispositivo capaz de mostrar a distância percorrida (função odômetro) e a velocidade
(função velocímetro). Num dos raios de uma das rodas, é colocado um ímã. Um sensor instalado no garfo é capaz de, a cada
passagem do ímã, (isto é, a cada revolução da roda), gerar um pulso elétrico, transmitido por um fio até o computador de bordo.
Previamente, o computador de bordo é programado com a medida do raio da roda. Assim, para poder funcionar como odômetro,
basta­lhe um contador de eventos: o número de pulsos registrado durante um certo percurso, multiplicado por 2π e pelo raio da
roda, fornece a distância percorrida.
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
Já a determinação da velocidade exige um temporizador, pois é preciso dividir a distância percorrida pelo tempo de percurso, e
este pode ser determinado pelo número de ciclos de máquina, multiplicado pelo tempo de cada ciclo (no nosso caso, 1µs)
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
A seleção para a configuração do “timer0” como contador de eventos ou como temporizador é feita por outro bit do registrador
especial TMOD: o bit C/T0 (bit 2) (analogamente, C/T1, o bit 6 de TMOD, seleciona a configuração do “timer1”). Com esse bit em
“0”, o “timer” fica configurado como temporizador (incrementado a cada ciclo de máquina). Com o bit C/T em “1”, o “timer” passa a
atuar como contador de eventos, isto é, de bordas de descida aplicadas ao pino T0 (ou T1, no caso do “timer1”).
Independentemente de sua configuração como contador de eventos ou como temporizador, cada “timer” pode ser ligado ou
desligado por programa, através de um bit do registrador especial TCON (cujo endereço de registrador é 88h): o bit TR0 (TCON.4,
cujo endereço de bit é 8Ch), que liga o “timer0” ao ser colocado em “1”, e o desliga quando em “0”. Analogamente, o bit TR1
(TCON.6, cujo endereço de bit é 8Eh) controla o “timer1”. Quando o “timer” está desligado, o seu valor de contagem permanece sem
ser alterado, mesmo que ocorram bordas de descida no pino T0 ou ciclos de máquina. Note­se, portanto, que desligar um “timer” não
significa “zerar” seu valor de contagem, mas sim “travar” este valor. Para “zerar” a contagem, é preciso escrever “0” nos
registradores de contagem: TH0 (ou TH1) e TL0 (ou TL1).
Por ser fornecido em 16 bits, o valor de contagem pode ser, no máximo, de 65.535 (=216−1). Isso significa que, se os registradores
de contagem tiverem sido inicialmente “zerados”, poderão ser contadas, no máximo, 65.535 bordas de subida no pino T0 (ou T1), se
o “timer” estiver configurado como contador de eventos; ou a passagem de 65.535µs (=0,065535s), se o “timer” estiver configurado
como temporizador.
Nesse caso, ocorrendo mais uma contagem (outra borda de descida em T0 ou T1, ou mais 1µs), o valor da contagem volta a zero.
Nesse momento, porém, ocorre um pedido de interrupção, causada pelo estouro da contagem do “timer”. Como já foi visto em outra
experiência, caso a respectiva interrupção esteja habilitada (por bits do registrador especial IE, já vistos), ocorre um desvio do
programa para o seu tratamento, a partir do endereço 000Bh (para o “timer0), ou 001Bh (para o “timer1”).
Com o “timer0” configurado como temporizador, temporizações de até 0,065535s podem ser indicadas pela ocorrência de um
pedido de interrupção de estouro de um dos “timers” (por exemplo, o “timer0”), desde que sejam seguidos os seguintes passos:
• “timer0” deve ser configurado como temporizador (C/T=TMOD.2 ← 0), no modo 1 (M1=TMOD.1 ← 0 e M0=TMOD.0 ← 1)
• valor inicial de contagem deve ser escrito nos registradores especiais TH0 e TL0 (mais adiante é mostrado como esse valor deve
ser calculado)
• a interrupção de estouro de contagem do “timer0” deve ser habilitada (ET0=IE.1 ← 1 e EA=IE.7 ← 1)
• “timer0” deve ser ligado (TR0=TCON.4 ← 1)
A partir desse instante, o valor de contagem do “timer0” passa a ser incrementado a cada 1µs. Ao estourar, voltando a 0 depois de
ter passado por 65.535, gera um pedido de interrupção, cujo tratamento deve sinalizar o fim da temporização previamente pretendida.
O tempo decorrido (T), em segundos, depende, evidentemente, do valor inicial de contagem do “timer” (TIMER_INICIAL):
T = (65.536 − TIMER_INICIAL) x 10­6
A temporização mais longa possível, Tmax, será obtida para o menor valor inicial de contagem, TIMER_INICIALmin.
Fazendo
TIMER_INICIALmin ← 0
então
Tmax = (65.536 − 0) x 10­6 = 0,065536s = 65,536ms
Para uma temporização T qualquer, menor do que esse valor, tem­se
TIMER_INICIAL ← inteiro (65.536 − 106 x T + 0,5)
onde
0 < T ≤ 0,065536s(=65,536ms)
Temporizações ainda mais longas do que 65,536ms podem ser obtidas através do uso de uma variável contadora de interrupções,
CONTA_INT, cujo valor inicial seja CONTA_INT_INICIAL. O tratamento do pedido de interrupção por estouro do temporizador
precisa, agora, decrementar CONTA_INT a cada interrupção, verificando se chegou a 0, caso em que a temporização estaria
encerrada. Caso contrário, o “timer” precisa ter seu valor de contagem (que acaba de passar a 0) reiniciado com TIMER_INICIAL,
até que estoure, gerando um novo pedido de interrupção.
O tempo decorrido (T), em segundos, fica agora sendo:
T = CONTA_INT_INICIAL x (65.536 − TIMER_INICIAL) x 10­6
Agora, para a determinar a temporização mais longa possível, Tmax, é necessário fazer
TIMER_INICIALmin ← 0
CONTA_INT_INICIALmax ← 256 (na verdade, o valor atribuído deve ser 0)
então
Tmax = 256 x (65.536 − 0) x 10­6 = 16,777216s ≅ 16,8s
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
Para uma temporização T qualquer, tem­se que
CONTA_INT_INICIAL x (65.536 − TIMER_INICIAL) = 106 x T
ou seja, é necessário determinar um par de inteiros, CONTA_INT_INICIAL e TIMER_INICIAL, que satisfaçam a equação
anterior, e tais que
0 < CONTA_INT_INICIAL ≤ 256
0 ≤ TIMER_INICIAL < 65.535
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
Uma possível forma de se determinar esse par de valores é fazer:
CONTA_INT_INICIAL ← inteiro ( (106 x T / 65.536) + 1 )
TIMER_INICIAL ← inteiro ( ( (CONTA_INT_INICIAL x 65.536 − 106 x T) / CONT_INT_INICIAL) + 0,5 )
No caso desta experiência, deseja­se uma temporização de 1s (isto é, T = 1s). Logo:
CONTA_INT_INICIAL ← inteiro ( (106 x 1 / 65.536) + 1 ) = inteiro (16,26) = 16
TIMER_INICIAL ← inteiro ( ( (16 x 65.536 − 106 x 1) / 16) + 0,5 ) = 3.036
Finalmente, um último problema: uma vez obtido o valor inicial de contagem (TIMER_INICIAL), é preciso determinar
TIMER_INICIAL_H e TIMER_INICIAL_L (bytes mais e menos significativos), a fim de carregá­los em TH0 e TL0,
respectivamente.
Sabendo­se que
TIMER_INICIAL = 256 x TIMER_INICIAL_H + TIMER_INICIAL_L
vem que
TIMER_INICIAL_H ← inteiro (TIMER_INICIAL / 256)
TIMER_INICIAL_L ← TIMER_INICIAL − 256 x TIMER_INICIAL_H
No nosso caso, com
TIMER_INICIAL = 3.036
vem que
TIMER_INICIAL_H ← inteiro (3036 / 256) = inteiro (11,86) = 11
TIMER_INICIAL_L ← 3.036 − 256 x 11 = 220
Parte II – Roteiro Experimental
Nesta experiência, você deverá realizar a montagem de um programa já escrito na linguagem de montagem do 8051, editado no
arquivo RELUZINT.ASM, cuja listagem é fornecida.
Ao ser executado, desde que os LEDs do kit tenham sido convenientemente conectados aos pinos da porta P1, como já foi feito na
experiência 13, haverá o mesmo efeito de deslocamento de luzes daquela experiência.
Ao mesmo tempo, um relógio digital será apresentado no display, incrementado a cada segundo. Antes de executar o programa, é
preciso ajustar o valor inicial do horário.
Descreva, sucintamente, o funcionamento do programa.
EXPERIÊNCIA 17 – QUESTÕES ADICIONAIS
1) Em qual área da memória são armazenadas as indicações de hora, minuto e segundo?
2) Em quais endereços dessa área essas indicações são armazenadas?
3) Explique o motivo para as instruções PUSH ACC e POP ACC, existentes na rotina R_TRATA_INT_TIMER0. Indique um ponto
do programa em que a ocorrência de uma interrupção do “timer0” causaria problemas, caso essas instruções não existissem.
4) Considere o planeta SPEEDY, cujo sistema de marcação de tempo é igual ao da Terra (ou seja, tem dias com 24 horas, horas com
60 minutos, minutos com 60 segundos), mas no qual o segundo é 20 vezes mais rápido do que o segundo na Terra. Altere o
arquivo RELUZINT.ASM, gerando o arquivo RELSPEED.ASM, de forma a apresentar o relógio do planeta SPEEDY
(mantendo o ritmo dos LEDs). Teste seu programa, lembrando que cada minuto terráqueo corresponde a 20 minutos speedyanos.
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
$INCLUDE(REG51.INC)
$INCLUDE(MONIT.INC)
; declaracoes de simbolos
; valores calculados para obter uma temporizacao de 1s
C_CONTA_INT_INICIAL EQU 16
C_TIMER_INICIAL_H EQU 11
C_TIMER_INICIAL_L EQU 220
DSEG
ORG 0070h
HORA: DS 1 ; valor das horas
MINUTO: DS 1 ; valor dos minutos
SEGUNDO: DS 1 ; valor dos segundos
CONTA_INT: DS 1 ; numero de interrupcoes do timer0
; (ao chegar a 0, indica que se passou 1s)
CSEG
; desvio para o tratamento da interrupcao do timer0
ORG VETORINT_TIMER0
JMP R_TRATA_INT_TIMER0
ORG 5000h
MOV SP, #2Fh ; inicia ponteiro da pilha
MOV TMOD, #00000001b ; timer0 no modo 1
MOV TH0, #C_TIMER_INICIAL_H
MOV TL0, #C_TIMER_INICIAL_L ; contagem para 1/16 s
MOV CONTA_INT, #C_CONTA_INT_INICIAL ; contagem para 1s
SETB ET0 ; habilita int. do timer0
SETB EA ; habilita todas ints. ja habilitadas
LCALL CLR_DSP ; limpa o display
MOV A, #0Ch
LCALL DSP_COM ; tira o cursor do display
SETB TR0 ; liga timer0
REPETE: MOV R0, #00010000b ; inicia estados dos LEDs da esquerda
MOV R1, #00001000b ; inicia estados dos LEDs da direita
MOV R2, #4 ; inicia contador de deslocamentos
VOLTA: MOV A, R0
ADD A, R1 ; junta estados dos LEDs
MOV P1, A ; acende e apaga LEDs
LCALL ATRASO ; espera um tempo
MOV A, R0
RL A
MOV R0, A ; desloca LED aceso para a esquerda
MOV A, R1
RR A
MOV R1, A ; desloca LED aceso para a direita
DJNZ R2, VOLTA ; se ainda nao chegou na ponta, volta
LJMP REPETE ; se ja' chegou na ponta, reinicia
; rotina para esperar um tempo
ATRASO: PUSH 0
PUSH 1
PUSH 2
MOV R0, #3
SALTO3: MOV R1, #0
SALTO2: MOV R2, #0FFh
SALTO1: DJNZ R2, SALTO1
DJNZ R1, SALTO2
; tratamento da interrupcao do timer0
R_TRATA_INT_TIMER0:
PUSH ACC ; salva acumulador na pilha (vai usa­lo na interr.)
MOV TH0, #C_TIMER_INICIAL_H
MOV TL0, #C_TIMER_INICIAL_L ; recarrega contador de 1/16s
DJNZ CONTA_INT, L_NAO_1S ; verifica se completou 1s
LCALL R_INCREMENTA_HORARIO ; atualiza horario, com mais 1s
LCALL R_MOSTRA_HORARIO ; mostra horario atualizado
MOV CONTA_INT, #C_CONTA_INT_INICIAL ; recarrega contador de 1s
L_NAO_1S:
POP ACC ; restaura acumulador
RETI
; incremento do horario (passou 1s)
R_INCREMENTA_HORARIO:
MOV A, SEGUNDO
ADD A, #1
DA A
MOV SEGUNDO, A ; incrementa os segundos
CJNE A, #60h, L_FIM_INCREMENTA ; precisa incrementar min?
MOV SEGUNDO, #0 ; e zerar segundos?
MOV A, MINUTO
ADD A, #1
DA A
MOV MINUTO, A ; incrementa os minutos
CJNE A, #60h, L_FIM_INCREMENTA ; precisa incrementar hora?
MOV MINUTO, #0 ; e zerar minutos?
MOV A, HORA
ADD A, #1
DA A
MOV HORA, A ; incrementa as horas
CJNE A, #24h, L_FIM_INCREMENTA ; precisa zerar hora?
MOV HORA, #0
L_FIM_INCREMENTA:
RET
; apresentacao do horario
R_MOSTRA_HORARIO:
MOV A, #0C4h
LCALL DSP_COM ; posiciona cursor na coluna 5 da linha 2
MOV A, HORA
LCALL AC_DSP ; mostra hora
MOV A, #':'
LCALL DSP_DAT
MOV A, MINUTO
LCALL AC_DSP ; mostra minuto
MOV A, #':'
LCALL DSP_DAT
MOV A, SEGUNDO
LCALL AC_DSP ; mostra segundo
RET
END
MM – Microprocessadores e Microcontroladores – Roteiro da Experiência 17
Download

EXPERIÊNCIA 1 – RESET + EXECUÇÃO DE PROGRAMAS