Upload
nguyenthuy
View
229
Download
0
Embed Size (px)
Citation preview
Capítulo 5 – Periféricos
Prof. Romis Attux
EA075 – 2015
Obs: Os slides são parcialmente baseados nos dos autores do livro texto
Periféricos
Periféricos são dispositivos de hardware que, como o nome indicam, operam na periferia da CPU mesmo quando ocupam o mesmo chip.
Neste capítulo, discutiremos aspectos e exemplos de periféricos.
Timers
Timers são dispositivos que medem intervalos de tempo.
Eles podem gerar eventos em tempos específicos (imagine o
controle de um semáforo, por exemplo) ou podem marcar o
espaçamento temporal entre dois eventos externos (por
exemplo, entre a passagem de um carro por dois sensores).
Um timer mede o tempo por meio da contagem de pulsos de
um sinal de clock de duração definida. Por exemplo, se é
utilizado um clock de 1 microssegundo, a contagem de 2000
pulsos equivale a um intervalo de 2 milissegundos.
Contadores
Contadores, de certa forma, generalizam a noção de timer, pois permitem que sejam contados eventos a partir não só de um sinal de clock fixo, mas de um sinal de entrada qualquer.
Um contador pode ser usado para medir o número de pessoas que passam por um sensor, por exemplo.
Timers podem ser combinados com contadores para medir taxas (e.g. a taxa de giro da roda de um carro).
Timers
Basicamente, configuram-se as entradas de um timer e se
monitoram suas saídas.
Discutiremos a seguir alguns exemplos usuais.
O primeiro exemplo, mostrado na figura a seguir, possui um
contador interno de 16 bits (0 a 65535), que é incrementado a cada
pulso e cujo estado é indicado por ‘cnt’. Para que se tenha uma
medida de tempo, é preciso conhecer o valor do período de clock.
Se tivermos um clock de 100 MHz, teremos um período de 10 ns. O
timer, então teria um alcance (range) de 0 a 655,35 microssegundos
e uma resolução de 10 ns (menor intervalo de tempo mensurável).
Timer - Exemplo
O timer contém ainda uma saída ‘top’ que indica
quando o valor máximo de contagem foi atingido,
o que representa uma espécie de overflow, já
que o estado retorna a zero.
Quando se usa o timer em conjunto com um
processador de propósito geral, pode-se ligar o
pino ‘top’ a um pino de interrupção, acionando
uma rotina de serviço que registra o número de
overflow, aumentando o range de contagem.
Muitos microcontroladores que contém timers
possuem interrupções próprias para eles,
distintas de interrupções externas.
Timer – Exemplo 2
O segundo timer que discutiremos também pode operar como contador. Isso se dá graças a um multiplexador que possui um bit de controle ‘mode’, o qual deixa passar um clock (modo de timer) ou um sinal de entrada genérico (modo de contador).
A figura a seguir ilustra esse timer.
Timer – Exemplo 3
Um terceiro tipo de timer permite que se defina um range de contagem específico (menor que o máximo) por meio de uma palavra ‘terminal_count’.
Por exemplo, se desejarmos contar apenas 300 ciclos, usamos esse número num comparador. Quando a contagem é atingida, gera-se um sinal ‘top’ e se faz o reset do contador.
A figura ilustra o esquema.
Timer – Exemplo 3
16-bit up
counter Clk
16
Terminal count
= Top
Reset
Timer with a terminal
count
Cnt
Timer – Exemplo 4
Seria possível utilizar também um contador reverso carregado com o valor terminal e que contasse até zero, quando seria então carregado com o valor terminal de novo. Nesse caso, a lógica de geração do sinal ‘top’ poderia ser feita simplesmente com uma porta NOR.
Timer – Exemplo 5
É possível usar um contador para operar com 16 e 32 bits lançando mão de dois contadores de 16 bits com o sinal de clock do segundo sendo o sinal ‘top’ do primeiro.
Essa estrutura é chamada de estrutura de contadores em cascata.
A figura a seguir ilustra a estrutura.
Timer – Exemplo 6
Também é possível construir um timer com um prescaler, que pode realizar uma divisão do sinal de clock. Por exemplo, pode-se ter um sinal de clock de 10 ns de período e, com o prescaler, obter, 80 ns de período, aumentando o range de contagem e tornando a resolução mais grosseira.
A figura a seguir ilustra isso.
Exemplo – Reaction Timer
Deseja-se projetar um timer que conte o tempo decorrido entre o acendimento de um LED e o momento em que um usuário aperta um botão.
A idéia geral é dada na seguinte figura.
indicator
light
reaction
button
time: 100 ms LCD
Exemplo – Reaction Timer
Utilizaremos um microcontrolador com um timer
de 16 bits embutido. O timer é incrementado a
cada ciclo de instrução, que corresponde, no
caso, a seis ciclos de clock. A frequência de
clock é de 12 MHz, de modo que um ciclo de
instrução equivale a 0,5 microssegundo.
Como o timer tem 16 bits, o range é de
65535*0,5s = 32,77 ms.
O timer não possui um prescaler, mas tem um
sinal ‘top’ e permite o carregamento de um valor
inicial de contagem qualquer.
Exemplo – Reaction Timer
O range do timer é menor que o tempo de
reação esperado (de alguns segundos).
Portanto, precisamos estender o range sem
contar com um prescaler ou um registrador de
contagem terminal.
Faremos o ajuste do valor inicial de contagem
para que haja overflow após 1 ms, e
monitoraremos o sinal ‘top’ para contar o número
de overflows ocorridos. Para gerar 1 ms, são
necessários 2000 ciclos de instrução. Portanto, o
valor inicial de contagem adequado é
65535 – 2000 = 63535.
Exemplo – Reaction Timer
/* main.c */
#define MS_INIT 63535
void main(void){
int count_milliseconds = 0;
configure timer mode
set Cnt to MS_INIT
wait a random amount of time
turn on indicator light
start timer
while (user has not pushed reaction button){
if(Top) {
stop timer
set Cnt to MS_INIT
start timer
reset Top
count_milliseconds++;
}
}
turn light off
printf(“time: %i ms“, count_milliseconds);
}
Exemplo – Reaction Timer
Note que há uma imprecisão, já que é preciso parar o timer, reiniciá-lo e começar de novo. Considera-se esse tempo desprezível em termos práticos.
Watchdog Timers
Watchdog timers são tipos especiais de timers.
Eles são configurados com um valor de tempo
real, mas, em vez de gerar um sinal a cada t
segundos, o timer é encerrado e gera um sinal
de falha caso um sinal não seja gerado para ele
no momento adequado.
Uma utilização comum desse tipo de timer é
para permitir que um sistema embarcado se
reinicie no caso de uma falha. Nesse caso,
colocam-se sinais de reset do watchdog no
código para evitar o timeout e conecta-se o pino
de falha no pino de reset do processador.
Watchdog Timers
Em sistemas nos quais o reset total não é uma
opção, pode-se configurar uma rotina de serviço
(associada a um pino de interrupção) que leve a
um pulo para uma parte segura do código.
Pode-se até mesmo adotar uma abordagem
híbrida, pulando para uma rotina de serviço,
registrando o erro, e partindo depois para o
reset.
Note que isso é importante, pois um sistema
embarcado nem sempre pode sofrer boot de
forma simples como um desktop.
UART
Uma UART (Universal Asynchronous Receiver / Transmitter) recebe dados seriais e os grava em paralelo (geralmente um byte). Ela também toma dados em paralelo e os transmite de maneira serial.
A comunicação serial é útil quando se quer comunicar bytes de dados entre dispositivos separados por distâncias longas ou quando os dispositivos possuem poucos pinos de entrada / saída disponíveis.
UART
Internamente, uma UART simples pode possuir alguns registradores de configuração, e dois processadores de operação independente, um para receber e o outro para transmitir.
O transmissor pode possuir um registrador, geralmente denominado buffer de transmissão, que guarda os dados a serem enviados. O registrador possui a capacidade de deslocamento, de modo que os bits podem ser enviados de maneira serial (um por vez).
UART
O receptor, por sua vez, também possui um registrador de deslocamento, que recebe serialmente os bits e “os paraleliza”.
Isso é ilustrado na figura a seguir.
embedded
device 1
0 0 1
1 0 1 1
Sending UART
1 0 0 1 1 0 1 1
Receiving UART
1 0 0 1 1 0 1 1
UART
Note que, para realizar o deslocamento na taxa apropriada (e configurada), a UART precisa de um timer.
O receptor monitora constantemente o pino de recepção (rx) buscando um bit de início. Esse bit é tipicamente sinalizado por uma transição de alto para baixo em rx. Quando o bit é detectado, o receptor começa a amostrar os dados em intervalos predeterminados, deslocando os bits para seu registrador.
UART
Se for configurado para isso, o receptor lê ainda um bit de paridade, que é usado para verificar se a informação recebida está correta. Por exemplo, se for usada paridade ímpar, o número de “1s” nos dados + bit de paridade deve ser ímpar. Também pode-se configurar a UART para lidar com paridade par ou para operar sem paridade.
Quando os dados são recebidos, a UART sinaliza e o processador lê o byte no registrador de recepção. Ele agora está apto a receber mais dados.
UART
O transmissor opera da seguinte forma. Primeiramente, ele envia um bit de transmissão em seu pino de transmissão (tx), sinalizando o início do processo.
Então ele desloca os dados para tx numa taxa pré-definida. Se necessário, ele adiciona um bit de paridade ao final, como já discutimos.
Nesse ponto, a UART sinaliza a seu processador que está pronta para transmitir mais dados.
UART - Protocolo
O protocolo usado por UART’s tem a seguinte estrutura. Primeiro define-se a baud rate, taxa de transmissão e recepção de bits. Também se especifica o número de bits de dados utilizado e o tipo de paridade. Por fim, o protocolo define o número mínimo de bits usados entre transmissões. Esses bits são importantes para que a UART possa se preparar para receber a informação quando ela vier.
UART – Baud Rate
A baud rate determina a taxa de transmissão / recepção entre UARTs. Taxas usuais incluem 2400, 4800, 9600 e 19200 bits/s.
A configuração da baud rate requer a escrita num registrador especial segundo regras pré-determinadas (que não discutiremos).
Seria possível realizar a transmissão nos moldes da UART em nível de software, mas isso consumiria tempo de computação sem necessidade.
Moduladores de Largura de
Pulso (PWMs) Um modulador de largura de pulso
(PWM) é um dispositivo que gera um sinal que repetidamente chaveia entre níveis baixo e alto.
Controla-se a duração do valor alto e do valor baixo indicando-se o período desejado e o duty cycle, a razão entre o tempo em que o sinal está em nível alto e seu período. Uma onda quadrada clássica tem duty cycle de 50%. A largura de pulso corresponde ao tempo em que este permanece em nível alto.
PWMs
clk
pwm_o
25% duty cycle – average pwm_o is 1.25V
clk
pwm_o
50% duty cycle – average pwm_o is 2.5V.
clk
pwm_o
75% duty cycle – average pwm_o is 3.75V.
PWMs - Aplicação
Um uso comum de PWMs é no controle da tensão média passada a dispositivos. Isso é feito por meio do controle do período e do duty cycle.
Suponhamos, por exemplo, que um motor DC tenha um número de rotações por minuto igual a 10 vezes o valor da tensão colocada em sua entrada. Para conseguir 125 rpm, precisaríamos de 1,25V, enquanto, para conseguir 250 rpm, precisaríamos de 2,5V.
PWMs - Aplicação
Para realizar o controle via PWM, utiliza-se o duty cycle para conseguir a tensão média desejada e adota-se um período pequeno o suficiente para não impactar no desempenho do motor.
Por exemplo, com um duty cycle de 25%, ter-se-ia uma tensão média de 1,25V e 125 rpm.
Também pode-se usar esse princípio em dimmers usados para iluminação.
PWMs - Aplicação
Outro uso clássico de PWM é na codificação de comandos para carros de controle remoto.
Nesse caso, diferentes duty cycles podem representar diferentes comandos (direita, esquerda etc.), e o receptor usa um timer para definir o comando recebido.
Controles de LCDs
LCDs (Liquid Crystal Displays) são dispositivos de baixos custo e consumo que são capazes de exibir textos e imagens. São amplamente usados em sistemas embarcados, uma vez que estes não possuem monitores como ocorre com os desktops.
LCDs – Princípios Básicos
LCDs de reflexão: a luz passa por uma placa polarizadora. Em seguida, a luz polarizada encontra o cristal líquido. Se uma região desse material é excitada, há um alinhamento de moléculas que permite à luz passar; caso contrário, a luz não passa. A luz que passa é refletida por um espelho e torna a região excitada iluminada.
LCDs de absorção: a operação é similar, mas, em vez de um espelho, usa-se uma película preta, o que faz com que a região excitada fique mais escura que o resto.
Exemplos - LCDs
Um dos LCDs mais simples é o display de sete segmentos. Cada um dos segmentos pode ser ligado ou desligado, permitindo a exibição de letras ou números.
Caso se deseje representar apenas os dígitos de 0 a 9, o papel do driver será apenas o de converter 4 bits em BCD numa série de sinais para ativar/desativar os segmentos.
Exemplos - LCDs
Um LCD de matriz de pontos (dot matrix) pode exibir caracteres
alfanuméricos ou outros símbolos.
Cada caractere emprega tipicamente uma matriz 8 x 5, e o LCD
driver converte os dados de entradas nos sinais para excitar os
pontos específicos.
Cada tipo de LCD pode exibir múltiplos caracteres; além disso, cada
caractere pode ser exibido de maneira direta ou inversa. O LCD
pode permitir que o caractere pisque ou pode exibir um cursor.
Funcionalidades desse tipo fazem com que seja interessante dispor
de um controlador de LCD, por exemplo, com oito entradas e um
enable.
Controlador
Para mandar um byte, são colocados os valores adequados nas oito entradas e aciona-se o enable.
O byte pode ser uma palavra de controle ou um dado (e.g. em ASCII) a ser exibido.
Exemplo – Inicialização de um
LCD Consideremos um microcontrolador
ligado a um controlador LCD, como mostrado na figura a seguir. O controlador recebe informações do microcontrolador, as decodifica e realiza as ações necessárias no LCD.
Exemplo – Inicialização de um
LCD Feita a sequência de inicialização, é possível mandar
palavras de controle ou dados a serem exibidos.
RS é colocado em nível baixo, quando se trata de uma
operação de controle. RS é colocada em nível alto para
indicar que os dados enviados devem ser exibidos. Toda
informação enviada deve ocorrer com o enable ativado. A
tabela exposta mostra as palavras de controle possíveis.
Feita a inicialização por meio dos códigos mostrados, opta-
se por uma interface de 8 bits, limpa-se o display, coloca-se o
cursor na posição inicial, e o cursor se move para a direita
enquanto os dados são exibidos.
Exemplo – Inicialização de um
LCD Agora, pode-se escrever no LCD.
Coloca-se RS = 1, e colocam-se os dados nas linhas DB7 – DB0. A função WriteChar aceita um caractere para escrita no LCD. A função EnableLCD(45) ativa o enable e age como um delay, de modo que o comando possa ser processado e executado.
Controladores de Keypad
Um keypad é um conjunto de botões que fornecem entradas para um sistema embarcado. São muito comuns em sistemas embarcados, que não costumam dispor de teclados à maneira de desktops.
Um keypad simples tem botões dispostos num arranjo M x N, como ilustrado a seguir.
Controladores de Keypad
O dispositivo tem N saídas, cada uma correspondente a uma
coluna e M saídas, cada uma correspondente a uma linha.
Quando um botão é apertado, uma coluna e uma linha
assumem nível alto, e o comando é identificado.
Pode-se usar um controlador para fazer uma varredura das
linhas e colunas, como mostrado na figura anterior. Quando o
botão é apertado, o controlador retorna o código
correspondente ao botão (‘key_code’), e coloca o bit
k_pressed em nível alto. Esse bit pode ser lido em software
de tempos em tempos (polling) ou gerar uma interrupção.
Conversores Analógico-Digital
Um conversor analógico-digital (ADC, A/D, A2D) é um dispositivo que converte um sinal analógico num sinal digital. Um conversor digital analógico (DAC, D/A, D2A) faz o oposto.
Essas conversões são muito importantes, pois os sistemas embarcados interagem com um ambiente que gera diversos sinais analógicos, embora só consigam lidar com dados digitais.
Conversores A/D
Um sinal analógico é considerado contínuo em seus valores (temperatura, velocidade etc.), enquanto um sinal digital assume apenas valores pertencentes a um conjunto finito (codificado em bits).
Consideremos, por exemplo, um sinal analógico que vai de 0 a 7,5V. Desejamos representar qualquer valor nessa faixa usando 4 bits (0000 a 1111, com distribuição uniforme). A figura a seguir ilustra isso.
Conversão A/D
Apresentamos a seguir o processo de amostragem e conversão de um sinal analógico entre 1V e 4V, a título de exemplo.
Conversão D/A
Apresentamos agora o processo inverso, de conversão D/A, ou seja, de reconstrução de uma estimativa do sinal analógico a partir dos bits correspondentes.
Conversão A/D
De maneira mais geral (supondo tensão mínima
nula), podemos computar os valores digitais a
partir dos analógicos (e vice-versa) usando a
relação:
e / Vmax = d / (2n – 1)
No nosso exemplo, se tomássemos e = 3V,
n = 4 e Vmax = 7,5, teríamos d = 6, ou 0110.
A resolução do conversor é dada por
Vmax / 2n – 1, que, em nosso exemplo, vale 0,5 V.
Conversores D/A
A estrutura interna de conversores D/A é mais simples que a de conversores A/D. Um conversor D/A basicamente tem ‘n’ entradas binárias, uma entrada para ‘Vmax’ e uma saída analógica ‘e’.
Um circuito com resistores e um amplificador operacional pode realizar essa conversão sem maiores dificuldades teóricas.
Conversores A/D
Conversores A/D são criaturas mais complexas. Dada uma entrada ‘Vmax’ e uma entrada analógica ‘e’, como encontrar a palavra binária correta?
Não há, como no caso de um D/A, um circuito analógico simples para isso.
Uma idéia seria usar um D/A conectado a Vmax e fazer uma busca pela palavra que aproxima a tensão de entrada com precisão suficiente. Mas como fazer essa busca?
Conversores A/D
Uma possibilidade seria usar uma busca exaustiva sequencial, que requer, no pior caso, um número exponencial de comparações.
Outra possibilidade é fazer uma busca binária, ou busca por aproximações sucessivas. Nesse caso, divide-se o range de valores de tensão possíveis em dois e verifica-se em que metade a tensão de entrada se encontra. Repete-se o processo então para o intervalo reduzido e assim por diante, exigindo no máximo ‘n’ comparações.
Aproximações Sucessivas
Suponhamos um conversor com 8 bits e range de 0 a 15V. Qual será a palavra
código para 5V?
Primeiramente, vemos que a metade do intervalo é 7,5V. 5V está abaixo, o que
significa que seu primeiro bit (o mais significativo) será zero.
Em seguida, achamos o ponto médio entre 0 e 7,5V, que é 3,75V. 5V está acima,
e, portanto, seu segundo bit mais significativo será “1”.
O ponto médio agora é 5,625V, e 5V está abaixo, o que gera um bit “0”.
Agora precisamos achar o ponto médio entre 3,75V e 5,625V, que é 4,6875V.
Temos que 5V está acima do intervalo, o que gera um bit “1”.
Aproximações Sucessivas
Agora precisamos achar o ponto médio entre 4,6875V e 5,625V,
que é 5,15625V. 5V está abaixo, o que gera um bit “0”.
O próximo ponto médio é 4,921875V, que leva a um bit “1”.
A seguir, tem-se 5,0390625V, que gera um bit “0”.
Por fim, tem-se 4,98046875V, que gera o oitavo bit, “1”.
Tem-se então 01010101 = 85.
Pela fórmula dada antes, teríamos 5/15 = d/28 – 1, ou seja, 85.
Note que a divisão por dois é feita de maneira eficiente em binário
por meio de deslocamentos, o que é sugerido pela figura a seguir.
Clocks de Tempo Real
Um real-time clock (RTC) é responsável por guardar data e hora num sistema
embarcado.
RTCs contém, tipicamente, um oscilador controlado por um cristal, que gera um
sinal de clock estável para uma cascata de contadores.
O primeiro desses contadores, tipicamente, conta até a frequência do oscilador, o
que indica 1 segundo. Nesse ponto, ele gera um sinal que move um segundo
contador, que vai até 59. Este gera um pulso para o contador de minutos. A
contagem de horas, dias, meses e anos segue de maneira similar.
Uma bateria de backup garante o funcionamento do sistema mesmo quando o
sistema embarcado é desligado.