Temporizador

Contadores i8254, palavra de controlo, read-back, divisor e intervalos em ticks.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

Uma aplicação que desenha a cada dois ticks precisa de uma fonte regular de eventos. No PC, a saída do contador 0 do i8254 está ligada à IRQ0. Os três contadores de 16 bits recebem impulsos de um relógio de entrada; o divisor e o modo determinam a saída de cada um.

Relógio, divisor e modos

Nos exemplos usamos a frequência nominal de entrada fin=1 193 182 Hzf_{in}=1\,193\,182\ \text{Hz}. No código do laboratório usa a constante TIMER_FREQ do cabeçalho de apoio, sem a repetir em várias funções.

Nos modos periódicos, um divisor NN determina a frequência:

fout=finN,T=Nfin.f_{out}=\frac{f_{in}}{N},\qquad T=\frac{N}{f_{in}}.

Para 1000 Hz, a política de quociente inteiro escolhe N=⌊1193182/1000⌋=1193N=\lfloor1193182/1000\rfloor=1193. Dividir o relógio por 1193 produz cerca de 1000,15 Hz. O pedido não é a frequência exata da saída. Em contagem binária, o valor carregado 0x0000 representa 65536, não um divisor zero. Os modos 2 e 3 exigem um divisor de pelo menos 2. Em BCD, o contador representa quatro algarismos decimais e o intervalo é diferente; não interpretes um valor BCD como um contador binário de 16 bits.

ModoComportamento da saída
0, terminal countA saída sobe quando a contagem termina e conserva esse nível
1, one-shotUm disparo externo inicia um impulso, que pode ser novamente disparado
2, rate generatorUm impulso baixo de um ciclo por período, com recarga automática
3, square waveSaída alta e baixa durante partes aproximadamente iguais do período
4, software strobeImpulso no fim da contagem iniciada por software
5, hardware strobeImpulso no fim da contagem disparada externamente

No modo 3, um divisor par dá metades iguais. Com divisor ímpar, a fase alta dura um ciclo de entrada mais do que a baixa, por isso não contes os dois flancos da onda como duas interrupções por período.

Palavra de controlo

As portas dos contadores são 0x40, 0x41 e 0x42; a porta de controlo é 0x43. A palavra de controlo normal tem estes campos:

BitsCampo
7 a 6Contador: 00 para 0, 01 para 1, 10 para 2
5 a 4Acesso: 01 só LSB, 10 só MSB, 11 LSB seguido de MSB
3 a 1Modo de contagem
0Base: 0 binária, 1 BCD

Por exemplo, contador 2, LSB seguido de MSB, modo 3, binário:

10 11 011 02=0xB6.10\ 11\ 011\ 0_2=\texttt{0xB6}.

Para carregar N=1234=0x04D2N=1234=\texttt{0x04D2}:

PassoPortaValorEfeito
10x430xB6Selecionar contador 2, LSB/MSB, modo 3 binário
20x420xD2Escrever os oito bits inferiores
30x420x04Escrever os oito bits superiores

As duas escritas usam a mesma porta, mas carregam partes diferentes. Inverter os bytes daria 0xD204, ou 53764. Se esse divisor fosse usado no contador 0, produziria cerca de 22,19 Hz em vez da frequência esperada para 1234.

Read-back e estado

Para conhecer a configuração, escreve um read-back command em 0x43 e lê o estado na porta do contador escolhido. Os bits 7 e 6 são 11 para distinguir este comando de uma palavra de controlo normal.

BitValor relevante no read-back
50 para capturar a contagem, 1 para não a capturar
40 para capturar o estado, 1 para não o capturar
31 seleciona o contador 2
21 seleciona o contador 1
11 seleciona o contador 0
0Reservado, escreve 0

COUNT e STATUS são seleções ativas a 0. Para obter só o estado do contador 0, a palavra é 0xE2: 0xC0 identifica read-back, 0x20 evita a contagem e 0x02 seleciona o contador. Depois, lê 0x40 uma vez.

No byte de estado, o bit 7 representa OUT e o bit 6 é Null Count, que indica se o novo valor ainda não foi carregado no elemento de contagem. Os bits 5 a 0 repetem acesso, modo e base. Não interpretes os bits 7 e 6 do estado como seleção do contador.

Extrai o modo com (status >> 1) & 7. Os códigos 6 e 7 são alternativas de 2 e 3; normaliza-os subtraindo 4. Quando o comando captura estado e contagem, a leitura da porta do contador devolve primeiro o byte de estado e depois os bytes da contagem, pela ordem de acesso programada. O latch permite obter um valor coerente sem juntar bytes de contagens diferentes.

Escolher a frequência

Para pedir 60 Hz, o divisor ideal é:

N∗=1 193 18260=19 886,366…N^*=\frac{1\,193\,182}{60}=19\,886{,}366\ldots

Como o divisor é inteiro, uma política habitual no laboratório usa o quociente inteiro, N=19886=0x4DAEN=19886=\texttt{0x4DAE}. A frequência real é:

freal=1 193 18219886≈60,001106 Hz.f_{real}=\frac{1\,193\,182}{19886}\approx60{,}001106\ \text{Hz}.

Carregam-se LSB 0xAE e MSB 0x4D. O período é cerca de 16,66636 ms. Uma contagem de 216000 ticks, interpretada como uma hora a 60 Hz, termina cerca de 0,0664 s antes de uma hora real neste modelo de relógio ideal.

A escolha por quociente inteiro e a escolha por arredondamento ao inteiro mais próximo são políticas diferentes. Com 100 Hz, o quociente dá 11931 e cerca de 100,006873 Hz; o arredondamento dá 11932 e cerca de 99,998491 Hz. Declara qual estás a usar antes de comparar resultados.

A simulação usa quociente inteiro e contagem binária em modo 3. Altera a frequência para observar o divisor, os bytes e a diferença entre pedido e resultado. Não modela tolerância do oscilador, atrasos do Minix nem perda de notificações.

Relógio de entrada1 193 182 Hz
Dividir por N19886
Frequência real60,001106 Hz
N = 19886, LSB = 0xAE, MSB = 0x4D. Período = 16,66636 ms.

Antes de converter para uint16_t, verifica a frequência e o quociente. Um pedido de 18 Hz exige um divisor maior do que 65536 e não cabe no intervalo binário. Converter primeiro pode produzir um divisor pequeno e uma frequência inesperada. Para usar 65536, conserva esse valor num tipo mais largo durante as contas e codifica-o como dois bytes zero.

Preservar a configuração

Se a função só altera a frequência, conserva os quatro bits inferiores do estado, que contêm modo e base. A palavra normal reúne seleção do contador, acesso LSB/MSB e status & 0x0F:

uint8_t control = (uint8_t)((timer << 6) | 0x30 | (status & 0x0F));

Este é um excerto de construção da palavra, com timer previamente validado entre 0 e 2. Ler a configuração, construir a palavra e carregar o divisor são operações com possíveis falhas de I/O. Se a base for BCD, uma rotina que só calcula divisores binários deve rejeitá-la ou tratá-la explicitamente.

Alterar timer 0 também afeta o Minix: o sistema assume a frequência que programou para medir tempo. Se passares de 60 para 30 Hz sem mudar esse pressuposto, o relógio do sistema avança cerca de metade do tempo real. Repõe a configuração exigida pelo ambiente ao terminar a experiência.

Ticks, intervalos e overflow

Com frequência ff, kk ticks representam aproximadamente k/fk/f segundos. Entre os contadores 120 e 453, passaram 333 ticks, ou 5,55 s a 60 Hz. A resolução é um tick; o resultado não mede frações de tick.

Para um contador sem sinal de 32 bits, a subtração também é feita módulo 2322^{32}. Se start = 0xFFFFFFFE e now = 3, now - start dá 5 em uint32_t, apesar da passagem por zero. O cálculo é útil desde que o intervalo real tenha menos de uma volta completa do contador. Não funciona se já passaram uma ou mais voltas sem que as tenhas contabilizado.

Para decidir timeouts por comparação de diferenças, mantém todos os valores com o mesmo tipo sem sinal e uma duração dentro do intervalo suportado. A 60 Hz, uma volta de 32 bits dura cerca de 828,5 dias. Um contador com sinal não oferece a mesma regra: o overflow com sinal é comportamento indefinido.

Finalmente, distinguir frequência do hardware e frequência de desenho evita erros de animação. Um timer a 60 Hz pode gerar um desenho a cada dois ticks, ou 30 frames/s. A lógica pode receber teclas entre frames; não a bloqueies à espera de um desenho.

Exercícios

Construir uma palavra de controlo

Configura contador 1, LSB seguido de MSB, modo 2 e contagem binária. Que palavra escreves em 0x43? Responde em decimal.

Pista
A seleção 1 ocupa bits 7 e 6 com 01.
Solução

0x40 | 0x30 | 0x04 | 0x00 = 0x74, ou 116. O bit de BCD permanece a 0. Esta é uma palavra normal, não um comando read-back.

Erros frequentes

Colocar o modo diretamente sem o deslocar ou escolher acesso MSB seguido de LSB, que não é o código 11.

Voltar à explicação
Calcular os bytes do divisor

Com relógio de 1193182 Hz, pede 100 Hz pela política de quociente inteiro. Calcula divisor, LSB e MSB e diz se a frequência real é acima ou abaixo de 100 Hz.

Pista
Divide antes de converter para 16 bits.
Solução

O divisor é floor(1193182/100) = 11931. Escreve 0x9B e depois 0x2E no contador. Como 11931 é menor do que o divisor ideal 11931,82, o quociente real é maior: cerca de 100,006873 Hz.

Confere a tua resposta:

  • Usei quociente inteiro 11931.
  • Separei LSB 0x9B e MSB 0x2E.
  • Distingui frequência pedida e real.

Erros frequentes

Arredondar para 11932 quando o enunciado pede quociente inteiro ou inverter a ordem dos bytes.

Voltar à explicação
Medir através da passagem por zero

start é uint32_t com valor 0xFFFFFFFC e now é uint32_t com valor 3. Houve menos de uma volta completa do contador. Quanto vale now - start em uint32_t?

Pista
A aritmética sem sinal é módulo 2 elevado a 32.
Solução

Há sete incrementos do início ao fim. A diferença calculada módulo 2 elevado a 32 é 7. O resultado exige que o intervalo real não inclua uma volta adicional inteira.

Erros frequentes

Concluir que toda a passagem por zero invalida a subtração ou aplicar a mesma regra ao overflow de inteiros com sinal.

Voltar à explicação
Separar comando e byte de estado

Queres ler só o estado do contador 2. Dá o comando read-back, a porta que lês e interpreta acesso, modo e base se receberes 0xBE. Normaliza o modo.

Pista

Selecionar contador 2 usa bit 3 no read-back; COUNT e STATUS são ativos a zero.

Mais uma pista

0xBE = 10111110 em binário. Os bits superiores do estado são OUT e Null Count.

Solução

O comando é 0xC0 | 0x20 | 0x08 = 0xE8, escrito em 0x43. Lês 0x42. O estado 0xBE tem acesso 11, LSB seguido de MSB; modo 111, código 7 que normaliza para modo 3; base binária, bit 0 a zero. OUT está a 1 e Null Count a 0. Os bits 7 e 6 não selecionam o contador neste byte.

Confere a tua resposta:

  • Construí 0xE8 e li 0x42.
  • Extraí acesso 11 e base binária.
  • Normalizei modo 7 para 3.

Erros frequentes

Usar 0xA0 como seleção num read-back ou interpretar código 7 como um sétimo modo independente.

Voltar à explicação
Rejeitar uma frequência impossível

Pedem 18 Hz ao temporizador binário. O quociente inteiro é 66287. Que deve fazer a função antes de converter para uint16_t?

Pista
65536 é o maior divisor binário.
Solução

Deve rejeitar o pedido. 66287 não cabe em 16 bits nem como 65536 codificado em dois bytes zero, porque excede o intervalo. Converter para uint16_t antes de validar daria um divisor pequeno e uma frequência inesperada.

Confere a tua resposta:

  • Calculei o divisor antes de converter.
  • Rejeitei 18 Hz por exceder 65536.
  • Não truncuei para um divisor pequeno.

Erros frequentes

Truncar o divisor ou programar dois bytes zero para um valor que não é 65536.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.